Issue
Calls to the following may result in truncated values:
void JSONVar::operator=(unsigned int i)
void JSONVar::operator=(long l)
void JSONVar::operator=(unsigned long ul)
All these methods wrap a call to CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num) shown below which sets valuedouble correctly but truncates valueint for values outside the bounds of INT_MIN - INT_MAX.
CJSON_PUBLIC (cJSON *) cJSON_CreateNumber(double num)
{
cJSON *item = cJSON_New_Item (&global_hooks);
if (item)
{
item->type = cJSON_Number;
item->valuedouble = num;
/* use saturation in case of overflow */
if (num >= INT_MAX)
{
item->valueint = INT_MAX;
}
else if (num <= (double )INT_MIN)
{
item->valueint = INT_MIN;
}
else
{
item->valueint = (int )num;
}
}
return item;
}
The corresponding getters all access the valueint.
JSONVar::operator unsigned int () const
{
return cJSON_IsNumber (_json) ? _json->valueint : 0 ;
}
JSONVar::operator long () const
{
return cJSON_IsNumber (_json) ? _json->valueint : 0 ;
}
JSONVar::operator unsigned long () const
{
return cJSON_IsNumber (_json) ? _json->valueint : 0 ;
}
Steps to reproduce
Sample code:
#include < Arduino_JSON.h>
void setup () {
Serial.begin (115200 );
JSONVar jsonVar;
jsonVar[" unsignedInt" ] = UINT_MAX;
jsonVar[" longMax" ] = LONG_MAX;
jsonVar[" longMin" ] = LONG_MIN;
jsonVar[" unsignedLong" ] = ULONG_MAX;
Serial.println (" Expected: " + String ((double ) jsonVar[" unsignedInt" ]) + " got: " + String ((unsigned int ) jsonVar[" unsignedInt" ]));
Serial.println (" Expected: " + String ((double ) jsonVar[" longMax" ]) + " got: " + String ((long ) jsonVar[" longMax" ]));
Serial.println (" Expected: " + String ((double ) jsonVar[" longMin" ]) + " got: " + String ((long ) jsonVar[" longMin" ]));
Serial.println (" Expected: " + String ((double ) jsonVar[" unsignedLong" ]) + " got: " + String ((unsigned long ) jsonVar[" unsignedLong" ]));
}
void loop () {
}
Output:
Expected: 4294967295.00 got: 2147483647
Expected: 2147483647.00 got: 2147483647
Expected: -2147483648.00 got: -k
Expected: 4294967295.00 got: 2147483647
Potential fixes
Fix the implementation of cJSON_CreateNumber (unlikely see Clean up the cJSON struct DaveGamble/cJSON#63 ) OR
Use valuedouble and static_cast to the correct type.
JSONVar::operator unsigned int () const
{
return cJSON_IsNumber (_json) ? static_cast <unsigned int >_json->valuedouble : 0 ;
}
JSONVar::operator long () const
{
return cJSON_IsNumber (_json) ? static_cast <long >_json->valuedouble : 0 ;
}
JSONVar::operator unsigned long () const
{
return cJSON_IsNumber (_json) ? static_cast <unsigned long >_json->valuedouble : 0 ;
}
Workaround:
When reading values of the types listed above use cast to double to get the valuedouble and then cast to the desired type.
e.g. static_cast((double) jsonVar["unsignedLong"])
Issue
Calls to the following may result in truncated values:
void JSONVar::operator=(unsigned int i)void JSONVar::operator=(long l)void JSONVar::operator=(unsigned long ul)All these methods wrap a call to
CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num)shown below which setsvaluedoublecorrectly but truncatesvalueintfor values outside the bounds ofINT_MIN-INT_MAX.The corresponding getters all access the
valueint.Steps to reproduce
Sample code:
Output:
Potential fixes
valuedoubleand static_cast to the correct type.Workaround:
When reading values of the types listed above use cast to
doubleto get thevaluedoubleand then cast to the desired type.e.g. static_cast((double) jsonVar["unsignedLong"])