Repository navigation
Check failed: result.second #32463
Description
Activity
Pulling this out into a separate issue for visibility.
@ronag do you have links to the failing runs? If we can isolate when it started happening it might help work out what caused it.
https://ci.nodejs.org/job/node-test-commit-plinux/31722/
Might be flaky. I did see it in another PR as well but can't find it at the moment.
I'm seeing this in Node 14.1.0 if I create two
Buffers (usingNapi::Buffer<uint8_t>::New) pointing to the same memory (stack trace below). I'm guessing this trips theCHECKinbacking-store.ccbecause the address is already inmap_.
Allocating two external buffers pointing to the same address used to work. Is the change in behaviour expected?# # Fatal error in , line 0 # Check failed: result.second. # # # #FailureMessage Object: 0x7ffc13226770 1: 0x55f12e563285 [/home/david/node/out/Release/node] 2: 0x55f12f57d916 V8_Fatal(char const*, ...) [/home/david/node/out/Release/node] 3: 0x55f12e99b485 v8::internal::GlobalBackingStoreRegistry::Register(std::shared_ptr<v8::internal::BackingStore>) [/home/david/node/out/Release/node] 4: 0x55f12e6bd967 v8::ArrayBuffer::GetBackingStore() [/home/david/node/out/Release/node] 5: 0x55f12e4c4cbb node::Buffer::New(node::Environment*, char*, unsigned long, void (*)(char*, void*), void*) [/home/david/node/out/Release/node] 6: 0x55f12e4c4fa2 node::Buffer::New(v8::Isolate*, char*, unsigned long, void (*)(char*, void*), void*) [/home/david/node/out/Release/node] 7: 0x55f12e4b743e napi_create_external_buffer [/home/david/node/out/Release/node] 8: 0x7f61c8d4e062 Napi::Buffer<unsigned char>::New(napi_env__*, unsigned char*, unsigned long) [/home/david/shared-memory-disruptor/build/Debug/disruptor.node] 9: 0x7f61c8d4d2be Napi::Buffer<unsigned char> Disruptor::ProduceClaimSync<Napi::Buffer>(Napi::Env const&, bool, unsigned long&, unsigned long&) [/home/david/shared-memory-disruptor/build/Debug/disruptor.node] 10: 0x7f61c8d4565e Disruptor::ProduceClaim(Napi::CallbackInfo const&) [/home/david/shared-memory-disruptor/build/Debug/disruptor.node] 11: 0x7f61c8d4f49d Napi::ObjectWrap<Disruptor>::InstanceMethodCallbackWrapper(napi_env__*, napi_callback_info__*)::{lambda()#1}::operator()() const [/home/david/shared-memory-disruptor/build/Debug/disruptor.node] 12: 0x7f61c8d50c02 napi_value__* Napi::details::WrapCallback<Napi::ObjectWrap<Disruptor>::InstanceMethodCallbackWrapper(napi_env__*, napi_callback_info__*)::{lambda()#1}>(Napi::ObjectWrap<Disruptor>::InstanceMethodCallbackWrapper(napi_env__*, napi_callback_info__*)::{lambda()#1}) [/home/david/shared-memory-disruptor/build/Debug/disruptor.node] 13: 0x7f61c8d4f535 Napi::ObjectWrap<Disruptor>::InstanceMethodCallbackWrapper(napi_env__*, napi_callback_info__*) [/home/david/shared-memory-disruptor/build/Debug/disruptor.node] 14: 0x55f12e49a9d8 [/home/david/node/out/Release/node] 15: 0x55f12e6f6d3f v8::internal::FunctionCallbackArguments::Call(v8::internal::CallHandlerInfo) [/home/david/node/out/Release/node] 16: 0x55f12e6f7100 [/home/david/node/out/Release/node] 17: 0x55f12e6f799a [/home/david/node/out/Release/node] 18: 0x55f12e6f824a v8::internal::Builtin_HandleApiCall(int, unsigned long*, v8::internal::Isolate*) [/home/david/node/out/Release/node] 19: 0x55f12ef766b9 [/home/david/node/out/Release/node]I guess this change is intended: https://monorail-prod.appspot.com/p/v8/issues/detail?id=9908
I'll try to work around it in my addons.
Here are a couple of downstream issues from native modules that have been impacted by this:
- ffi-napi 2.5.0 crashes on Node 14 on macOS 10.15.4 node-ffi-napi/node-ffi-napi#71
- "Check failed: result.second" in Node 14.1 via Sharp 0.24 lovell/sharp#2196
(Anecdotally I've heard https://github.com/grpc/grpc-node is also affected, but the only issue I can find that mentions it is pulumi/pulumi#4258 (comment) .)
Suggestions for a straightforward fix or workaround for this breaking change would be greatly appreciated.
Reacted by Simon TrigonaI have experienced issues with grpc-node as well in some early tests of node 14. I haven't circled back to gather enough info to submit an issue to the project.
/cc @addaleax
My addon has a fixed memory range so I'm able to work around this issue by making a single buffer and then calling
Buffer#slicewhen I need to return a view onto it.
Wouldn't work for addons which dynamically allocate memory though - I guess you could keep track of what you've allocated previously and use finalizers to determine when and when not to return the same object.I'm having serious issues with this. I spent a while trying to debug it and I can't seem to figure it out. I've audited my code thoroughly and concluded that it does not pass live duplicate pointers into
napi_create_external_buffer. I've also valgrinded it to ensure nothing funky is happening memory-wise.From what I can guess this is happening:
- Addon code allocates pointer P via
malloc. - P is passed into
napi_create_external_bufferwith a finalization callback which callsfree(P). P is inserted into v8's global array buffer table for tracking. - The finalization callback is executed on GC. P is freed and returned to the allocator. P is not yet removed from v8's global array buffer table.
- Addon code attempts to allocate memory once again. The allocator returns P, as it is now available.
- P is passed into
napi_create_external_buffer. P still has not been removed from the v8 global array buffer table. - The world ends with
Check failed: result.second.
Step 3 seems to be the issue (again, this is just my guess at what is happening). It's been difficult trying to isolate this as it appears to be a "now you see it, now you don't" type of issue. I've come up with an offensively slow workaround. I don't consider it acceptable performance-wise.
Reacted by Anna Henningsen, Jon Knapp, Dmitriy and Erik De Rijcke- Addon code allocates pointer P via
@chjj Yeah, we’ve been having a lot of trouble with this, too. This isn’t quite trivial to fix, because the API contracts for
napi_create_external_bufferand the V8BackingStorearen’t the same – you can’t run JS from theBackingStoredeleter callback or necessarily even be sure on which thread it runs, but you can do that from the Node.js/N-APIBufferfree callback.I’ll try to change the behavior here by making the
Bufferfree callback only fire once theBackingStoredeleter runs, by posting a task back to the JS thread, but that’s not necessarily trivial either.(It’s unfortunate that we have a
BufferAPI in N-API at all, tbh. But that’s a mistake we can’t undo now.)@addaleax, thanks for the response.
I’ll try to change the behavior here by making the Buffer free callback only fire once the BackingStore deleter runs, by posting a task back to the JS thread, but that’s not necessarily trivial either.
I see. Now that I'm understanding the issue more, I suppose the alternative would be to allow the programmer to pass two finalize callbacks: one for JS stuff, one for non-JS stuff which would execute atomically with the BackingStore deletion. That seems pretty ugly though and probably not possible to implement at this point.
(It’s unfortunate that we have a Buffer API in N-API at all, tbh. But that’s a mistake we can’t undo now.)
Would
napi_create_external_arraybuffernot have this issue? Based on what you said above, I assumed it would.I'm going through my code now and considering how to rewrite all of this.
(It’s unfortunate that we have a Buffer API in N-API at all, tbh. But that’s a mistake we can’t undo now.)
Would
napi_create_external_arraybuffernot have this issue? Based on what you said above, I assumed it would.It does, unfortunately – for the same reason as the
Buffervariant, its API contract precedes the V8 changes here. I’ll try to implement the solution from above, and see how far I’ll get with that.- addedbufferIssues and PRs related to the buffer subsystem.Issues and PRs related to the buffer subsystem.flaky-testIssues and PRs involving tests that fail intermittently in CI.Issues and PRs involving tests that fail intermittently in CI.node-apiIssues and PRs related to Node-API.Issues and PRs related to Node-API.
on May 9, 2020 9 remaining items
The latest v14.15.0 still produces the same error. I'm doing simple buffer construction without "pointing two buffers to the same native address", and still get the error.
The code roughly looks like this:
color_image_data = (uint8_t *)malloc(data_length); memcpy(color_image_data, image_data_from_device, data_length); Napi::Buffer<uint8_t> color_image_buffer = Napi::Buffer<uint8_t>::New(env, color_image_data, data_length);
I feel like this is what @chjj talked in #32463 (comment).
Edit
I finally figured out my problem was that
image_data_from_deviceis probably already freed. Since I'm doingNapi::ThreadSafeFunctioninside a loop,image_data_from_deviceis very likely to have been destructed when accessed inside the thread.Napi::Buffermay have been repeatedly initialized using the same nonsense pointer and hence the error. So it is indeed "pointing two buffers to the same native address".- added a commit that references this issue
on Aug 7, 2021 @addaleax should we reopen it since it doesn't actually be fixed.
Reacted by Hetchet, Luis Aleman, Andrew Schmadel, Rod, somanuell and Towry Wang@Brooooooklyn Can you provide more context than this?
We're seeing this on Node 16.15.0 while running tests with Ava.
Reacted by Jonah Snider, Chris, Rod, ash, Joe Harvey, somanuell, Matt Turner, Mat, Nils, vudanghd and 4 moreGetting this in Node v16.14.0 several times
Reacted by Towry WangReacted by Towry WangI got same issue in Node v16.15.1 when I run tests with Vitest.
# Fatal error in , line 0 # Check failed: result.second. # # # #FailureMessage Object: 0000002046CFB340 1: 00007FF7F1B879CF v8::internal::CodeObjectRegistry::~CodeObjectRegistry+114207 2: 00007FF7F1AA3E9F std::basic_ostream<char,std::char_traits<char> >::operator<<+65103 3: 00007FF7F27826C2 V8_Fatal+162 4: 00007FF7F21EDA3D v8::internal::BackingStore::Reallocate+637 5: 00007FF7F24371B9 v8::ArrayBuffer::GetBackingStore+137 6: 00007FF7F1B367EA node::Buffer::Data+58 7: 00007FF7F1B0AC5C DSA_meth_get_flags+19404 8: 00007FF7F2405BC6 v8::internal::Builtins::code_handle+172790 9: 00007FF7F24057B9 v8::internal::Builtins::code_handle+171753 10: 00007FF7F2405A7C v8::internal::Builtins::code_handle+172460 11: 00007FF7F24058E0 v8::internal::Builtins::code_handle+172048 12: 00007FF7F24D8FE1 v8::internal::SetupIsolateDelegate::SetupHeap+494673 13: 000001DFF0D54323Reacted by Jack Asher, Arina Shilyaeva, Žilvinas, Brody Dingel, Simona , Kevin O., Peter Skinner and Aislinn HayesReacted by vudanghd, Jan Beckmann, stuartch3n, Oleksii Bilan, Felipe Vasconcelos, Ben, Towry Wang and Peter Skinner@Ram4GB Can you open a new issue and link back to this one? It's not clear whether this is in fact the same issue or just the same error message.
By the way, the stack trace is bogus (common problem on Windows.) It'd be helpful if you could test on Linux or macOS, where the stack trace is reliable.
@bnoordhuis not sure if this helps but rolling back to node v16.13.2 has stopped these intermittent fatal errors on my system (MacBook Pro M1).
Reacted by Lê Minh Cường and Jeff SeeFWIW, I can still reproduce the issue with Node v16.13.2.
Reacted by Rod, Vasyl Moskalov, wbzqe, uriesk and Towry Wang- added a commit that references this issue
on Feb 3, 2023 - added a commit that references this issue
on May 12, 2025 - added a commit that references this issue
on Nov 24, 2025 - added a commit that references this issue
on Jul 27, 2026
Not sure why you pinged build here as that's a code problem (failing check). From the stack trace and previously (#31061) that check is to with arraybuffers and backing stores. If it's occurring in multiple PR's that would suggest something has landed on master that has regressed.
Originally posted by @richardlau in #32414 (comment)