DCHECK crash on !i_isolate->is_execution_terminating() #227
Description
Activity
Thanks for opening this. It also affect V8 10.3: nodejs/node#43195 (comment)
Sorry for the inconvenience here :/.
I think V8 has been a bit too lenient on this in the past (and it led to a bunch of issues within chrome).
The general idea is really that you don't use V8 anymore after marking it for termination, and I'm aware of how painful it can be to track down those issues.I think having simple accessors still available would make sense (and it might well be that I totally missed a use case present in node).
Example in CI: https://ci.nodejs.org/job/node-test-commit-arm-debug/2497/nodes=ubuntu1804-arm64/
Problematic code: https://github.com/nodejs/node/blob/6ac55fa337b57cecf36602d0acc3da25ee82a589/src/env-inl.h#L222-L237
/cc @nodejs/async_hooks
Adding
if (env()->can_call_into_js()) {around this code solves the async hooks problem but it seems there are other similar places where JS code is called but no longer allowed.Adding
if (env()->can_call_into_js()) {around this code solves the async hooks problemI’m not sure what else to do besides doing this and being consistent about this.
Problem seems to be the perform_stopping_check() lambda in callback.cc Close method. It tries to clean up async_hooks reactively to the env stopping, but at that point it's no longer safe to create the HandleScope for setting the length field on js_execution_async_resources_. If the env is already in shutdown, it should be safe to just skip that though. 🤔
I suspect we're going to need to just play that game of whack-a-mole to get any of those post-shutdown stuff filtered out.
Alright - i can spin up a PR for that soon then!
Reacted by Michaël Zasso, Stephen Belanger and Tony GorezReacted by Michaël Zasso, Matteo Collina, Stephen Belanger, Charles Kerr and Tony GorezHey 👋
I tried to reproduce the bug, but I struggled a bit as I'm fairly new to the codebase.
I have two questions:
- Should we checkout a specific branch to reproduce it? (like
targos:v8-103) - How could we run a single test file like
parallel/test-worker-esm-exit? The documentation points outmake jstestbut it executes all the tests. Maybe I miss it somewhere?
- Should we checkout a specific branch to reproduce it? (like
@tony-go tests can be run as a rule with just the node executable, so
out/Debug/node /path/to/test/file. If you do want to use the test runner, you can also just dopython3 tools/test.py test/parallel/test-worker-esm-exit.js(i personally prefer using the runner since it allows for much more customization)Reacted by Tony GorezThanks, @codebytere 🙌
Finally found this: https://github.com/nodejs/node/blob/main/BUILDING.md#running-tests
@Flarna hmm - that's strange since theres a
can_call_into_js()immediately prior: https://github.com/nodejs/node/blob/6932fb8bac3a4caf3f3fabee0a595a077f477f63/src/api/callback.cc#L103There's a bunch of places within that function that the state can transition though, which is why it checks it several times. Probably another place it needs a check now or something...it's a complicated bit of code. 😐
@codebytere It's a while that I had this in my debugger so can't remember in detail. But as far as I remmeber it's as @Qard said the state changes after that check you refer to.
I know the microtask queue bits change it briefly. Forget if there were other cases, but basically these callback scopes can end up nested within each other and that can have some unexpected side effects if not handled carefully.
11 remaining items
Here's the latest canary CI run in debug mode (green): https://ci.nodejs.org/job/node-test-commit-arm-debug/4183/nodes=ubuntu1804-arm64/
Maybe these crashes are only reproducible within Electron?
- added 3 commits that reference this issue
on Sep 26, 2022 Looks like it 🤔 at least, it looks like it's specific to embedded Node.js and i haven't been able to repro it on your canary branch
Tracked it down to https://github.com/electron/node/blob/3e6b3b22c5f687e170944a1cef51caa41a4caea1/src/node_task_queue.cc#L142-L143 - it's causing this error:
# # Fatal error in ../../v8/src/execution/microtask-queue.cc, line 182 # Debug check failed: maybe_result.is_null(). # # # #FailureMessage Object: 0x16d4f8b48 1: 0x11e947804 node::NodePlatform::GetStackTracePrinter()::$_3::__invoke() [/Users/codebytere/Developer/electron-gn/src/out/Testing/Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Electron Framework] 2: 0x11b8bbb74 V8_Fatal(char const*, int, char const*, ...) [/Users/codebytere/Developer/electron-gn/src/out/Testing/Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Electron Framework] 3: 0x11b8bb818 std::Cr::enable_if<!std::is_function<std::Cr::remove_pointer<unsigned char>::type>::value && !std::is_enum<unsigned char>::value && has_output_operator<unsigned char, v8::base::CheckMessageStream>::value, std::Cr::basic_string<char, std::Cr::char_traits<char>, std::Cr::allocator<char>>>::type v8::base::PrintCheckOperand<unsigned char>(unsigned char) [/Users/codebytere/Developer/electron-gn/src/out/Testing/Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Electron Framework] 4: 0x117ccfad4 v8::internal::MicrotaskQueue::RunMicrotasks(v8::internal::Isolate*) [/Users/codebytere/Developer/electron-gn/src/out/Testing/Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Electron Framework] 5: 0x117ccf414 v8::internal::MicrotaskQueue::PerformCheckpointInternal(v8::Isolate*) [/Users/codebytere/Developer/electron-gn/src/out/Testing/Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Electron Framework] 6: 0x11e8b4b14 node::loader::ModuleWrap::Evaluate(v8::FunctionCallbackInfo<v8::Value> const&) [/Users/codebytere/Developer/electron-gn/src/out/Testing/Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Electron Framework] 7: 0x117a45bd0 v8::internal::FunctionCallbackArguments::Call(v8::internal::CallHandlerInfo) [/Users/codebytere/Developer/electron-gn/src/out/Testing/Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Electron Framework] 8: 0x117a443e0 v8::internal::MaybeHandle<v8::internal::Object> v8::internal::(anonymous namespace)::HandleApiCallHelper<false>(v8::internal::Isolate*, v8::internal::Handle<v8::internal::HeapObject>, v8::internal::Handle<v8::internal::FunctionTemplateInfo>, v8::internal::Handle<v8::internal::Object>, unsigned long*, int) [/Users/codebytere/Developer/electron-gn/src/out/Testing/Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Electron Framework] 9: 0x117a42754 v8::internal::Builtin_Impl_HandleApiCall(v8::internal::BuiltinArguments, v8::internal::Isolate*) [/Users/codebytere/Developer/electron-gn/src/out/Testing/Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Electron Framework] 10: 0x117a420d4 v8::internal::Builtin_HandleApiCall(int, unsigned long*, v8::internal::Isolate*) [/Users/codebytere/Developer/electron-gn/src/out/Testing/Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Electron Framework] 11: 0x12407ea510c 12: 0x12407e0fbe4 13: 0x12407e0fbe4 14: 0x12407e4b3a0 15: 0x12407f13a28 16: 0x12407e39024 17: 0x12407e0d7e8 18: 0x117c85224 v8::internal::(anonymous namespace)::Invoke(v8::internal::Isolate*, v8::internal::(anonymous namespace)::InvokeParams const&) [/Users/codebytere/Developer/electron-gn/src/out/Testing/Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Electron Framework] 19: 0x117c8673c v8::internal::(anonymous namespace)::InvokeWithTryCatch(v8::internal::Isolate*, v8::internal::(anonymous namespace)::InvokeParams const&) [/Users/codebytere/Developer/electron-gn/src/out/Testing/Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Electron Framework] 20: 0x117c86e28 v8::internal::Execution::TryRunMicrotasks(v8::internal::Isolate*, v8::internal::MicrotaskQueue*) [/Users/codebytere/Developer/electron-gn/src/out/Testing/Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Electron Framework] 21: 0x117ccf6b0 v8::internal::MicrotaskQueue::RunMicrotasks(v8::internal::Isolate*) [/Users/codebytere/Developer/electron-gn/src/out/Testing/Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Electron Framework] 22: 0x117ccf414 v8::internal::MicrotaskQueue::PerformCheckpointInternal(v8::Isolate*) [/Users/codebytere/Developer/electron-gn/src/out/Testing/Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Electron Framework] 23: 0x117a45bd0 v8::internal::FunctionCallbackArguments::Call(v8::internal::CallHandlerInfo) [/Users/codebytere/Developer/electron-gn/src/out/Testing/Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Electron Framework] 24: 0x117a443e0 v8::internal::MaybeHandle<v8::internal::Object> v8::internal::(anonymous namespace)::HandleApiCallHelper<false>(v8::internal::Isolate*, v8::internal::Handle<v8::internal::HeapObject>, v8::internal::Handle<v8::internal::FunctionTemplateInfo>, v8::internal::Handle<v8::internal::Object>, unsigned long*, int) [/Users/codebytere/Developer/electron-gn/src/out/Testing/Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Electron Framework] 25: 0x117a42754 v8::internal::Builtin_Impl_HandleApiCall(v8::internal::BuiltinArguments, v8::internal::Isolate*) [/Users/codebytere/Developer/electron-gn/src/out/Testing/Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Electron Framework] 26: 0x117a420d4 v8::internal::Builtin_HandleApiCall(int, unsigned long*, v8::internal::Isolate*) [/Users/codebytere/Developer/electron-gn/src/out/Testing/Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Electron Framework] 27: 0x12407ea510c 28: 0x12407e0fbe4 29: 0x12407e0d90c 30: 0x12407e0d5a8 31: 0x117c851d8 v8::internal::(anonymous namespace)::Invoke(v8::internal::Isolate*, v8::internal::(anonymous namespace)::InvokeParams const&) [/Users/codebytere/Developer/electron-gn/src/out/Testing/Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Electron Framework] 32: 0x117c842e0 v8::internal::Execution::Call(v8::internal::Isolate*, v8::internal::Handle<v8::internal::Object>, v8::internal::Handle<v8::internal::Object>, int, v8::internal::Handle<v8::internal::Object>*) [/Users/codebytere/Developer/electron-gn/src/out/Testing/Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Electron Framework] 33: 0x11798f3c0 v8::Function::Call(v8::Local<v8::Context>, v8::Local<v8::Value>, int, v8::Local<v8::Value>*) [/Users/codebytere/Developer/electron-gn/src/out/Testing/Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Electron Framework] 34: 0x11e84f554 node::InternalCallbackScope::Close() [/Users/codebytere/Developer/electron-gn/src/out/Testing/Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Electron Framework] 35: 0x11e84f1ac node::InternalCallbackScope::~InternalCallbackScope() [/Users/codebytere/Developer/electron-gn/src/out/Testing/Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Electron Framework] 36: 0x11e88f7ec node::StartExecution(node::Environment*, std::Cr::function<v8::MaybeLocal<v8::Value> (node::StartExecutionCallbackInfo const&)>) [/Users/codebytere/Developer/electron-gn/src/out/Testing/Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Electron Framework] 37: 0x11e8514a4 node::LoadEnvironment(node::Environment*, std::Cr::function<v8::MaybeLocal<v8::Value> (node::StartExecutionCallbackInfo const&)>) [/Users/codebytere/Developer/electron-gn/src/out/Testing/Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Electron Framework] 38: 0x11673ffd0 electron::NodeMain(int, char**) [/Users/codebytere/Developer/electron-gn/src/out/Testing/Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Electron Framework] 39: 0x116566e1c ElectronInitializeICUandStartNode [/Users/codebytere/Developer/electron-gn/src/out/Testing/Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Electron Framework] 40: 0x102ca5088 Command: /Users/codebytere/Developer/electron-gn/src/out/Testing/Electron.app/Contents/MacOS/Electron --experimental-vm-modules /Users/codebytere/Developer/electron-gn/src/third_party/electron_node/test/sequential/test-vm-timeout-escape-promise-module-2.js --- CRASHED (Signal: 5) ---@santigimeno i determined it's related to
v8::Isolate::SafeForTerminationScope, which i think is missing somewhere for nested microtasks. Electron starts Node.js withonly_terminate_in_safe_scopeset totrue, which triggers this error after https://chromium-review.googlesource.com/c/chromium/src/+/3620285also cc @addaleax since this appears specific to timeouts with
microtaskMode: 'afterEvaluate'and i also see you added nodejs/node#36344 to handle SIGINT interruptions. Any pointers would be appreciated 🙇🏻♀️- added 2 commits that reference this issue
on Jan 3, 2023
https://chromium-review.googlesource.com/c/v8/v8/+/3620285
was merged recently and causes a ton of failures in a variety of tests (~50 or so,
parallel/test-worker-esm-exitas an example):I initially attempted to fix by adding in early returns in various places:
but it ended up being a bit of a whac-a-mole game with new ones appearing with every early return I added so i'm not sure what the best approach is.
cc @targos and @camillobruni since you opened the CL :)