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.
This commit is contained in:
omkar bhor authored and GitHub committed 2026-10-09 09:22:59 +09:00
1 parent dbbae0dee3
commit a8e6d5f871
2 files changed
+40 -4

No files matched your search

+8 -4
View File
@@ -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);
+32
View File
@@ -1752,6 +1752,38 @@ has(nan)
[0,1,2]
false
has(infinite)
[0,1,2]
false
has(-infinite)
[0,1,2]
false
del(.[infinite])
[1,2,3]
[1,2,3]
del(.[-infinite])
[1,2,3]
[1,2,3]
has(1e10)
[0,1,2]
false
has(-1e10)
[0,1,2]
false
del(.[1e10])
[1,2,3]
[1,2,3]
del(.[-1e10])
[1,2,3]
[1,2,3]
keys
[42,3,35]
[0,1,2]