From: Dmitry Volyntsev Date: Tue, 3 Mar 2026 02:00:09 +0000 (-0800) Subject: Fixed logical assignment short-circuit with non-writable properties. X-Git-Tag: 0.9.6~3 X-Git-Url: http://www.kaiwu.me/postgresql/commit/static/gitweb.js?a=commitdiff_plain;h=9e97ff87c681d99635e1e2637f748742c65912fc;p=njs.git Fixed logical assignment short-circuit with non-writable properties. When the logical condition was already satisfied (e.g., falsy for &&=, truthy for ||=, non-nullish for ??=), the short-circuit jump landed on the property set instruction instead of past it. This caused spurious TypeErrors for non-writable, getter-only, and non-extensible property targets even though no assignment should occur. This fixes logical assignment introduced in 1a64ba68. This change fixes 9 more tests in test262. --- diff --git a/src/njs_generator.c b/src/njs_generator.c index 9de1a145..c2f1856d 100644 --- a/src/njs_generator.c +++ b/src/njs_generator.c @@ -3773,15 +3773,15 @@ njs_generate_logical_assignment_end(njs_vm_t *vm, expr->index, node); } - njs_code_set_jump_offset(generator, njs_vmcode_test_jump_t, - ctx->jump_offset); - if (ctx->prop_index == NJS_INDEX_NONE) { ret = njs_generate_global_property_set(vm, generator, lvalue, expr); if (njs_slow_path(ret != NJS_OK)) { return ret; } + njs_code_set_jump_offset(generator, njs_vmcode_test_jump_t, + ctx->jump_offset); + node->index = lvalue->index; ret = njs_generate_node_index_release(vm, generator, expr); @@ -3798,6 +3798,9 @@ njs_generate_logical_assignment_end(njs_vm_t *vm, return ret; } + njs_code_set_jump_offset(generator, njs_vmcode_test_jump_t, + ctx->jump_offset); + ret = njs_generate_children_indexes_release(vm, generator, lvalue); if (njs_slow_path(ret != NJS_OK)) { return ret; diff --git a/src/test/njs_unit_test.c b/src/test/njs_unit_test.c index bbe70ebb..f9b7266e 100644 --- a/src/test/njs_unit_test.c +++ b/src/test/njs_unit_test.c @@ -1618,6 +1618,38 @@ static njs_unit_test_t njs_test[] = "log"), njs_str("gs") }, + /* Logical assignment: short-circuit with non-writable property. */ + + { njs_str("var o = {};" + "Object.defineProperty(o, 'x', {value: 0, writable: false});" + "o.x &&= 1"), + njs_str("0") }, + { njs_str("var o = {};" + "Object.defineProperty(o, 'x', {value: 2, writable: false});" + "o.x ||= 1"), + njs_str("2") }, + + /* Logical assignment: short-circuit with getter-only property. */ + + { njs_str("var o = {};" + "Object.defineProperty(o, 'x'," + " {get: function() {return 0}, set: undefined});" + "o.x &&= 1"), + njs_str("0") }, + { njs_str("var o = {};" + "Object.defineProperty(o, 'x'," + " {get: function() {return 2}, set: undefined});" + "o.x ||= 1"), + njs_str("2") }, + + /* Logical assignment: short-circuit with non-extensible object. */ + + { njs_str("var o = {};" + "Object.preventExtensions(o);" + "o.prop &&= 1;" + "o.prop"), + njs_str("undefined") }, + /* Logical assignment: non-lvalue error */ { njs_str("1 ||= 2"), @@ -1689,6 +1721,21 @@ static njs_unit_test_t njs_test[] = "log"), njs_str("gs") }, + /* ??= short-circuit with non-writable property. */ + + { njs_str("var o = {};" + "Object.defineProperty(o, 'x', {value: 0, writable: false});" + "o.x ?\?= 1"), + njs_str("0") }, + + /* ??= short-circuit with getter-only property. */ + + { njs_str("var o = {};" + "Object.defineProperty(o, 'x'," + " {get: function() {return 0}, set: undefined});" + "o.x ?\?= 1"), + njs_str("0") }, + /* ??= non-lvalue error */ { njs_str("1 ?\?= 2"),