@ 261102.1

261009.1 · a8e6d5f8714ad470ae1dbbf6198dec03092d954c

Fix undefined behavior on out-of-range array index in has() and del() (#3560)

Converting a double outside the int range to int is undefined behavior, and has() and del() did it on array indices like infinite or 1e10, which UBSan reports as "inf is outside the range of representable values of type 'int'". Only NaN was guarded against.

Clamp the index to the int range in has(), as getting and setting array elements already do, and drop out-of-range indices in del() before they are converted. Such indices can never refer to an element, so has() returns false and del() leaves the array unchanged, the same as for indices past the end of the array. Valid indices deleted together with out-of-range ones, as in del(.[0, 1e10]), are still deleted.

reading declarations

Changes to src/jv_aux.c. All files

src/jv_aux.c

@@ -260,11 +260,14 @@ jv jv_has(jv t, jv k) {     jv_free(elem);   } else if (jv_get_kind(t) == JV_KIND_ARRAY &&              jv_get_kind(k) == JV_KIND_NUMBER) {-    if (jvp_number_is_nan(k)) {+    double nv = jv_number_value(k);+    if (isnan(nv)) {       jv_free(t);       ret = jv_false();     } else {-      jv elem = jv_array_get(t, (int)jv_number_value(k));+      if (nv < INT_MIN) nv = INT_MIN;+      if (nv > INT_MAX) nv = INT_MAX;+      jv elem = jv_array_get(t, (int)nv);       ret = jv_bool(jv_is_valid(elem));       jv_free(elem);     }@@ -294,9 +297,10 @@ static jv jv_dels(jv t, jv keys) {     jv starts = jv_array(), ends = jv_array();     jv_array_foreach(keys, i, key) {       if (jv_get_kind(key) == JV_KIND_NUMBER) {-        if (jvp_number_is_nan(key)) {+        double nv = jv_number_value(key);+        if (isnan(nv) || nv < INT_MIN || nv > INT_MAX) {           jv_free(key);-        } else if (jv_number_value(key) < 0) {+        } else if (nv < 0) {           neg_keys = jv_array_append(neg_keys, key);         } else {           nonneg_keys = jv_array_append(nonneg_keys, key);