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:
1 parent
dbbae0dee3
commit
a8e6d5f871
2 files changed
+40
-4
No files matched your search
+8
-4
@@ -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);
|
||||
|
||||
@@ -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]
|
||||
|
||||
Reference in new issue
Block a user