]> git.ipfire.org Git - thirdparty/json-c.git/commitdiff
Set error codes for truncating int conversions 882/head
authorSimon Resch <simon.resch@code-intelligence.de>
Tue, 26 Nov 2024 19:42:29 +0000 (20:42 +0100)
committerSimon Resch <simon.resch@code-intelligence.de>
Wed, 27 Nov 2024 06:17:20 +0000 (07:17 +0100)
json_object_get_int/int64/uint64() now sets errno to ERANGE when the source value
can't be represented in the target type.

json_object.c
json_object.h
tests/test_int_get.c

index 995b0eda9bb86bf5b32bc36d1e2a7e9b3f65bbdf..d67a61a4b15820797e902b367a4c73c668c87feb 100644 (file)
@@ -757,17 +757,29 @@ int32_t json_object_get_int(const struct json_object *jso)
        {
        case json_type_int:
                /* Make sure we return the correct values for out of range numbers. */
-               if (cint64 <= INT32_MIN)
+               if (cint64 < INT32_MIN)
+               {
+                       errno = ERANGE;
                        return INT32_MIN;
-               if (cint64 >= INT32_MAX)
+               }
+               if (cint64 > INT32_MAX)
+               {
+                       errno = ERANGE;
                        return INT32_MAX;
+               }
                return (int32_t)cint64;
        case json_type_double:
                cdouble = JC_DOUBLE_C(jso)->c_double;
-               if (cdouble <= INT32_MIN)
+               if (cdouble < INT32_MIN)
+               {
+                       errno = ERANGE;
                        return INT32_MIN;
-               if (cdouble >= INT32_MAX)
+               }
+               if (cdouble > INT32_MAX)
+               {
+                       errno = ERANGE;
                        return INT32_MAX;
+               }
                if (isnan(cdouble))
                {
                        errno = EINVAL;
@@ -820,8 +832,11 @@ int64_t json_object_get_int64(const struct json_object *jso)
                {
                case json_object_int_type_int64: return jsoint->cint.c_int64;
                case json_object_int_type_uint64:
-                       if (jsoint->cint.c_uint64 >= INT64_MAX)
+                       if (jsoint->cint.c_uint64 > INT64_MAX)
+                       {
+                               errno = ERANGE;
                                return INT64_MAX;
+                       }
                        return (int64_t)jsoint->cint.c_uint64;
                default: json_abort("invalid cint_type");
                }
@@ -829,10 +844,16 @@ int64_t json_object_get_int64(const struct json_object *jso)
        case json_type_double:
                // INT64_MAX can't be exactly represented as a double
                // so cast to tell the compiler it's ok to round up.
-               if (JC_DOUBLE_C(jso)->c_double >= (double)INT64_MAX)
+               if (JC_DOUBLE_C(jso)->c_double > (double)INT64_MAX)
+               {
+                       errno = ERANGE;
                        return INT64_MAX;
-               if (JC_DOUBLE_C(jso)->c_double <= INT64_MIN)
+               }
+               if (JC_DOUBLE_C(jso)->c_double < (double)INT64_MIN)
+               {
+                       errno = ERANGE;
                        return INT64_MIN;
+               }
                if (isnan(JC_DOUBLE_C(jso)->c_double))
                {
                        errno = EINVAL;
@@ -864,7 +885,10 @@ uint64_t json_object_get_uint64(const struct json_object *jso)
                {
                case json_object_int_type_int64:
                        if (jsoint->cint.c_int64 < 0)
+                       {
+                               errno = ERANGE;
                                return 0;
+                       }
                        return (uint64_t)jsoint->cint.c_int64;
                case json_object_int_type_uint64: return jsoint->cint.c_uint64;
                default: json_abort("invalid cint_type");
@@ -873,10 +897,16 @@ uint64_t json_object_get_uint64(const struct json_object *jso)
        case json_type_double:
                // UINT64_MAX can't be exactly represented as a double
                // so cast to tell the compiler it's ok to round up.
-               if (JC_DOUBLE_C(jso)->c_double >= (double)UINT64_MAX)
+               if (JC_DOUBLE_C(jso)->c_double > (double)UINT64_MAX)
+               {
+                       errno = ERANGE;
                        return UINT64_MAX;
+               }
                if (JC_DOUBLE_C(jso)->c_double < 0)
+               {
+                       errno = ERANGE;
                        return 0;
+               }
                if (isnan(JC_DOUBLE_C(jso)->c_double))
                {
                        errno = EINVAL;
index b6f3dc70cf59bd6077483075c58c734c52ea94aa..e21138ecf1db7fc5eb0d5befca97aa3217b06d71 100644 (file)
@@ -743,7 +743,8 @@ JSON_EXPORT struct json_object *json_object_new_uint64(uint64_t i);
  * which return INT32_MIN and the errno is set to EINVAL.
  * Strings will be parsed as an integer. If no conversion exists then 0 is
  * returned and errno is set to EINVAL. null is equivalent to 0 (no error values
- * set)
+ * set).
+ * Sets errno to ERANGE if the value exceeds the range of int.
  *
  * Note that integers are stored internally as 64-bit values.
  * If the value of too big or too small to fit into 32-bit, INT32_MAX or
@@ -789,7 +790,8 @@ JSON_EXPORT int json_object_int_inc(struct json_object *obj, int64_t val);
  * which return INT64_MIN and the errno is set to EINVAL.
  * Strings will be parsed as an int64. If no conversion exists then 0 is
  * returned and errno is set to EINVAL. null is equivalent to 0 (no error values
- * set)
+ * set).
+ * Sets errno to ERANGE if the value exceeds the range of int64.
  *
  * NOTE: Set errno to 0 directly before a call to this function to determine
  * whether or not conversion was successful (it does not clear the value for
@@ -807,7 +809,8 @@ JSON_EXPORT int64_t json_object_get_int64(const struct json_object *obj);
  * which return 0 and the errno is set to EINVAL.
  * Strings will be parsed as an uint64. If no conversion exists then 0 is
  * returned and errno is set to EINVAL. null is equivalent to 0 (no error values
- * set)
+ * set).
+ * Sets errno to ERANGE if the value exceeds the range of uint64.
  *
  * NOTE: Set errno to 0 directly before a call to this function to determine
  * whether or not conversion was successful (it does not clear the value for
index 2da08c6306cb6697b0c861aacf944295be594e62..e694fb36a43f5d496b85c96820b193842af37312 100644 (file)
@@ -8,6 +8,8 @@
 
 #include "json.h"
 
+#define I32_MAX_S "2147483647"
+#define I32_MIN_S "-2147483648"
 #define I64_MAX_S "9223372036854775807"
 #define I64_OVER  "9223372036854775808"
 #define I64_MIN_S "-9223372036854775808"
@@ -43,12 +45,15 @@ int main(int argc, char **argv)
 
        CHECK_GET_INT(N_I64(INT32_MAX), INT32_MAX && errno == 0);
        CHECK_GET_INT(N_I64(INT32_MIN), INT32_MIN && errno == 0);
-       CHECK_GET_INT(N_I64(INT64_MAX), INT32_MAX && errno == 0);
-       CHECK_GET_INT(N_I64(INT64_MIN), INT32_MIN && errno == 0);
-       CHECK_GET_INT(N_STR(I64_MAX_S), INT32_MAX && errno == 0);
-       CHECK_GET_INT(N_STR(I64_MIN_S), INT32_MIN && errno == 0);
+       CHECK_GET_INT(N_I64(INT64_MAX), INT32_MAX && errno == ERANGE);
+       CHECK_GET_INT(N_I64(INT64_MIN), INT32_MIN && errno == ERANGE);
+       CHECK_GET_INT(N_STR(I32_MAX_S), INT32_MAX && errno == 0);
+       CHECK_GET_INT(N_STR(I32_MIN_S), INT32_MIN && errno == 0);
+       CHECK_GET_INT(N_STR(I64_MAX_S), INT32_MAX && errno == ERANGE);
+       CHECK_GET_INT(N_STR(I64_MIN_S), INT32_MIN && errno == ERANGE);
+       CHECK_GET_INT(N_DBL(INFINITY),  INT32_MAX && errno == ERANGE);
+       CHECK_GET_INT(N_DBL(-INFINITY), INT32_MIN && errno == ERANGE);
        CHECK_GET_INT(N_DBL(NAN),       INT32_MIN && errno == EINVAL);
-
        printf("INT GET PASSED\n");
 
        CHECK_GET_INT64(N_I64(INT64_MAX), INT64_MAX && errno == 0);
@@ -57,12 +62,16 @@ int main(int argc, char **argv)
        CHECK_GET_INT64(N_STR(I64_MIN_S), INT64_MIN && errno == 0);
        CHECK_GET_INT64(N_STR(I64_OVER),  INT64_MAX && errno == ERANGE);
        CHECK_GET_INT64(N_STR(I64_UNDER), INT64_MIN && errno == ERANGE);
+       CHECK_GET_INT64(N_DBL(INFINITY),  INT64_MAX && errno == ERANGE);
+       CHECK_GET_INT64(N_DBL(-INFINITY), INT64_MIN && errno == ERANGE);
        CHECK_GET_INT64(N_DBL(NAN),       INT64_MIN && errno == EINVAL);
        printf("INT64 GET PASSED\n");
 
        CHECK_GET_UINT64(N_U64(UINT64_MAX), UINT64_MAX && errno == 0);
        CHECK_GET_UINT64(N_U64(-1),         UINT64_MAX && errno == 0);
        CHECK_GET_UINT64(N_STR(U64_OUT_S),  UINT64_MAX && errno == ERANGE);
+       CHECK_GET_UINT64(N_DBL(INFINITY),   UINT64_MAX && errno == ERANGE);
+       CHECK_GET_UINT64(N_DBL(-INFINITY),  0          && errno == ERANGE);
        CHECK_GET_UINT64(N_DBL(NAN),        0          && errno == EINVAL);
        printf("UINT64 GET PASSED\n");