-
Notifications
You must be signed in to change notification settings - Fork 29.8k
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
node-api: avoid SecondPassCallback crash #38899
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -321,7 +321,8 @@ class Reference : public RefBase { | |
Reference(napi_env env, v8::Local<v8::Value> value, Args&&... args) | ||
: RefBase(env, std::forward<Args>(args)...), | ||
_persistent(env->isolate, value), | ||
_secondPassParameter(new SecondPassCallParameterRef(this)) { | ||
_secondPassParameter(new SecondPassCallParameterRef(this)), | ||
_secondPassScheduled(false) { | ||
if (RefCount() == 0) { | ||
SetWeak(); | ||
} | ||
|
@@ -348,7 +349,7 @@ class Reference : public RefBase { | |
// If the second pass callback is scheduled, it will delete the | ||
// parameter passed to it, otherwise it will never be scheduled | ||
// and we need to delete it here. | ||
if (_secondPassParameter != nullptr) { | ||
if (!_secondPassScheduled) { | ||
delete _secondPassParameter; | ||
} | ||
} | ||
|
@@ -445,8 +446,7 @@ class Reference : public RefBase { | |
reference->_persistent.Reset(); | ||
// Mark the parameter not delete-able until the second pass callback is | ||
// invoked. | ||
reference->_secondPassParameter = nullptr; | ||
|
||
reference->_secondPassScheduled = true; | ||
data.SetSecondPassCallback(SecondPassCallback); | ||
} | ||
|
||
|
@@ -468,12 +468,14 @@ class Reference : public RefBase { | |
// the reference itself has already been deleted so nothing to do | ||
return; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is this branch that early breaks from the SecondPassCallback. However, it seems that we did fail to reach to this branch. |
||
} | ||
reference->_secondPassParameter = nullptr; | ||
reference->Finalize(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. IIUC, the problem happens here as the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @legendecas see comment above which explains how the fix addresses the issue. |
||
} | ||
|
||
bool env_teardown_finalize_started_ = false; | ||
v8impl::Persistent<v8::Value> _persistent; | ||
SecondPassCallParameterRef* _secondPassParameter; | ||
bool _secondPassScheduled; | ||
}; | ||
|
||
enum UnwrapAction { | ||
|
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.
@legendecas removing this is the line and using the boolean flag instead is what resolves the issue. The with this line is that it sets the reference->_secondPassParameter to nullptr which means that when we later try to clear what it points to its null and we con't actually clear it.
Putting that in another way the old flow was
-> set reference->_secondPassParameter to nullptr
-> schedule second pass callback
-> start env teardown and decide we want to try to cancel the Finalization in the second pass callback. To do that we need reference->_secondPassParameter but it has already been set to null so we do nothing....
-> the second pass callback still runs Finalization even though it should have been aborted.
This patch avoids setting reference->_secondPassParameter to null too early.
->
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.
Thanks for your explanation. IIUC, This line transfers the ownership of secondPassParameter to the second pass callback, but didn't transfer the ownership of the content of secondPassParameter (i.e. the
v8impl::Reference
) to the callback. In that sense, I'm afraid I didn't get the point how the change clears the content of secondPassParameter on the env teardown to prevent second pass callback to finalize.