Repository navigation
Conversation
ObjectDefineProperties (ECMA-262 20.1.2.3.1) looks up each own key with [[GetOwnProperty]] and reads and converts its descriptor before moving on to the next key, and defines the properties only after every descriptor has been converted. Object.defineProperties and Object.create filtered all the keys for enumerability up front, so a proxy saw every getOwnPropertyDescriptor call before the first get, and a getter that changed a later key was not seen. Each property was also defined right after its descriptor was read, so an invalid descriptor for a later key left the earlier ones defined. Check each key and convert its descriptor in one loop, then define the properties in a second loop, as the XXX comment suggested. Fixes quickjs-ng#1794
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #1794.
ObjectDefineProperties(ECMA-262 20.1.2.3.1) does two passes. The first pass goes through each own key. For each key it calls[[GetOwnProperty]], and if the property is enumerable it reads the descriptor object withGetand converts it withToPropertyDescriptor. Only then does it move on to the next key. The second pass defines the properties after every descriptor has been converted.JS_ObjectDefineProperties, whichObject.definePropertiesandObject.createboth use, differed in two ways:JS_GPN_ENUM_ONLY). A proxy therefore saw everygetOwnPropertyDescriptorcall before the firstget:ownKeys, gopd a, gopd b, get a, get binstead ofownKeys, gopd a, get a, gopd b, get b. A getter that made a later key non-enumerable, or deleted it, was also not taken into account.XXXcomment pointed this out.This change checks each key and converts its descriptor in a single loop, storing the results in an array. A second loop defines the properties.
Object.definePropertyis unchanged.V8 (Node 26.10.0) passes every assertion in the new test.
Validation:
tests/bug1794.js. On master it fails at line 12 withgot |ownKeys,gopd a,gopd b,get a,get b|, expected |ownKeys,gopd a,get a,gopd b,get b|. With this change it passes.test262/test/staging/sm/object/defineProperties-order.js(staging is excluded intest262.conf) fails on master and passes with this change.run-test262 -m -c test262.conf -a:40/82220 errors, the same as on master, and they matchtest262_errors.txt.run-test262 -c tests.conf:1/121 errors. The one failure istests/test_std.js:254("second pipe handler was not called"), which fails the same way on master on this macOS machine.tests/bug1794.js, the test262built-ins/Object/defineProperties,built-ins/Object/createandbuilt-ins/Object/definePropertydirectories (0 errors), and a script that exercises the error paths (a throwing getter, a throwing descriptor field, a define failure on a frozen target, a throwing proxy trap) all ran clean.cmake -DQJS_BUILD_WERROR=ONbuild,make ctest cxxtest, and a-DJS_CHECK_JSVALUE -Wall -Werror -fsyntax-onlycheck ofquickjs.call pass.make codegenleaves no diff.