-
Notifications
You must be signed in to change notification settings - Fork 2.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Restrict DeepMerger
mutable object reuse to fix subtle production-only bug
#9742
Conversation
merge(a, b) { | ||
// We use the same DeepMerger instance throughout the read, so any | ||
// merged objects created during this read can be updated later in the | ||
// read using in-place/destructive property assignments. Once the read | ||
// is finished, these objects will be frozen, but in the meantime it's | ||
// good for performance and memory usage if we avoid allocating a new | ||
// object for every merged property. | ||
return merger.merge(a, b); | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This comment might have been right about it being "good for performance and memory usage if we avoid allocating a new object for every merged property," in theory, but you have to be prepared to abandon any optimization that causes bugs, as this one did.
9fc3818
to
916f974
Compare
LGTM. I've checked and confirmed that this does resolve the bug in the sample reproduction in #9735. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch! Thanks Ben.
If you revert the previous commit and run `npm test`, you'll see all the tests this dynamic Object.isFrozen check has been silently protecting from failing, but only (and this is the important part) in development. Since we only actually freeze objects with Object.freeze in development, this Object.isFrozen check does not help in production, so an object that would have been frozen in development gets reused as a mutable copy, potentially acquiring properties it should not acquire (a bug fixed by the previous commit, first reported in issue #9735).
916f974
to
570b7f3
Compare
Issue #9735 appears to be due to a bug I introduced in my commit 756ab87 in PR #8734. This PR takes us (partially) back to the way things worked before that commit.
I believe I've found two complementary ways to fix this problem:
Thanks very much to @akallem for some deep debugging and an excellent reproduction in #9735.