diff --git a/src-input/duk_api_object.c b/src-input/duk_api_object.c index a97249b3..37de5d61 100644 --- a/src-input/duk_api_object.c +++ b/src-input/duk_api_object.c @@ -27,7 +27,7 @@ DUK_EXTERNAL duk_bool_t duk_get_prop(duk_context *ctx, duk_idx_t obj_idx) { tv_obj = duk_require_tval(ctx, obj_idx); tv_key = duk_require_tval(ctx, -1); - rc = duk_hobject_getprop(thr, tv_obj, tv_key); + rc = duk_hobject_getprop(thr, tv_obj, tv_key, DUK_PROP_FLAG_INTERNAL /*flags*/); DUK_ASSERT(rc == 0 || rc == 1); /* a value is left on stack regardless of rc */ @@ -96,7 +96,7 @@ DUK_LOCAL duk_bool_t duk__put_prop_shared(duk_context *ctx, duk_idx_t obj_idx, d duk_tval *tv_obj; duk_tval *tv_key; duk_tval *tv_val; - duk_small_int_t throw_flag; + duk_small_uint_t flags; duk_bool_t rc; /* Note: copying tv_obj and tv_key to locals to shield against a valstack @@ -112,9 +112,11 @@ DUK_LOCAL duk_bool_t duk__put_prop_shared(duk_context *ctx, duk_idx_t obj_idx, d tv_obj = duk_require_tval(ctx, obj_idx); tv_key = duk_require_tval(ctx, idx_key); tv_val = duk_require_tval(ctx, idx_key ^ 1); - throw_flag = duk_is_strict_call(ctx); + DUK_ASSERT(DUK_PROP_FLAG_THROW == 1); /* duk_is_strict_call() -> throw flag */ + DUK_ASSERT(duk_is_strict_call(ctx) == 0 || duk_is_strict_call(ctx) == 1); + flags = duk_is_strict_call(ctx) | DUK_PROP_FLAG_INTERNAL; - rc = duk_hobject_putprop(thr, tv_obj, tv_key, tv_val, throw_flag); + rc = duk_hobject_putprop(thr, tv_obj, tv_key, tv_val, flags); DUK_ASSERT(rc == 0 || rc == 1); duk_pop_2(ctx); /* remove key and value */ @@ -173,7 +175,7 @@ DUK_EXTERNAL duk_bool_t duk_del_prop(duk_context *ctx, duk_idx_t obj_idx) { duk_hthread *thr = (duk_hthread *) ctx; duk_tval *tv_obj; duk_tval *tv_key; - duk_small_int_t throw_flag; + duk_small_uint_t flags; duk_bool_t rc; DUK_ASSERT_CTX_VALID(ctx); @@ -184,9 +186,11 @@ DUK_EXTERNAL duk_bool_t duk_del_prop(duk_context *ctx, duk_idx_t obj_idx) { tv_obj = duk_require_tval(ctx, obj_idx); tv_key = duk_require_tval(ctx, -1); - throw_flag = duk_is_strict_call(ctx); + DUK_ASSERT(DUK_PROP_FLAG_THROW == 1); /* duk_is_strict_call() -> throw flag */ + DUK_ASSERT(duk_is_strict_call(ctx) == 0 || duk_is_strict_call(ctx) == 1); + flags = duk_is_strict_call(ctx) | DUK_PROP_FLAG_INTERNAL; - rc = duk_hobject_delprop(thr, tv_obj, tv_key, throw_flag); + rc = duk_hobject_delprop(thr, tv_obj, tv_key, flags); DUK_ASSERT(rc == 0 || rc == 1); duk_pop(ctx); /* remove key */ @@ -247,7 +251,7 @@ DUK_EXTERNAL duk_bool_t duk_has_prop(duk_context *ctx, duk_idx_t obj_idx) { tv_obj = duk_require_tval(ctx, obj_idx); tv_key = duk_require_tval(ctx, -1); - rc = duk_hobject_hasprop(thr, tv_obj, tv_key); + rc = duk_hobject_hasprop(thr, tv_obj, tv_key, DUK_PROP_FLAG_INTERNAL /*flags*/); DUK_ASSERT(rc == 0 || rc == 1); duk_pop(ctx); /* remove key */ diff --git a/src-input/duk_bi_json.c b/src-input/duk_bi_json.c index bcd69250..2ef0525e 100644 --- a/src-input/duk_bi_json.c +++ b/src-input/duk_bi_json.c @@ -1949,7 +1949,7 @@ DUK_LOCAL duk_bool_t duk__enc_value(duk_json_enc_ctx *js_ctx, duk_idx_t idx_hold DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv_holder)); tv_key = DUK_GET_TVAL_NEGIDX(ctx, -1); DUK_ASSERT(DUK_TVAL_IS_STRING(tv_key)); - (void) duk_hobject_getprop(thr, tv_holder, tv_key); + (void) duk_hobject_getprop(thr, tv_holder, tv_key, 0 /*flags*/); /* FIXME: allow internal? */ /* -> [ ... key val ] */ diff --git a/src-input/duk_bi_reflect.c b/src-input/duk_bi_reflect.c index 81ff6120..8fcedc39 100644 --- a/src-input/duk_bi_reflect.c +++ b/src-input/duk_bi_reflect.c @@ -53,7 +53,7 @@ DUK_INTERNAL duk_ret_t duk_bi_reflect_object_get(duk_context *ctx) { DUK_ASSERT(thr != NULL); tv_obj = DUK_GET_TVAL_POSIDX(ctx, 0); tv_key = DUK_GET_TVAL_POSIDX(ctx, 1); - (void) duk_hobject_getprop(thr, tv_obj, tv_key); /* This could also be a duk_get_prop(). */ + (void) duk_hobject_getprop(thr, tv_obj, tv_key, 0 /*flags*/); /* This could also be a duk_get_prop(). */ return 1; } @@ -73,7 +73,7 @@ DUK_INTERNAL duk_ret_t duk_bi_reflect_object_has(duk_context *ctx) { DUK_ASSERT(thr != NULL); tv_obj = DUK_GET_TVAL_POSIDX(ctx, 0); tv_key = DUK_GET_TVAL_POSIDX(ctx, 1); - ret = duk_hobject_hasprop(thr, tv_obj, tv_key); + ret = duk_hobject_hasprop(thr, tv_obj, tv_key, 0 /*flags*/); duk_push_boolean(ctx, ret); return 1; } diff --git a/src-input/duk_hobject.h b/src-input/duk_hobject.h index 6a40684f..bef99d63 100644 --- a/src-input/duk_hobject.h +++ b/src-input/duk_hobject.h @@ -873,14 +873,15 @@ DUK_INTERNAL_DECL duk_bool_t duk_hobject_get_own_propdesc(duk_hthread *thr, duk_ duk_hobject_find_existing_entry_tval_ptr((heap), (obj), DUK_HEAP_STRING_INT_VALUE((heap))) /* core property functions */ -DUK_INTERNAL_DECL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key); -DUK_INTERNAL_DECL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key, duk_tval *tv_val, duk_bool_t throw_flag); -DUK_INTERNAL_DECL duk_bool_t duk_hobject_delprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key, duk_bool_t throw_flag); -DUK_INTERNAL_DECL duk_bool_t duk_hobject_hasprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key); +#define DUK_PROP_FLAG_THROW (1 << 0) +#define DUK_PROP_FLAG_FORCE (1 << 1) +#define DUK_PROP_FLAG_INTERNAL (1 << 2) /* allow access to internal keys */ +DUK_INTERNAL_DECL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key, duk_small_uint_t flags); +DUK_INTERNAL_DECL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key, duk_tval *tv_val, duk_small_uint_t flags); +DUK_INTERNAL_DECL duk_bool_t duk_hobject_delprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key, duk_small_uint_t flags); +DUK_INTERNAL_DECL duk_bool_t duk_hobject_hasprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key, duk_small_uint_t flags); /* internal property functions */ -#define DUK_DELPROP_FLAG_THROW (1 << 0) -#define DUK_DELPROP_FLAG_FORCE (1 << 1) DUK_INTERNAL_DECL duk_bool_t duk_hobject_delprop_raw(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_small_uint_t flags); DUK_INTERNAL_DECL duk_bool_t duk_hobject_hasprop_raw(duk_hthread *thr, duk_hobject *obj, duk_hstring *key); DUK_INTERNAL_DECL void duk_hobject_define_property_internal(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_small_uint_t flags); diff --git a/src-input/duk_hobject_props.c b/src-input/duk_hobject_props.c index 31bc8c84..690a9081 100644 --- a/src-input/duk_hobject_props.c +++ b/src-input/duk_hobject_props.c @@ -107,7 +107,7 @@ DUK_LOCAL duk_uint32_t duk__tval_number_to_arr_idx(duk_tval *tv) { dbl = DUK_TVAL_GET_NUMBER(tv); idx = (duk_uint32_t) dbl; if ((duk_double_t) idx == dbl) { - /* Is whole and within 32 bit range. If the value happens to be 0xFFFFFFFF, + /* Is whole and within 32 bit range. If the value happens to be 0xFFFFFFFF, * it's not a valid array index but will then match DUK__NO_ARRAY_INDEX. */ return idx; @@ -1669,6 +1669,23 @@ DUK_LOCAL duk_bool_t duk__get_own_propdesc_raw(duk_hthread *thr, duk_hobject *ob if (out_desc->e_idx >= 0) { duk_int_t e_idx = out_desc->e_idx; out_desc->flags = DUK_HOBJECT_E_GET_FLAGS(thr->heap, obj, e_idx); + +#if 0 + /* FIXME: this would impact all prototype lookup steps but + * fixes Object.defineProperty() etc automatically. + */ + if (DUK_HSTRING_HAS_INTERNAL(key)) { + DUK_DDD(DUK_DDDPRINT("-> internal property, pretend 'undefined' and protected")); + + if (flags & DUK__DESC_FLAG_PUSH_VALUE) { + duk_push_undefined(ctx); + } + out_desc->flags = DUK_PROPDESC_FLAG_ENUMERABLE | /* E5 Section 15.5.5.2 */ + DUK_PROPDESC_FLAG_VIRTUAL; + return 1; + } +#endif + if (out_desc->flags & DUK_PROPDESC_FLAG_ACCESSOR) { DUK_DDD(DUK_DDDPRINT("-> found accessor property in entry part")); out_desc->get = DUK_HOBJECT_E_GET_VALUE_GETTER(thr->heap, obj, e_idx); @@ -2276,7 +2293,7 @@ DUK_LOCAL duk_bool_t duk__putprop_fastpath_bufobj_tval(duk_hthread *thr, duk_hob * GETPROP: Ecmascript property read. */ -DUK_INTERNAL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key) { +DUK_INTERNAL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key, duk_small_uint_t flags) { duk_context *ctx = (duk_context *) thr; duk_tval tv_obj_copy; duk_tval tv_key_copy; @@ -2285,6 +2302,9 @@ DUK_INTERNAL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj, duk_uint32_t arr_idx = DUK__NO_ARRAY_INDEX; duk_propdesc desc; duk_uint_t sanity; + duk_bool_t internal_flag; + + internal_flag = (flags & DUK_PROP_FLAG_INTERNAL); DUK_DDD(DUK_DDDPRINT("getprop: thr=%p, obj=%p, key=%p (obj -> %!T, key -> %!T)", (void *) thr, (void *) tv_obj, (void *) tv_key, @@ -2447,6 +2467,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj, arr_idx = duk__push_tval_to_hstring_arr_idx(ctx, tv_key, &key); DUK_ASSERT(key != NULL); + /* FIXME: internal property check */ if (duk__get_own_propdesc_raw(thr, h_target, key, arr_idx, &desc, DUK_GETDESC_FLAG_PUSH_VALUE)) { duk_tval *tv_hook = duk_require_tval(ctx, -3); /* value from hook */ duk_tval *tv_targ = duk_require_tval(ctx, -1); /* value from target */ @@ -2647,6 +2668,12 @@ DUK_INTERNAL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj, DUK_ASSERT(curr != NULL); DUK_ASSERT(key != NULL); + /* FIXME: this applies to the "front end" of a property lookup */ + if (DUK_HSTRING_HAS_INTERNAL(key) && !internal_flag) { + DUK_DDD(DUK_DDDPRINT("-> internal property, pretend 'undefined' and protected")); + goto not_found; + } + sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY; do { if (!duk__get_own_propdesc_raw(thr, curr, key, arr_idx, &desc, DUK_GETDESC_FLAG_PUSH_VALUE)) { @@ -2700,6 +2727,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj, * Not found */ + not_found: duk_to_undefined(ctx, -1); /* [key] -> [undefined] (default value) */ DUK_DDD(DUK_DDDPRINT("-> %!T (not found)", (duk_tval *) duk_get_tval(ctx, -1))); @@ -2780,7 +2808,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj, * the target object. */ -DUK_INTERNAL duk_bool_t duk_hobject_hasprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key) { +DUK_INTERNAL duk_bool_t duk_hobject_hasprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key, duk_small_uint_t flags) { duk_context *ctx = (duk_context *) thr; duk_tval tv_key_copy; duk_hobject *obj; @@ -2788,6 +2816,9 @@ DUK_INTERNAL duk_bool_t duk_hobject_hasprop(duk_hthread *thr, duk_tval *tv_obj, duk_uint32_t arr_idx; duk_bool_t rc; duk_propdesc desc; + duk_bool_t internal_flag; + + internal_flag = (flags & DUK_PROP_FLAG_INTERNAL); DUK_DDD(DUK_DDDPRINT("hasprop: thr=%p, obj=%p, key=%p (obj -> %!T, key -> %!T)", (void *) thr, (void *) tv_obj, (void *) tv_key, @@ -2853,6 +2884,13 @@ DUK_INTERNAL duk_bool_t duk_hobject_hasprop(duk_hthread *thr, duk_tval *tv_obj, DUK_ASSERT(obj != NULL); DUK_UNREF(arr_idx); + /* FIXME: this applies to the "front end" of a property lookup */ + if (DUK_HSTRING_HAS_INTERNAL(key) && !internal_flag) { + DUK_DDD(DUK_DDDPRINT("-> internal property, pretend 'undefined' and protected")); + rc = 0; + goto pop_and_return; + } + #if defined(DUK_USE_ES6_PROXY) if (DUK_UNLIKELY(DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(obj))) { duk_hobject *h_target; @@ -3166,7 +3204,7 @@ duk_bool_t duk__handle_put_array_length_smaller(duk_hthread *thr, * The delete always succeeds: key has no exotic behavior, property * is configurable, and no resize occurs. */ - rc = duk_hobject_delprop_raw(thr, obj, key, force_flag ? DUK_DELPROP_FLAG_FORCE : 0); + rc = duk_hobject_delprop_raw(thr, obj, key, force_flag ? DUK_PROP_FLAG_FORCE : 0); DUK_UNREF(rc); DUK_ASSERT(rc != 0); } @@ -3292,7 +3330,7 @@ DUK_LOCAL duk_bool_t duk__handle_put_array_length(duk_hthread *thr, duk_hobject * (We currently make a copy of all of the input values to avoid issues.) */ -DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key, duk_tval *tv_val, duk_bool_t throw_flag) { +DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key, duk_tval *tv_val, duk_small_uint_t flags) { duk_context *ctx = (duk_context *) thr; duk_tval tv_obj_copy; duk_tval tv_key_copy; @@ -3307,11 +3345,16 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj, duk_int_t e_idx; duk_uint_t sanity; duk_uint32_t new_array_length = 0; /* 0 = no update */ + duk_bool_t throw_flag; + duk_bool_t internal_flag; - DUK_DDD(DUK_DDDPRINT("putprop: thr=%p, obj=%p, key=%p, val=%p, throw=%ld " + throw_flag = (flags & DUK_PROP_FLAG_THROW); + internal_flag = (flags & DUK_PROP_FLAG_INTERNAL); + + DUK_DDD(DUK_DDDPRINT("putprop: thr=%p, obj=%p, key=%p, val=%p, flags=%lx " "(obj -> %!T, key -> %!T, val -> %!T)", (void *) thr, (void *) tv_obj, (void *) tv_key, (void *) tv_val, - (long) throw_flag, (duk_tval *) tv_obj, (duk_tval *) tv_key, (duk_tval *) tv_val)); + (unsigned long) flags, (duk_tval *) tv_obj, (duk_tval *) tv_key, (duk_tval *) tv_val)); DUK_ASSERT(thr != NULL); DUK_ASSERT(thr->heap != NULL); @@ -3460,6 +3503,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj, arr_idx = duk__push_tval_to_hstring_arr_idx(ctx, tv_key, &key); DUK_ASSERT(key != NULL); + /* FIXME: internal key check */ if (duk__get_own_propdesc_raw(thr, h_target, key, arr_idx, &desc, DUK_GETDESC_FLAG_PUSH_VALUE)) { duk_tval *tv_targ = duk_require_tval(ctx, -1); duk_bool_t datadesc_reject; @@ -3619,6 +3663,12 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj, lookup: + /* FIXME: this applies to the "front end" of a property lookup */ + if (DUK_HSTRING_HAS_INTERNAL(key) && !internal_flag) { + DUK_DDD(DUK_DDDPRINT("-> internal property, pretend 'undefined' and protected")); + goto fail_not_writable; + } + /* * Check whether the property already exists in the prototype chain. * Note that the actual write goes into the original base object @@ -4217,8 +4267,10 @@ DUK_INTERNAL duk_bool_t duk_hobject_delprop_raw(duk_hthread *thr, duk_hobject *o duk_bool_t throw_flag; duk_bool_t force_flag; - throw_flag = (flags & DUK_DELPROP_FLAG_THROW); - force_flag = (flags & DUK_DELPROP_FLAG_FORCE); + /* FIXME: this always allows internal property deletion */ + + throw_flag = (flags & DUK_PROP_FLAG_THROW); + force_flag = (flags & DUK_PROP_FLAG_FORCE); DUK_DDD(DUK_DDDPRINT("delprop_raw: thr=%p, obj=%p, key=%p, throw=%ld, force=%ld (obj -> %!O, key -> %!O)", (void *) thr, (void *) obj, (void *) key, (long) throw_flag, (long) force_flag, @@ -4360,7 +4412,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_delprop_raw(duk_hthread *thr, duk_hobject *o * DELPROP: Ecmascript property deletion. */ -DUK_INTERNAL duk_bool_t duk_hobject_delprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key, duk_bool_t throw_flag) { +DUK_INTERNAL duk_bool_t duk_hobject_delprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key, duk_small_uint_t flags) { duk_context *ctx = (duk_context *) thr; duk_hstring *key = NULL; #if defined(DUK_USE_ES6_PROXY) @@ -4369,6 +4421,11 @@ DUK_INTERNAL duk_bool_t duk_hobject_delprop(duk_hthread *thr, duk_tval *tv_obj, duk_int_t entry_top; duk_uint32_t arr_idx = DUK__NO_ARRAY_INDEX; duk_bool_t rc; + duk_bool_t throw_flag; + duk_bool_t internal_flag; + + throw_flag = (flags & DUK_PROP_FLAG_THROW); + internal_flag = (flags & DUK_PROP_FLAG_INTERNAL); DUK_DDD(DUK_DDDPRINT("delprop: thr=%p, obj=%p, key=%p (obj -> %!T, key -> %!T)", (void *) thr, (void *) tv_obj, (void *) tv_key, @@ -4401,6 +4458,15 @@ DUK_INTERNAL duk_bool_t duk_hobject_delprop(duk_hthread *thr, duk_tval *tv_obj, duk_hobject *obj = DUK_TVAL_GET_OBJECT(tv_obj); DUK_ASSERT(obj != NULL); + arr_idx = duk__push_tval_to_hstring_arr_idx(ctx, tv_key, &key); + DUK_ASSERT(key != NULL); + + /* FIXME: this applies to the "front end" of a property lookup */ + if (DUK_HSTRING_HAS_INTERNAL(key) && !internal_flag) { + DUK_DDD(DUK_DDDPRINT("-> internal property, pretend 'undefined' and protected")); + goto fail_not_configurable; + } + #if defined(DUK_USE_ES6_PROXY) if (DUK_UNLIKELY(DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(obj))) { duk_hobject *h_target; @@ -4423,7 +4489,6 @@ DUK_INTERNAL duk_bool_t duk_hobject_delprop(duk_hthread *thr, duk_tval *tv_obj, /* Target object must be checked for a conflicting * non-configurable property. */ - arr_idx = duk__push_tval_to_hstring_arr_idx(ctx, tv_key, &key); DUK_ASSERT(key != NULL); if (duk__get_own_propdesc_raw(thr, h_target, key, arr_idx, &desc, 0 /*flags*/)) { /* don't push value */ @@ -4451,8 +4516,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_delprop(duk_hthread *thr, duk_tval *tv_obj, key = duk_to_hstring(ctx, -1); DUK_ASSERT(key != NULL); - - rc = duk_hobject_delprop_raw(thr, obj, key, throw_flag ? DUK_DELPROP_FLAG_THROW : 0); + rc = duk_hobject_delprop_raw(thr, obj, key, throw_flag ? DUK_PROP_FLAG_THROW : 0); goto done_rc; } else if (DUK_TVAL_IS_STRING(tv_obj)) { /* XXX: unnecessary string coercion for array indices, @@ -4751,7 +4815,7 @@ DUK_INTERNAL void duk_hobject_set_length(duk_hthread *thr, duk_hobject *obj, duk DUK_GET_TVAL_NEGIDX(ctx, -3), DUK_GET_TVAL_NEGIDX(ctx, -2), DUK_GET_TVAL_NEGIDX(ctx, -1), - 0); + 0 /*flags*/); duk_pop_n(ctx, 3); } @@ -4776,7 +4840,8 @@ DUK_INTERNAL duk_uint32_t duk_hobject_get_length(duk_hthread *thr, duk_hobject * duk_push_hstring_stridx(ctx, DUK_STRIDX_LENGTH); (void) duk_hobject_getprop(thr, DUK_GET_TVAL_NEGIDX(ctx, -2), - DUK_GET_TVAL_NEGIDX(ctx, -1)); + DUK_GET_TVAL_NEGIDX(ctx, -1), + 0 /*flags*/); val = duk_to_number(ctx, -1); duk_pop_n(ctx, 3); @@ -4807,6 +4872,8 @@ DUK_INTERNAL duk_ret_t duk_hobject_object_get_own_property_descriptor(duk_contex obj = duk_require_hobject_promote_mask(ctx, 0, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER); key = duk_to_hstring(ctx, 1); + /* FIXME: internal key check */ + DUK_ASSERT(obj != NULL); DUK_ASSERT(key != NULL); @@ -5037,6 +5104,7 @@ duk_bool_t duk_hobject_define_property_helper(duk_context *ctx, duk_bool_t is_configurable; duk_bool_t is_writable; duk_bool_t force_flag; + duk_bool_t internal_flag; duk_small_uint_t new_flags; duk_propdesc curr; duk_uint32_t arridx_new_array_length; /* != 0 => post-update for array 'length' (used when key is an array index) */ @@ -5065,6 +5133,7 @@ duk_bool_t duk_hobject_define_property_helper(duk_context *ctx, is_enumerable = (defprop_flags & DUK_DEFPROP_ENUMERABLE); is_configurable = (defprop_flags & DUK_DEFPROP_CONFIGURABLE); force_flag = (defprop_flags & DUK_DEFPROP_FORCE); + internal_flag = force_flag; /* FIXME: separate flag? */ arr_idx = DUK_HSTRING_GET_ARRIDX_SLOW(key); @@ -5088,6 +5157,12 @@ duk_bool_t duk_hobject_define_property_helper(duk_context *ctx, (long) has_set, (void *) set, (duk_heaphdr *) set, (long) arr_idx, (long) throw_flag)); + /* FIXME: this applies to the "front end" of a property lookup */ + if (DUK_HSTRING_HAS_INTERNAL(key) && !internal_flag) { + DUK_DDD(DUK_DDDPRINT("-> internal property, pretend 'undefined' and protected")); + goto fail_not_configurable; + } + /* * Array exotic behaviors can be implemented at this point. The local variables * are essentially a 'value copy' of the input descriptor (Desc), which is modified @@ -5906,6 +5981,8 @@ DUK_INTERNAL duk_bool_t duk_hobject_object_ownprop_helper(duk_context *ctx, duk_ h_v = duk_to_hstring(ctx, 0); DUK_ASSERT(h_v != NULL); + /* FIXME: internal key check */ + h_obj = duk_push_this_coercible_to_object(ctx); DUK_ASSERT(h_obj != NULL); diff --git a/src-input/duk_hthread_builtins.c b/src-input/duk_hthread_builtins.c index 10f8bfb0..837220e8 100644 --- a/src-input/duk_hthread_builtins.c +++ b/src-input/duk_hthread_builtins.c @@ -666,12 +666,12 @@ DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) { #if !defined(DUK_USE_ES6_OBJECT_PROTO_PROPERTY) DUK_DD(DUK_DDPRINT("delete Object.prototype.__proto__ built-in which is not enabled in features")); - (void) duk_hobject_delprop_raw(thr, thr->builtins[DUK_BIDX_OBJECT_PROTOTYPE], DUK_HTHREAD_STRING___PROTO__(thr), DUK_DELPROP_FLAG_THROW); + (void) duk_hobject_delprop_raw(thr, thr->builtins[DUK_BIDX_OBJECT_PROTOTYPE], DUK_HTHREAD_STRING___PROTO__(thr), DUK_PROP_FLAG_THROW); #endif #if !defined(DUK_USE_ES6_OBJECT_SETPROTOTYPEOF) DUK_DD(DUK_DDPRINT("delete Object.setPrototypeOf built-in which is not enabled in features")); - (void) duk_hobject_delprop_raw(thr, thr->builtins[DUK_BIDX_OBJECT_CONSTRUCTOR], DUK_HTHREAD_STRING_SET_PROTOTYPE_OF(thr), DUK_DELPROP_FLAG_THROW); + (void) duk_hobject_delprop_raw(thr, thr->builtins[DUK_BIDX_OBJECT_CONSTRUCTOR], DUK_HTHREAD_STRING_SET_PROTOTYPE_OF(thr), DUK_PROP_FLAG_THROW); #endif /* XXX: relocate */ diff --git a/src-input/duk_js_executor.c b/src-input/duk_js_executor.c index 0314952f..618f2a80 100644 --- a/src-input/duk_js_executor.c +++ b/src-input/duk_js_executor.c @@ -3518,7 +3518,7 @@ DUK_LOCAL DUK_NOINLINE void duk__js_execute_bytecode_inner(duk_hthread *entry_th tv_obj = DUK__REGCONSTP_B(ins); tv_key = DUK__REGCONSTP_C(ins); - rc = duk_hobject_getprop(thr, tv_obj, tv_key); /* -> [val] */ + rc = duk_hobject_getprop(thr, tv_obj, tv_key, 0 /*flags*/); /* -> [val] */ DUK_UNREF(rc); /* ignore */ tv_obj = NULL; /* invalidated */ tv_key = NULL; /* invalidated */ @@ -3541,7 +3541,9 @@ DUK_LOCAL DUK_NOINLINE void duk__js_execute_bytecode_inner(duk_hthread *entry_th DUK_ASSERT(tv_val != NULL); tv_obj = DUK__REGCONSTP_B(ins); tv_key = DUK__REGCONSTP_C(ins); - rc = duk_hobject_putprop(thr, tv_obj, tv_key, tv_val, DUK__STRICT()); + DUK_ASSERT(DUK_PROP_FLAG_THROW == 1); /* DUK__STRICT() -> throw flag */ + DUK_ASSERT(DUK__STRICT() == 0 || DUK__STRICT() == 1); + rc = duk_hobject_putprop(thr, tv_obj, tv_key, tv_val, DUK__STRICT() /*flags*/); DUK_UNREF(rc); /* ignore */ tv_obj = NULL; /* invalidated */ tv_key = NULL; /* invalidated */ @@ -3567,7 +3569,7 @@ DUK_LOCAL DUK_NOINLINE void duk__js_execute_bytecode_inner(duk_hthread *entry_th * B -> object reg/const (may be const e.g. in "'foo'[1]") \ * C -> key reg/const \ */ \ - (void) duk_hobject_getprop(thr, (barg), (carg)); \ + (void) duk_hobject_getprop(thr, (barg), (carg), 0 /*flags*/); \ DUK__REPLACE_TOP_A_BREAK(); \ } #define DUK__PUTPROP_BODY(aarg,barg,carg) { \ @@ -3578,7 +3580,9 @@ DUK_LOCAL DUK_NOINLINE void duk__js_execute_bytecode_inner(duk_hthread *entry_th * Note: intentional difference to register arrangement \ * of e.g. GETPROP; 'A' must contain a register-only value. \ */ \ - (void) duk_hobject_putprop(thr, (aarg), (barg), (carg), DUK__STRICT()); \ + DUK_ASSERT(DUK_PROP_FLAG_THROW == 1); /* DUK__STRICT() -> throw flag */ \ + DUK_ASSERT(DUK__STRICT() == 0 || DUK__STRICT() == 1); \ + (void) duk_hobject_putprop(thr, (aarg), (barg), (carg), DUK__STRICT() /*flags*/); \ break; \ } #define DUK__DELPROP_BODY(barg,carg) { \ @@ -3587,7 +3591,9 @@ DUK_LOCAL DUK_NOINLINE void duk__js_execute_bytecode_inner(duk_hthread *entry_th * C -> key reg/const \ */ \ duk_bool_t rc; \ - rc = duk_hobject_delprop(thr, (barg), (carg), DUK__STRICT()); \ + DUK_ASSERT(DUK_PROP_FLAG_THROW == 1); /* DUK__STRICT() -> throw flag */\ + DUK_ASSERT(DUK__STRICT() == 0 || DUK__STRICT() == 1); \ + rc = duk_hobject_delprop(thr, (barg), (carg), DUK__STRICT() /*flags*/); \ DUK_ASSERT(rc == 0 || rc == 1); \ DUK__REPLACE_BOOL_A_BREAK(rc); \ } diff --git a/src-input/duk_js_ops.c b/src-input/duk_js_ops.c index 38eba944..1239a75f 100644 --- a/src-input/duk_js_ops.c +++ b/src-input/duk_js_ops.c @@ -1192,7 +1192,8 @@ DUK_INTERNAL duk_bool_t duk_js_in(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv retval = duk_hobject_hasprop(thr, DUK_GET_TVAL_NEGIDX(ctx, -1), - DUK_GET_TVAL_NEGIDX(ctx, -2)); + DUK_GET_TVAL_NEGIDX(ctx, -2), + 0 /*flags*/); duk_pop_2(ctx); return retval; diff --git a/src-input/duk_js_var.c b/src-input/duk_js_var.c index 3431f284..d7637f15 100644 --- a/src-input/duk_js_var.c +++ b/src-input/duk_js_var.c @@ -1082,14 +1082,14 @@ duk_bool_t duk__get_identifier_reference(duk_hthread *thr, DUK_ASSERT(name != NULL); DUK_TVAL_SET_STRING(&tv_name, name); - found = duk_hobject_hasprop(thr, tv_target, &tv_name); + found = duk_hobject_hasprop(thr, tv_target, &tv_name, 0 /*flags*/); /* FIXME: internal? */ } else { /* XXX: duk_hobject_hasprop() would be correct for * non-Proxy objects too, but it is about ~20-25% * slower at present so separate code paths for * Proxy and non-Proxy now. */ - found = duk_hobject_hasprop_raw(thr, target, name); + found = duk_hobject_hasprop_raw(thr, target, name); /* FIXME: internal? */ } if (found) { @@ -1245,7 +1245,7 @@ duk_bool_t duk__getvar_helper(duk_hthread *thr, DUK_TVAL_SET_OBJECT(&tv_tmp_obj, ref.holder); DUK_TVAL_SET_STRING(&tv_tmp_key, name); - (void) duk_hobject_getprop(thr, &tv_tmp_obj, &tv_tmp_key); /* [this value] */ + (void) duk_hobject_getprop(thr, &tv_tmp_obj, &tv_tmp_key, 0 /*flags*/); /* [this value] */ /* ref.value, ref.this.binding invalidated here by getprop call */ @@ -1364,6 +1364,8 @@ void duk__putvar_helper(duk_hthread *thr, DUK_TVAL_SET_OBJECT(&tv_tmp_obj, ref.holder); DUK_TVAL_SET_STRING(&tv_tmp_key, name); + DUK_ASSERT(DUK_PROP_FLAG_THROW == 1); /* strict -> throw flag */ + DUK_ASSERT(strict == 0 || strict == 1); (void) duk_hobject_putprop(thr, &tv_tmp_obj, &tv_tmp_key, val, strict); /* ref.value and ref.this_binding invalidated here */ @@ -1388,7 +1390,7 @@ void duk__putvar_helper(duk_hthread *thr, DUK_TVAL_SET_OBJECT(&tv_tmp_obj, thr->builtins[DUK_BIDX_GLOBAL]); DUK_TVAL_SET_STRING(&tv_tmp_key, name); - (void) duk_hobject_putprop(thr, &tv_tmp_obj, &tv_tmp_key, val, 0); /* 0 = no throw */ + (void) duk_hobject_putprop(thr, &tv_tmp_obj, &tv_tmp_key, val, 0 /*flags*/); /* 0 = no throw */ /* NB: 'val' may be invalidated here because put_value may realloc valstack, * caller beware.