diff --git a/releases/releases.yaml b/releases/releases.yaml index f5270bfd9c..43256960fb 100644 --- a/releases/releases.yaml +++ b/releases/releases.yaml @@ -1366,3 +1366,4 @@ duktape_releases: - "Fix failing assert for CBOR.encode() when argument is a zero-size dynamic plain array (GH-2316, GH-2318)" - "Fix pointer overflow in String.prototype.startsWith/endsWith() with certain arguments (GH-2320)" - "Fix assertion failure and incorrect behavior in some enumeration cases involving inherited duplicate keys (GH-2322)" + - "Fix unstable pointer in 'putvar' which could trigger e.g. in a with(proxy) statement (GH-2323)" diff --git a/src-input/duk_js_var.c b/src-input/duk_js_var.c index 9e78a0815e..0a84a65d9f 100644 --- a/src-input/duk_js_var.c +++ b/src-input/duk_js_var.c @@ -1281,6 +1281,7 @@ void duk__putvar_helper(duk_hthread *thr, duk_tval *val, duk_bool_t strict) { duk__id_lookup_result ref; + duk_tval tv_tmp_val; duk_tval tv_tmp_obj; duk_tval tv_tmp_key; duk_bool_t parents; @@ -1298,10 +1299,13 @@ void duk__putvar_helper(duk_hthread *thr, DUK_ASSERT(val != NULL); /* env and act may be NULL */ - DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(env); - DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(name); + DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(env); + DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(name); DUK_ASSERT_REFCOUNT_NONZERO_TVAL(val); + DUK_TVAL_SET_TVAL(&tv_tmp_val, val); /* Stabilize. */ + val = NULL; + /* * In strict mode E5 protects 'eval' and 'arguments' from being * assigned to (or even declared anywhere). Attempt to do so @@ -1333,7 +1337,7 @@ void duk__putvar_helper(duk_hthread *thr, tv_val = ref.value; DUK_ASSERT(tv_val != NULL); - DUK_TVAL_SET_TVAL_UPDREF(thr, tv_val, val); /* side effects */ + DUK_TVAL_SET_TVAL_UPDREF(thr, tv_val, &tv_tmp_val); /* side effects */ /* ref.value invalidated here */ } else { @@ -1341,7 +1345,7 @@ void duk__putvar_helper(duk_hthread *thr, DUK_TVAL_SET_OBJECT(&tv_tmp_obj, ref.holder); DUK_TVAL_SET_STRING(&tv_tmp_key, name); - (void) duk_hobject_putprop(thr, &tv_tmp_obj, &tv_tmp_key, val, strict); + (void) duk_hobject_putprop(thr, &tv_tmp_obj, &tv_tmp_key, &tv_tmp_val, strict); /* ref.value invalidated here */ } @@ -1366,7 +1370,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, &tv_tmp_val, 0); /* 0 = no throw */ /* NB: 'val' may be invalidated here because put_value may realloc valstack, * caller beware. diff --git a/tests/ecmascript/test-bug-putvar-ptrstab-proxywith-gh2323.js b/tests/ecmascript/test-bug-putvar-ptrstab-proxywith-gh2323.js new file mode 100644 index 0000000000..3ce80407db --- /dev/null +++ b/tests/ecmascript/test-bug-putvar-ptrstab-proxywith-gh2323.js @@ -0,0 +1,20 @@ +/*=== +done +===*/ + +function main() { + var v3 = [2,2,2,2,2,2,2,2,2]; + var v4 = v3; + var v5 = {constructor:String,call:String,apply:String,get:String,construct:String,defineProperty:String,has:String,preventExtensions:String}; + v3.length = 1343; + var v7 = new Proxy(v4,v5); + with (v7) { + var v9 = 0; + } +} +try { + main(); +} catch (e) { + print(e.stack || e); +} +print('done');