return null in bad retrieval, throw on bad insert
This commit is contained in:
@@ -7572,10 +7572,10 @@ static JSValue JS_GetPropertyValue(JSContext *ctx, JSValueConst this_obj,
|
||||
signed_idx = JS_VALUE_GET_INT(prop);
|
||||
switch(p->class_id) {
|
||||
case JS_CLASS_ARRAY:
|
||||
/* arrays require non-negative numeric index */
|
||||
/* arrays require non-negative numeric index - return null for invalid */
|
||||
if (signed_idx < 0) {
|
||||
JS_FreeValue(ctx, prop);
|
||||
return JS_ThrowTypeError(ctx, "array index must be non-negative");
|
||||
return JS_NULL;
|
||||
}
|
||||
idx = (uint32_t)signed_idx;
|
||||
if (unlikely(idx >= p->u.array.count)) goto slow_path;
|
||||
@@ -7585,34 +7585,41 @@ static JSValue JS_GetPropertyValue(JSContext *ctx, JSValueConst this_obj,
|
||||
}
|
||||
} else {
|
||||
slow_path:
|
||||
/* Type checking for array vs object indexing */
|
||||
/* Type checking for array vs object indexing - return null for invalid retrieval */
|
||||
if (JS_VALUE_GET_TAG(this_obj) == JS_TAG_OBJECT) {
|
||||
JSObject *p = JS_VALUE_GET_OBJ(this_obj);
|
||||
if (p->class_id == JS_CLASS_ARRAY) {
|
||||
/* Arrays require numeric index */
|
||||
/* Arrays require numeric index - return null for non-numeric */
|
||||
if (prop_tag != JS_TAG_INT && !JS_TAG_IS_FLOAT64(prop_tag)) {
|
||||
JS_FreeValue(ctx, prop);
|
||||
return JS_ThrowTypeError(ctx, "array index must be a number");
|
||||
return JS_NULL;
|
||||
}
|
||||
/* Check for negative index */
|
||||
/* Return null for negative index */
|
||||
if (prop_tag == JS_TAG_INT) {
|
||||
if (JS_VALUE_GET_INT(prop) < 0) {
|
||||
JS_FreeValue(ctx, prop);
|
||||
return JS_ThrowTypeError(ctx, "array index must be non-negative");
|
||||
return JS_NULL;
|
||||
}
|
||||
} else {
|
||||
double d = JS_VALUE_GET_FLOAT64(prop);
|
||||
if (d < 0) {
|
||||
JS_FreeValue(ctx, prop);
|
||||
return JS_ThrowTypeError(ctx, "array index must be non-negative");
|
||||
return JS_NULL;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* Objects require text or object (symbol) key - NOT numbers */
|
||||
if (prop_tag != JS_TAG_STRING && prop_tag != JS_TAG_STRING_ROPE &&
|
||||
prop_tag != JS_TAG_SYMBOL && prop_tag != JS_TAG_OBJECT) {
|
||||
/* Objects require text or non-array object (symbol) key - return null for invalid */
|
||||
if (prop_tag == JS_TAG_OBJECT) {
|
||||
/* Check if it's an array - arrays not allowed as object keys */
|
||||
JSObject *key_obj = JS_VALUE_GET_OBJ(prop);
|
||||
if (key_obj->class_id == JS_CLASS_ARRAY) {
|
||||
JS_FreeValue(ctx, prop);
|
||||
return JS_NULL;
|
||||
}
|
||||
} else if (prop_tag != JS_TAG_STRING && prop_tag != JS_TAG_STRING_ROPE &&
|
||||
prop_tag != JS_TAG_SYMBOL) {
|
||||
JS_FreeValue(ctx, prop);
|
||||
return JS_ThrowTypeError(ctx, "object key must be text or object");
|
||||
return JS_NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8388,9 +8395,18 @@ static int JS_SetPropertyValue(JSContext *ctx, JSValueConst this_obj,
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* Objects require text or object (symbol) key - NOT numbers */
|
||||
if (prop_tag != JS_TAG_STRING && prop_tag != JS_TAG_STRING_ROPE &&
|
||||
prop_tag != JS_TAG_SYMBOL && prop_tag != JS_TAG_OBJECT) {
|
||||
/* Objects require text or non-array object (symbol) key - NOT numbers */
|
||||
if (prop_tag == JS_TAG_OBJECT) {
|
||||
/* Check if it's an array - arrays not allowed as object keys */
|
||||
JSObject *key_obj = JS_VALUE_GET_OBJ(prop);
|
||||
if (key_obj->class_id == JS_CLASS_ARRAY) {
|
||||
JS_FreeValue(ctx, prop);
|
||||
JS_FreeValue(ctx, val);
|
||||
JS_ThrowTypeError(ctx, "object key must be text or object, not array");
|
||||
return -1;
|
||||
}
|
||||
} else if (prop_tag != JS_TAG_STRING && prop_tag != JS_TAG_STRING_ROPE &&
|
||||
prop_tag != JS_TAG_SYMBOL) {
|
||||
JS_FreeValue(ctx, prop);
|
||||
JS_FreeValue(ctx, val);
|
||||
JS_ThrowTypeError(ctx, "object key must be text or object");
|
||||
|
||||
@@ -1831,4 +1831,69 @@ return {
|
||||
if (!caught) throw "object should not be able to use null as key"
|
||||
},
|
||||
|
||||
// ============================================================================
|
||||
// RETRIEVAL WITH INVALID KEY RETURNS NULL (not throw)
|
||||
// ============================================================================
|
||||
|
||||
test_array_get_string_key_returns_null: function() {
|
||||
var a = [1, 2, 3]
|
||||
var result = a["x"]
|
||||
if (result != null) throw "array get with string key should return null"
|
||||
},
|
||||
|
||||
test_array_get_negative_index_returns_null: function() {
|
||||
var a = [1, 2, 3]
|
||||
var result = a[-1]
|
||||
if (result != null) throw "array get with negative index should return null"
|
||||
},
|
||||
|
||||
test_array_get_object_key_returns_null: function() {
|
||||
var a = [1, 2, 3]
|
||||
var k = {}
|
||||
var result = a[k]
|
||||
if (result != null) throw "array get with object key should return null"
|
||||
},
|
||||
|
||||
test_array_get_array_key_returns_null: function() {
|
||||
var a = [1, 2, 3]
|
||||
var result = a[[1, 2]]
|
||||
if (result != null) throw "array get with array key should return null"
|
||||
},
|
||||
|
||||
test_array_get_boolean_key_returns_null: function() {
|
||||
var a = [1, 2, 3]
|
||||
var result = a[true]
|
||||
if (result != null) throw "array get with boolean key should return null"
|
||||
},
|
||||
|
||||
test_array_get_null_key_returns_null: function() {
|
||||
var a = [1, 2, 3]
|
||||
var result = a[null]
|
||||
if (result != null) throw "array get with null key should return null"
|
||||
},
|
||||
|
||||
test_obj_get_number_key_returns_null: function() {
|
||||
var o = {a: 1}
|
||||
var result = o[5]
|
||||
if (result != null) throw "object get with number key should return null"
|
||||
},
|
||||
|
||||
test_obj_get_array_key_returns_null: function() {
|
||||
var o = {a: 1}
|
||||
var result = o[[1, 2]]
|
||||
if (result != null) throw "object get with array key should return null"
|
||||
},
|
||||
|
||||
test_obj_get_boolean_key_returns_null: function() {
|
||||
var o = {a: 1}
|
||||
var result = o[true]
|
||||
if (result != null) throw "object get with boolean key should return null"
|
||||
},
|
||||
|
||||
test_obj_get_null_key_returns_null: function() {
|
||||
var o = {a: 1}
|
||||
var result = o[null]
|
||||
if (result != null) throw "object get with null key should return null"
|
||||
},
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user