MIRROR: javascript for ๐Ÿœ's, a tiny runtime with big ambitions
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

make Object and Array constructor prototypes read-only

+31 -19
+14 -4
src/ant.c
··· 3475 3475 return result; 3476 3476 } 3477 3477 3478 + static ant_value_t js_setprop_readonly_nonconfigurable(ant_t *js, ant_value_t obj, const char *key, size_t keylen, ant_value_t v) { 3479 + ant_value_t k = js_mkstr(js, key, keylen); 3480 + if (is_err(k)) return k; 3481 + ant_value_t result = js_setprop(js, obj, k, v); 3482 + if (is_err(result)) return result; 3483 + 3484 + js_set_descriptor(js, js_as_obj(obj), key, keylen, 0); 3485 + return result; 3486 + } 3487 + 3478 3488 #define SYM_FLAG_GLOBAL 1u 3479 3489 #define SYM_FLAG_WELL_KNOWN 2u 3480 3490 ··· 5942 5952 if (enumerable) attrs |= ANT_PROP_ATTR_ENUMERABLE; 5943 5953 if (configurable) attrs |= ANT_PROP_ATTR_CONFIGURABLE; 5944 5954 5945 - if (!sym_key) js_set_descriptor(js, as_obj, prop_str, prop_len, desc_flags); 5946 - 5947 5955 if (existing_off > 0) { 5948 5956 bool is_frozen = obj_ptr ? obj_ptr->frozen : false; 5949 5957 bool is_nonconfig = is_nonconfig_prop(js, existing_off) || is_frozen; ··· 5964 5972 if (is_nonconfig && is_readonly && has_value) 5965 5973 return js_mkerr(js, "Cannot assign to read-only property '%.*s'", (int)prop_len, prop_str); 5966 5974 if (has_value) js_saveval(js, existing_off, value); 5975 + if (!sym_key) js_set_descriptor(js, as_obj, prop_str, prop_len, desc_flags); 5967 5976 5968 5977 ant_prop_ref_t *ref = propref_get(js, existing_off); 5969 5978 if (ref && ref->obj) { ··· 5979 5988 | (writable ? ANT_PROP_ATTR_WRITABLE : 0) 5980 5989 | (configurable ? ANT_PROP_ATTR_CONFIGURABLE : 0); 5981 5990 mkprop(js, as_obj, prop_key, value, prop_attrs); 5991 + if (!sym_key) js_set_descriptor(js, as_obj, prop_str, prop_len, desc_flags); 5982 5992 5983 5993 if (obj_ptr && obj_ptr->shape) { 5984 5994 if (!js_obj_ensure_unique_shape(obj_ptr)) return js_mkerr(js, "oom"); ··· 12662 12672 defmethod(js, obj_func_obj, "preventExtensions", 17, js_mkfun(builtin_object_preventExtensions)); 12663 12673 12664 12674 js_setprop(js, obj_func_obj, ANT_STRING("name"), ANT_STRING("Object")); 12665 - js_setprop_nonconfigurable(js, obj_func_obj, "prototype", 9, object_proto); 12675 + js_setprop_readonly_nonconfigurable(js, obj_func_obj, "prototype", 9, object_proto); 12666 12676 ant_value_t obj_func = js_obj_to_func(obj_func_obj); 12667 12677 js_setprop(js, glob, js_mkstr(js, "Object", 6), obj_func); 12668 12678 ··· 12741 12751 ant_value_t arr_ctor_obj = mkobj(js, 0); 12742 12752 set_proto(js, arr_ctor_obj, function_proto); 12743 12753 set_slot(arr_ctor_obj, SLOT_CFUNC, js_mkfun(builtin_Array)); 12744 - js_setprop_nonconfigurable(js, arr_ctor_obj, "prototype", 9, array_proto); 12754 + js_setprop_readonly_nonconfigurable(js, arr_ctor_obj, "prototype", 9, array_proto); 12745 12755 defmethod(js, arr_ctor_obj, "isArray", 7, js_mkfun(builtin_Array_isArray)); 12746 12756 defmethod(js, arr_ctor_obj, "from", 4, js_mkfun(builtin_Array_from)); 12747 12757 defmethod(js, arr_ctor_obj, "of", 2, js_mkfun(builtin_Array_of));
+17 -15
tests/test_literal_primordials.cjs
··· 41 41 { 42 42 const altProto = { mark: 'object-assign' }; 43 43 BuiltinObject.prototype = altProto; 44 + assert( 45 + BuiltinObject.prototype === originalObjectCtorProto, 46 + 'Object.prototype assignment should not replace the built-in constructor prototype property' 47 + ); 44 48 const obj = {}; 45 49 assert(BuiltinObject.getPrototypeOf(obj) === primordialObjectProto, 'object literal should keep primordial Object prototype'); 46 50 assertEq(obj.mark, undefined, 'object literal should ignore assigned ctor prototype'); ··· 67 71 console.log('\nTest 3: object literal ignores Object.defineProperty on ctor prototype'); 68 72 { 69 73 const altProto = { mark: 'object-define' }; 70 - if (!tryRedefineCtorPrototype(BuiltinObject, altProto)) { 71 - console.log('SKIP'); 72 - } else { 73 - assertEq(BuiltinObject.prototype.mark, 'object-define', 'defineProperty should update Object.prototype property'); 74 + assertEq(tryRedefineCtorPrototype(BuiltinObject, altProto), false, 'defineProperty should reject redefining Object.prototype'); 75 + assert(BuiltinObject.prototype === originalObjectCtorProto, 'Object.prototype should stay unchanged after rejected defineProperty'); 74 76 const obj = {}; 75 77 assert( 76 78 BuiltinObject.getPrototypeOf(obj) === primordialObjectProto, 77 - 'object literal should keep primordial Object prototype after defineProperty' 79 + 'object literal should keep primordial Object prototype after rejected defineProperty' 78 80 ); 79 - assertEq(obj.mark, undefined, 'object literal should ignore defineProperty-updated ctor prototype'); 80 - } 81 + assertEq(obj.mark, undefined, 'object literal should ignore rejected defineProperty-updated ctor prototype'); 81 82 } 82 83 restore(); 83 84 console.log('PASS'); ··· 87 88 const altProto = []; 88 89 altProto.mark = 'array-assign'; 89 90 BuiltinArray.prototype = altProto; 91 + assert( 92 + BuiltinArray.prototype === originalArrayCtorProto, 93 + 'Array.prototype assignment should not replace the built-in constructor prototype property' 94 + ); 90 95 const arr = []; 91 96 assert(BuiltinObject.getPrototypeOf(arr) === primordialArrayProto, 'array literal should keep primordial Array prototype'); 92 97 assertEq(arr.mark, undefined, 'array literal should ignore assigned ctor prototype'); ··· 111 116 { 112 117 const altProto = []; 113 118 altProto.mark = 'array-define'; 114 - if (!tryRedefineCtorPrototype(BuiltinArray, altProto)) { 115 - console.log('SKIP'); 116 - } else { 117 - assertEq(BuiltinArray.prototype.mark, 'array-define', 'defineProperty should update Array.prototype property'); 118 - const arr = []; 119 - assert(BuiltinObject.getPrototypeOf(arr) === primordialArrayProto, 'array literal should keep primordial Array prototype after defineProperty'); 120 - assertEq(arr.mark, undefined, 'array literal should ignore defineProperty-updated ctor prototype'); 121 - } 119 + assertEq(tryRedefineCtorPrototype(BuiltinArray, altProto), false, 'defineProperty should reject redefining Array.prototype'); 120 + assert(BuiltinArray.prototype === originalArrayCtorProto, 'Array.prototype should stay unchanged after rejected defineProperty'); 121 + const arr = []; 122 + assert(BuiltinObject.getPrototypeOf(arr) === primordialArrayProto, 'array literal should keep primordial Array prototype after rejected defineProperty'); 123 + assertEq(arr.mark, undefined, 'array literal should ignore rejected defineProperty-updated ctor prototype'); 122 124 } 123 125 restore(); 124 126 console.log('PASS');