Open raphael-bmec-co opened 7 months ago
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)
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)
valuedouble
valueint
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; }
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
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_json->valuedouble: 0; }
JSONVar::operator unsigned long () const { return cJSON_IsNumber (_json) ? static_cast_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<unsigned long>((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 setsvaluedouble
correctly but truncatesvalueint
for values outside the bounds ofINT_MIN
-INT_MAX
.The corresponding getters all access the
valueint
.Steps to reproduce
Sample code:
Output:
Potential fixes
valuedouble
and static_cast to the correct type.JSONVar::operator long () const { return cJSON_IsNumber (_json) ? static_cast_json->valuedouble: 0;
}
JSONVar::operator unsigned long () const { return cJSON_IsNumber (_json) ? static_cast_json->valuedouble: 0;
}