Skip to content

Commit e23c04f

Browse files
mhdawsonrichardlau
authored andcommitted
node-api: avoid SecondPassCallback crash
PR #38000 added indirection so that we could stop finalization in cases where it had been scheduled in a second pass callback but we were doing it in advance in environment teardown. Unforunately we missed that the code which tries to clear the second pass parameter checked if the pointer to the parameter (_secondPassParameter) was nullptr and that when the second pass callback was scheduled we set _secondPassParameter to nullptr in order to avoid it being deleted outside of the second pass callback. The net result was that we would not clear the _secondPassParameter contents and failed to avoid the Finalization in the second pass callback. This PR adds an additional boolean for deciding if the secondPassParameter should be deleted outside of the second pass callback instead of setting secondPassParameter to nullptr thus avoiding the conflict between the 2 ways it was being used. See the discussion starting at: #38273 (comment) for how this was discovered on OSX while trying to upgrade to a new V8 version. Signed-off-by: Michael Dawson <[email protected]> PR-URL: #38899 Backport-PR-URL: #42512 Reviewed-By: Chengzhong Wu <[email protected]> Reviewed-By: James M Snell <[email protected]>
1 parent a7224c9 commit e23c04f

File tree

1 file changed

+6
-4
lines changed

1 file changed

+6
-4
lines changed

src/js_native_api_v8.cc

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -320,7 +320,8 @@ class Reference : public RefBase {
320320
Reference(napi_env env, v8::Local<v8::Value> value, Args&&... args)
321321
: RefBase(env, std::forward<Args>(args)...),
322322
_persistent(env->isolate, value),
323-
_secondPassParameter(new SecondPassCallParameterRef(this)) {
323+
_secondPassParameter(new SecondPassCallParameterRef(this)),
324+
_secondPassScheduled(false) {
324325
if (RefCount() == 0) {
325326
SetWeak();
326327
}
@@ -347,7 +348,7 @@ class Reference : public RefBase {
347348
// If the second pass callback is scheduled, it will delete the
348349
// parameter passed to it, otherwise it will never be scheduled
349350
// and we need to delete it here.
350-
if (_secondPassParameter != nullptr) {
351+
if (!_secondPassScheduled) {
351352
delete _secondPassParameter;
352353
}
353354
}
@@ -444,8 +445,7 @@ class Reference : public RefBase {
444445
reference->_persistent.Reset();
445446
// Mark the parameter not delete-able until the second pass callback is
446447
// invoked.
447-
reference->_secondPassParameter = nullptr;
448-
448+
reference->_secondPassScheduled = true;
449449
data.SetSecondPassCallback(SecondPassCallback);
450450
}
451451

@@ -467,12 +467,14 @@ class Reference : public RefBase {
467467
// the reference itself has already been deleted so nothing to do
468468
return;
469469
}
470+
reference->_secondPassParameter = nullptr;
470471
reference->Finalize();
471472
}
472473

473474
bool env_teardown_finalize_started_ = false;
474475
v8impl::Persistent<v8::Value> _persistent;
475476
SecondPassCallParameterRef* _secondPassParameter;
477+
bool _secondPassScheduled;
476478
};
477479

478480
class ArrayBufferReference final : public Reference {

0 commit comments

Comments
 (0)