Skip to content

Throwing JS error asynchronously crashes while building snapshots because of async hook stack corruption #48676

@RaisinTen

Description

@RaisinTen

Version

v20.4.0

Platform

Darwin Darshans-MacBook-Pro.local 22.4.0 Darwin Kernel Version 22.4.0: Mon Mar 6 21:00:17 PST 2023; root:xnu-8796.101.5~3/RELEASE_X86_64 x86_64

Subsystem

snapshot

What steps will reproduce the bug?

Building a snapshot from this script causes a crash.

snapshot.js

setTimeout(() => {
  throw new Error('lol');
}, 1000);

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

Always.

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

No crashes. I would expect it to throw the JS error similar to how running the script normally throws:

$ node snapshot.js
/tmp/snapshot.js:2
  throw new Error('lol');
  ^

Error: lol
    at Timeout._onTimeout (/tmp/snapshot.js:2:9)
    at listOnTimeout (node:internal/timers:573:17)
    at process.processTimers (node:internal/timers:514:7)

Node.js v20.4.0

What do you see instead?

Building the snapshot crashes like this:

$ node --snapshot-blob snapshot.blob --build-snapshot snapshot.js
/tmp/snapshot.js:21: Uncaught Error: lol
Error: async hook stack has become corrupted (actual: 2, expected: 0)
 1: 0x104ae52c8 node::AsyncHooks::FailWithCorruptedAsyncStack(double) [/usr/local/bin/node]
 2: 0x104ae5224 node::AsyncHooks::pop_async_context(double) [/usr/local/bin/node]
 3: 0x104a97b9d node::InternalCallbackScope::Close() [/usr/local/bin/node]
 4: 0x104a977de node::InternalCallbackScope::~InternalCallbackScope() [/usr/local/bin/node]
 5: 0x104b1bd9b node::Environment::RunTimers(uv_timer_s*) [/usr/local/bin/node]
 6: 0x10568ca06 uv__run_timers [/usr/local/bin/node]
 7: 0x105690971 uv_run [/usr/local/bin/node]
 8: 0x104a98753 node::SpinEventLoopInternal(node::Environment*) [/usr/local/bin/node]
 9: 0x104c17c4f node::SnapshotBuilder::Generate(node::SnapshotData*, std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>>> const&, std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>>> const&, std::__1::optional<std::__1::basic_string_view<char, std::__1::char_traits<char>>>) [/usr/local/bin/node]
10: 0x104b42eb6 node::GenerateAndWriteSnapshotData(node::SnapshotData const**, node::InitializationResultImpl const*) [/usr/local/bin/node]
11: 0x104b43569 node::Start(int, char**) [/usr/local/bin/node]
12: 0x7ff80cf0a41f start [/usr/lib/dyld]

Crash site -

node/src/env.cc

Lines 133 to 138 in b5e16ad

// Ask for the async_id to be restored as a check that the stack
// hasn't been corrupted.
if (UNLIKELY(fields_[kCheck] > 0 &&
async_id_fields_[kExecutionAsyncId] != async_id)) {
FailWithCorruptedAsyncStack(async_id);
}

Additional information

cc @joyeecheung

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions