Skip to content

Embedder Crash at Check failed: node->IsInUse() from v20.12 #52418

@caoccao

Description

@caoccao

Version

v20.12.1

Platform

Windows x86_64, MacOS arm64

Subsystem

No response

What steps will reproduce the bug?

Project Javet embeds Node.js to JVM. It works well with v20.11.1. But when I upgraded Node.js to v20.12.0 or v20.12.1, it crashed at api/environment.cc L522:

void FreeEnvironment(Environment* env) {
//...
  delete env; // <-- Crash here
}

The stack trace is as follows.

```cpp
#
# Fatal error in , line 0
# Check failed: node->IsInUse().
#
#
#
#FailureMessage Object: 0x16f50ac38
----- Native stack trace -----

 1: 0x131d8435c node::NodePlatform::GetStackTracePrinter()::$_3::__invoke() [AAAA.dylib]
 2: 0x1319489d8 V8_Fatal(char const*, ...) [AAAA.dylib]
 3: 0x13063a460 v8::internal::GlobalHandles::NodeSpace<v8::internal::GlobalHandles::Node>::Release(v8::internal::GlobalHandles::Node*) [AAAA.dylib]
 4: 0x131ca2f2c node::Environment::~Environment() [AAAA.dylib]
 5: 0x131ca341c node::Environment::~Environment() [AAAA.dylib]
 6: 0x131c2db04 node::FreeEnvironment(node::Environment*) [AAAA.dylib]

The Release function is at deps/v8/src/handles/global-handles.cc and the source code is as follows.

template <class NodeType>
void GlobalHandles::NodeSpace<NodeType>::Free(NodeType* node) {
  CHECK(node->IsInUse()); // <-- Crash here
  node->Release(first_free_);
  first_free_ = node;
  BlockType* block = BlockType::From(node);
  if (block->DecreaseUsage()) {
    block->ListRemove(&first_used_block_);
  }
  global_handles_->isolate()->counters()->global_handles()->Decrement();
  handles_count_--;
}

I have no idea on what was changed at Node.js side causing a not-in-use node to be released by V8, because there is no code change at my side. The relevant Javet source code is at here in CloseV8Context() and CloseV8Isolate().

It crashed on both Windows x86_64 and MacOS arm64, and I suspect it crashes on all platforms.

How often does it reproduce? Is there a required condition?

It's consistent.

What is the expected behavior? Why is that the expected behavior?

It doesn't crash.

What do you see instead?

#
# Fatal error in , line 0
# Check failed: node->IsInUse().
#
#
#
#FailureMessage Object: 0x16f50ac38
----- Native stack trace -----

 1: 0x131d8435c node::NodePlatform::GetStackTracePrinter()::$_3::__invoke() [AAAA.dylib]
 2: 0x1319489d8 V8_Fatal(char const*, ...) [AAAA.dylib]
 3: 0x13063a460 v8::internal::GlobalHandles::NodeSpace<v8::internal::GlobalHandles::Node>::Release(v8::internal::GlobalHandles::Node*) [AAAA.dylib]
 4: 0x131ca2f2c node::Environment::~Environment() [AAAA.dylib]
 5: 0x131ca341c node::Environment::~Environment() [AAAA.dylib]
 6: 0x131c2db04 node::FreeEnvironment(node::Environment*) [AAAA.dylib]

Additional information

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    embeddingIssues and PRs related to embedding Node.js in another project.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions