Skip to content
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

n-api: test for finalizer calls JS from first round phantom callback #25927

Closed
mlippautz opened this issue Feb 4, 2019 · 10 comments
Closed

n-api: test for finalizer calls JS from first round phantom callback #25927

mlippautz opened this issue Feb 4, 2019 · 10 comments
Labels
node-api Issues and PRs related to the Node-API.

Comments

@mlippautz
Copy link

V8's API does not allow calling directly back into V8 from weak callbacks, see: `

// calls may be called in the first callback. Should additional work be

Instead, a second pass callback should be set using the WeakCallbackInfo API.

Affected are tests using this testing API:

napi_call_function(env, undefined, js_cb, 0, NULL, NULL));

This should fire a DCHECK for allowed allocations as soon as the JS callback executed non-trivial JS.

It also breaks the assumption that V8 can call out to the callback during the GC when not all pointers (of other v8::Persistent handles) have not been updated.

@hashseed

@hashseed
Copy link
Member

hashseed commented Feb 4, 2019

@nodejs/n-api
@addaleax
@mcollina

@hashseed
Copy link
Member

hashseed commented Feb 4, 2019

I guess in V8 we should add a v8::internal::DisallowJavaScriptExecution scope.

@addaleax addaleax added the node-api Issues and PRs related to the Node-API. label Feb 4, 2019
@mhdawson
Copy link
Member

mhdawson commented Feb 6, 2019

@mlippautz do you believe its an issue in the test or in the N-API implementation itself?

@addaleax
Copy link
Member

addaleax commented Feb 6, 2019

@mhdawson It is, yes

@gabrielschulhof
Copy link
Contributor

I interpret this to mean that we should honour the engine's constraints and throw an exception from the N-API implementation whenever we're about to call back into V8 knowing that we're coming from a weak callback and knowing that the call would result in JS execution. I think we can capture this with NAPI_PREAMBLE().

@gabrielschulhof
Copy link
Contributor

@hashseed does this restriction apply also to things like Object::Set() as well? IOW must I avoid all calls that return a Maybe from a weak callback?

@addaleax
Copy link
Member

addaleax commented Feb 6, 2019

@gabrielschulhof What we do elsewhere in core (e.g. async hooks) is to delay running callbacks that may invoke JS with a SetImmediate call, btw. GC is nondeterministic anyway, and delaying the callback gives us the freedom to do whatever we want in it.

I’d first try either that, or use @mlippautz’ suggestion of using SetSecondPassCallback().

@mlippautz
Copy link
Author

I am not fluent in n-api but it looks like napi_add_finalizer would only accept a native callback in finalize_cb. That seems safe.

The problem is that the other parameters passed can be used to invoke JS. Prohibit parameters likely limits usability so documentation should probably mention that no V8 API may be called on them and they should only be passed along. (That's how V8 went about this problem.)

As already mentioned, solutions are posting another task to the platform using node or using SetSecondPassCallback which would post the task from within V8, or potentially execute it synchronously after GC in V8 (e.g. when under memory pressure).

@hashseed
Copy link
Member

hashseed commented Feb 7, 2019

@hashseed does this restriction apply also to things like Object::Set() as well? IOW must I avoid all calls that return a Maybe from a weak callback?

Yes. It's not so much JS execution that's bad, but all access to the heap that assumes consistent heap state. During GC, that may not be the case.

@gabrielschulhof
Copy link
Contributor

@mlippautz you're right in that there is no indication that it is unsafe to call into V8. It's also true that other engines may not have this restriction. Therefore I think we should try to provide the feature whereby we invoke the weak callback in such a way that it is safe to call into the engine from there.

gabrielschulhof pushed a commit to gabrielschulhof/node that referenced this issue Feb 7, 2019
Calling into the engine from a weak callback is unsafe, however, the
engine offers a way to attach a second-pass weak callback which gets
called when it is safe to call into JavaScript. This moves the point
at which the N-API finalize callback gets called to this latter point.

Fixes: nodejs#25927
addaleax pushed a commit that referenced this issue Feb 13, 2019
Calling into the engine from a weak callback is unsafe, however, the
engine offers a way to attach a second-pass weak callback which gets
called when it is safe to call into JavaScript. This moves the point
at which the N-API finalize callback gets called to this latter point.

Fixes: #25927
PR-URL: #25992
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com>
gabrielschulhof pushed a commit to gabrielschulhof/node that referenced this issue Mar 4, 2019
Calling into the engine from a weak callback is unsafe, however, the
engine offers a way to attach a second-pass weak callback which gets
called when it is safe to call into JavaScript. This moves the point
at which the N-API finalize callback gets called to this latter point.

Fixes: nodejs#25927
PR-URL: nodejs#25992
Backport-PR-URL: nodejs#26058
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com>
gabrielschulhof pushed a commit to gabrielschulhof/node that referenced this issue Mar 4, 2019
Calling into the engine from a weak callback is unsafe, however, the
engine offers a way to attach a second-pass weak callback which gets
called when it is safe to call into JavaScript. This moves the point
at which the N-API finalize callback gets called to this latter point.

Fixes: nodejs#25927
PR-URL: nodejs#25992
Backport-PR-URL: nodejs#26060
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com>
BethGriggs pushed a commit that referenced this issue Mar 12, 2019
Calling into the engine from a weak callback is unsafe, however, the
engine offers a way to attach a second-pass weak callback which gets
called when it is safe to call into JavaScript. This moves the point
at which the N-API finalize callback gets called to this latter point.

Fixes: #25927
PR-URL: #25992
Backport-PR-URL: #26058
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com>
BethGriggs pushed a commit that referenced this issue Mar 20, 2019
Calling into the engine from a weak callback is unsafe, however, the
engine offers a way to attach a second-pass weak callback which gets
called when it is safe to call into JavaScript. This moves the point
at which the N-API finalize callback gets called to this latter point.

Fixes: #25927
PR-URL: #25992
Backport-PR-URL: #26060
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
node-api Issues and PRs related to the Node-API.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants