-
Notifications
You must be signed in to change notification settings - Fork 30k
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
n-api: unlink reference during its destructor #35933
n-api: unlink reference during its destructor #35933
Conversation
Currently, a reference is being unlinked from the list of references tracked by the environment when `v8impl::Reference::Delete` is called. This causes a leak when deletion must be deferred because the finalizer hasn't yet run, but the finalizer does not run because environment teardown is in progress, and so no more gc runs will happen, and the `FinalizeAll` run that happens during environment teardown does not catch the reference because it's no longer in the list. The test below will fail when running with ASAN: ``` ./node ./test/node-api/test_worker_terminate_finalization/test.js ``` OTOH if, to address the above leak, we make a special case to not unlink a reference during environment teardown, we run into a situation where the reference gets deleted by `v8impl::Reference::Delete` but does not get unlinked because it's environment teardown time. This leaves a stale pointer in the linked list which will result in a use-after-free in `FinalizeAll` during environment teardown. The test below will fail if we make the above change: ``` ./node -e "require('./test/node-api/test_instance_data/build/Release/test_ref_then_set.node');" ``` Thus, we unlink a reference precisely when we destroy it – in its destructor. Refs: nodejs#34731 Refs: nodejs#34839 Refs: nodejs#35620 Refs: nodejs#35777 Fixes: nodejs#35778 Signed-off-by: Gabriel Schulhof <gabriel.schulhof@intel.com>
Review requested:
|
@himself65 @Trott I made the destructor virtual. |
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.
LGTM, great that we discussed this in the last N-API team meeting.
Commit Queue failed- Loading data for nodejs/node/pull/35933 ✔ Done loading data for nodejs/node/pull/35933 ----------------------------------- PR info ------------------------------------ Title n-api: unlink reference during its destructor (#35933) ⚠ Could not retrieve the email or name of the PR author's from user's GitHub profile! Branch gabrielschulhof:reference-segfault-35620-final -> nodejs:master Labels C++, n-api Commits 2 - n-api: unlink reference during its destructor - fixup! make the destructor virtual Committers 1 - Gabriel Schulhof PR-URL: https://github.com/nodejs/node/pull/35933 Fixes: https://github.com/nodejs/node/issues/35778 Refs: https://github.com/nodejs/node/issues/34731 Refs: https://github.com/nodejs/node/pull/34839 Refs: https://github.com/nodejs/node/issues/35620 Refs: https://github.com/nodejs/node/pull/35777 Reviewed-By: Zeyu Yang Reviewed-By: Rich Trott Reviewed-By: Michael Dawson ------------------------------ Generated metadata ------------------------------ PR-URL: https://github.com/nodejs/node/pull/35933 Fixes: https://github.com/nodejs/node/issues/35778 Refs: https://github.com/nodejs/node/issues/34731 Refs: https://github.com/nodejs/node/pull/34839 Refs: https://github.com/nodejs/node/issues/35620 Refs: https://github.com/nodejs/node/pull/35777 Reviewed-By: Zeyu Yang Reviewed-By: Rich Trott Reviewed-By: Michael Dawson -------------------------------------------------------------------------------- ✔ Last GitHub Actions successful ℹ Last Full PR CI on 2020-11-03T19:46:51Z: https://ci.nodejs.org/job/node-test-pull-request/34041/ - Querying data for job/node-test-pull-request/34041/ ✔ Build data downloaded ✔ Last Jenkins CI successful ℹ This PR was created on Mon, 02 Nov 2020 23:33:51 GMT ✔ Approvals: 3 ✔ - Zeyu Yang (@himself65): https://github.com/nodejs/node/pull/35933#pullrequestreview-522152386 ✔ - Rich Trott (@Trott) (TSC): https://github.com/nodejs/node/pull/35933#pullrequestreview-522500099 ✔ - Michael Dawson (@mhdawson) (TSC): https://github.com/nodejs/node/pull/35933#pullrequestreview-523676946 -------------------------------------------------------------------------------- ✔ No git cherry-pick in progress ✔ No git am in progress ✔ No git rebase in progress -------------------------------------------------------------------------------- - Bringing origin/master up to date... From https://github.com/nodejs/node * branch master -> FETCH_HEAD ✔ origin/master is now up-to-date - Downloading patch for 35933 From https://github.com/nodejs/node * branch refs/pull/35933/merge -> FETCH_HEAD ✔ Fetched commits as d4d6dfdb9412..b2cf693bbfd6 -------------------------------------------------------------------------------- [master 5ae2240fe7] n-api: unlink reference during its destructor Author: Gabriel Schulhof Date: Mon Nov 2 15:06:23 2020 -0800 2 files changed, 2 insertions(+), 3 deletions(-) [master 275e347723] fixup! make the destructor virtual Author: Gabriel Schulhof Date: Tue Nov 3 08:16:59 2020 -0800 1 file changed, 1 insertion(+), 1 deletion(-) ✔ Patches applied There are 2 commits in the PR. Attempting autorebase. Rebasing (2/4) Commit Queue action: https://github.com/nodejs/node/actions/runs/346580978 |
Landed in c822ba7. |
Currently, a reference is being unlinked from the list of references tracked by the environment when `v8impl::Reference::Delete` is called. This causes a leak when deletion must be deferred because the finalizer hasn't yet run, but the finalizer does not run because environment teardown is in progress, and so no more gc runs will happen, and the `FinalizeAll` run that happens during environment teardown does not catch the reference because it's no longer in the list. The test below will fail when running with ASAN: ``` ./node ./test/node-api/test_worker_terminate_finalization/test.js ``` OTOH if, to address the above leak, we make a special case to not unlink a reference during environment teardown, we run into a situation where the reference gets deleted by `v8impl::Reference::Delete` but does not get unlinked because it's environment teardown time. This leaves a stale pointer in the linked list which will result in a use-after-free in `FinalizeAll` during environment teardown. The test below will fail if we make the above change: ``` ./node -e "require('./test/node-api/test_instance_data/build/Release/test_ref_then_set.node');" ``` Thus, we unlink a reference precisely when we destroy it – in its destructor. Refs: #34731 Refs: #34839 Refs: #35620 Refs: #35777 Fixes: #35778 Signed-off-by: Gabriel Schulhof <gabriel.schulhof@intel.com> PR-URL: #35933 Reviewed-By: Rich Trott <rtrott@gmail.com> Reviewed-By: Michael Dawson <midawson@redhat.com> Reviewed-By: Zeyu Yang <himself65@outlook.com>
Currently, a reference is being unlinked from the list of references tracked by the environment when `v8impl::Reference::Delete` is called. This causes a leak when deletion must be deferred because the finalizer hasn't yet run, but the finalizer does not run because environment teardown is in progress, and so no more gc runs will happen, and the `FinalizeAll` run that happens during environment teardown does not catch the reference because it's no longer in the list. The test below will fail when running with ASAN: ``` ./node ./test/node-api/test_worker_terminate_finalization/test.js ``` OTOH if, to address the above leak, we make a special case to not unlink a reference during environment teardown, we run into a situation where the reference gets deleted by `v8impl::Reference::Delete` but does not get unlinked because it's environment teardown time. This leaves a stale pointer in the linked list which will result in a use-after-free in `FinalizeAll` during environment teardown. The test below will fail if we make the above change: ``` ./node -e "require('./test/node-api/test_instance_data/build/Release/test_ref_then_set.node');" ``` Thus, we unlink a reference precisely when we destroy it – in its destructor. Refs: #34731 Refs: #34839 Refs: #35620 Refs: #35777 Fixes: #35778 Signed-off-by: Gabriel Schulhof <gabriel.schulhof@intel.com> PR-URL: #35933 Reviewed-By: Rich Trott <rtrott@gmail.com> Reviewed-By: Michael Dawson <midawson@redhat.com> Reviewed-By: Zeyu Yang <himself65@outlook.com>
Currently, a reference is being unlinked from the list of references tracked by the environment when `v8impl::Reference::Delete` is called. This causes a leak when deletion must be deferred because the finalizer hasn't yet run, but the finalizer does not run because environment teardown is in progress, and so no more gc runs will happen, and the `FinalizeAll` run that happens during environment teardown does not catch the reference because it's no longer in the list. The test below will fail when running with ASAN: ``` ./node ./test/node-api/test_worker_terminate_finalization/test.js ``` OTOH if, to address the above leak, we make a special case to not unlink a reference during environment teardown, we run into a situation where the reference gets deleted by `v8impl::Reference::Delete` but does not get unlinked because it's environment teardown time. This leaves a stale pointer in the linked list which will result in a use-after-free in `FinalizeAll` during environment teardown. The test below will fail if we make the above change: ``` ./node -e "require('./test/node-api/test_instance_data/build/Release/test_ref_then_set.node');" ``` Thus, we unlink a reference precisely when we destroy it – in its destructor. Refs: #34731 Refs: #34839 Refs: #35620 Refs: #35777 Fixes: #35778 Signed-off-by: Gabriel Schulhof <gabriel.schulhof@intel.com> PR-URL: #35933 Reviewed-By: Rich Trott <rtrott@gmail.com> Reviewed-By: Michael Dawson <midawson@redhat.com> Reviewed-By: Zeyu Yang <himself65@outlook.com>
Currently, a reference is being unlinked from the list of references tracked by the environment when `v8impl::Reference::Delete` is called. This causes a leak when deletion must be deferred because the finalizer hasn't yet run, but the finalizer does not run because environment teardown is in progress, and so no more gc runs will happen, and the `FinalizeAll` run that happens during environment teardown does not catch the reference because it's no longer in the list. The test below will fail when running with ASAN: ``` ./node ./test/node-api/test_worker_terminate_finalization/test.js ``` OTOH if, to address the above leak, we make a special case to not unlink a reference during environment teardown, we run into a situation where the reference gets deleted by `v8impl::Reference::Delete` but does not get unlinked because it's environment teardown time. This leaves a stale pointer in the linked list which will result in a use-after-free in `FinalizeAll` during environment teardown. The test below will fail if we make the above change: ``` ./node -e "require('./test/node-api/test_instance_data/build/Release/test_ref_then_set.node');" ``` Thus, we unlink a reference precisely when we destroy it – in its destructor. Refs: #34731 Refs: #34839 Refs: #35620 Refs: #35777 Fixes: #35778 Signed-off-by: Gabriel Schulhof <gabriel.schulhof@intel.com> PR-URL: #35933 Reviewed-By: Rich Trott <rtrott@gmail.com> Reviewed-By: Michael Dawson <midawson@redhat.com> Reviewed-By: Zeyu Yang <himself65@outlook.com>
Currently, a reference is being unlinked from the list of references tracked by the environment when `v8impl::Reference::Delete` is called. This causes a leak when deletion must be deferred because the finalizer hasn't yet run, but the finalizer does not run because environment teardown is in progress, and so no more gc runs will happen, and the `FinalizeAll` run that happens during environment teardown does not catch the reference because it's no longer in the list. The test below will fail when running with ASAN: ``` ./node ./test/node-api/test_worker_terminate_finalization/test.js ``` OTOH if, to address the above leak, we make a special case to not unlink a reference during environment teardown, we run into a situation where the reference gets deleted by `v8impl::Reference::Delete` but does not get unlinked because it's environment teardown time. This leaves a stale pointer in the linked list which will result in a use-after-free in `FinalizeAll` during environment teardown. The test below will fail if we make the above change: ``` ./node -e "require('./test/node-api/test_instance_data/build/Release/test_ref_then_set.node');" ``` Thus, we unlink a reference precisely when we destroy it – in its destructor. Refs: #34731 Refs: #34839 Refs: #35620 Refs: #35777 Fixes: #35778 Signed-off-by: Gabriel Schulhof <gabriel.schulhof@intel.com> PR-URL: #35933 Reviewed-By: Rich Trott <rtrott@gmail.com> Reviewed-By: Michael Dawson <midawson@redhat.com> Reviewed-By: Zeyu Yang <himself65@outlook.com>
Currently, a reference is being unlinked from the list of references
tracked by the environment when
v8impl::Reference::Delete
is called.This causes a leak when deletion must be deferred because the finalizer
hasn't yet run, but the finalizer does not run because environment
teardown is in progress, and so no more gc runs will happen, and the
FinalizeAll
run that happens during environment teardown does notcatch the reference because it's no longer in the list. The test below
will fail when running with ASAN:
OTOH if, to address the above leak, we make a special case to not
unlink a reference during environment teardown, we run into a
situation where the reference gets deleted by
v8impl::Reference::Delete
but does not get unlinked because it'senvironment teardown time. This leaves a stale pointer in the linked
list which will result in a use-after-free in
FinalizeAll
duringenvironment teardown. The test below will fail if we make the above
change:
Thus, we unlink a reference precisely when we destroy it – in its
destructor.
Refs: #34731
Refs: #34839
Refs: #35620
Refs: #35777
Fixes: #35778
Signed-off-by: @gabrielschulhof
Checklist
make -j4 test
(UNIX), orvcbuild test
(Windows) passes