-
Notifications
You must be signed in to change notification settings - Fork 29.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Check failed: result.second #32463
Comments
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
|
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:
(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. |
I 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 |
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 From what I can guess this is happening:
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. |
@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 I’ll try to change the behavior here by making the (It’s unfortunate that we have a |
@addaleax, thanks for the response.
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.
Would I'm going through my code now and considering how to rewrite all of this. |
It does, unfortunately – for the same reason as the |
Release `Buffer` and `ArrayBuffer` instances that were created through our addon APIs and have finalizers attached to them only after V8 has called the deleter callback passed to the `BackingStore`, instead of relying on our own GC callback(s). This fixes the following race condition: 1. Addon code allocates pointer P via `malloc`. 2. P is passed into `napi_create_external_buffer` with a finalization callback which calls `free(P)`. P is inserted into V8’s global array buffer table for tracking. 3. 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. (!) 4. Addon code attempts to allocate memory once again. The allocator returns P, as it is now available. 5. P is passed into `napi_create_external_buffer`. P still has not been removed from the v8 global array buffer table. 6. The world ends with `Check failed: result.second`. Since our API contract is to call the finalizer on the JS thread on which the `ArrayBuffer` was created, but V8 may call the `BackingStore` deleter callback on another thread, fixing this requires posting a task back to the JS thread. Refs: nodejs#32463 (comment) Fixes: nodejs#32463
Release `Buffer` and `ArrayBuffer` instances that were created through our addon APIs and have finalizers attached to them only after V8 has called the deleter callback passed to the `BackingStore`, instead of relying on our own GC callback(s). This fixes the following race condition: 1. Addon code allocates pointer P via `malloc`. 2. P is passed into `napi_create_external_buffer` with a finalization callback which calls `free(P)`. P is inserted into V8’s global array buffer table for tracking. 3. 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. (!) 4. Addon code attempts to allocate memory once again. The allocator returns P, as it is now available. 5. P is passed into `napi_create_external_buffer`. P still has not been removed from the v8 global array buffer table. 6. The world ends with `Check failed: result.second`. Since our API contract is to call the finalizer on the JS thread on which the `ArrayBuffer` was created, but V8 may call the `BackingStore` deleter callback on another thread, fixing this requires posting a task back to the JS thread. Refs: #32463 (comment) Fixes: #32463 PR-URL: #33321 Reviewed-By: James M Snell <jasnell@gmail.com>
Except for the race condition, so, with node 14.x (also the 14.3 that implements the fix), it's no (more?) correct to have multiple create_node_buffer pointing at the same c buffer? I'm using a pool of frames for decoding and I used to create a new node buffer for every frame (not caring if the source frame was already used in another buffer). Something like:
|
Yes – it’s unfortunate but it’s what it is.
Well, that’s what I ended up doing – it’s not great, but it works. You’ll want to make sure that |
I ran into a problem keeping track of weak references to buffers, which I need because I hand them out to the Javascript app and let them be garbage collected. |
@davedoesdev thanks for showing your implementation, I wonder how does it work with LTS (or older) node, where there is no guarantee of the release order of the backingstore. |
@addaleax should we reopen it since it doesn't actually be fixed. |
@Brooooooklyn Can you provide more context than this? |
We're seeing this on Node 16.15.0 while running tests with Ava. |
Getting this in Node v16.14.0 several times |
I got same issue in Node v16.15.1 when I run tests with Vitest.
|
@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). |
FWIW, I can still reproduce the issue with Node v16.13.2. |
This commit effectively reverts: nodejs#32463 That change introduces an upward JS API dependency on the Node API. Since that change fixed a bug, this will need to be revisited to determine the best way to fix the original bug without circular dependencies.
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)
The text was updated successfully, but these errors were encountered: