-
Notifications
You must be signed in to change notification settings - Fork 30.1k
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
src: no abort from GetFD if object isn't wrapped #6184
Conversation
}); | ||
}); | ||
|
||
dgram.createSocket('udp4').close(checkTCP); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fun!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just curious. What do you mean by "Fun"?
LGTM but Fedor has a point that there are probably more places where the value of |
LGTM. +1 on seeing if this can hit the other places too. |
7da4fd4
to
c7066fb
Compare
@bnoordhuis @indutny I've gone through and made it so we always check the return value of |
JSStream* wrap = Unwrap<JSStream>(args.Holder()); | ||
WriteWrap* w = Unwrap<WriteWrap>(args[0].As<Object>()); | ||
JSStream* wrap; | ||
// TODO(trevnorris): Verify that args[0] is actually an Object. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why leave this as a todo?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wanted feedback on whether it should throw or just return early.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd add a CHECK. If it's not an object, there's a logic error in node somewhere, right?
Left some comments. I do wonder if this approach isn't too blunt. I see a lot places where a nullptr wrap object is arguably an abort-worthy bug. |
I don't disagree here. Originally all I wanted to make sure of is that it would be impossible to abort the process if inspecting the handle at any point in it's lifetime. Similar to how I originally wanted to prevent abort from the C++ getters. And, lazily, it was easier to prevent abort from every unwrap instead of reason about each location. In the hopes that this would highlight every location where it could abort, and from there we could identify which places should definitely abort. |
@bnoordhuis Everything's been fixed. This was a blunt approach to the problem, and I'm fine going back through and being more decisive about when we choose to abort. |
ping @bnoordhuis @addaleax mind giving this a once over as well? |
@@ -14,6 +14,10 @@ inline BaseObject::BaseObject(Environment* env, v8::Local<v8::Object> handle) | |||
: handle_(env->isolate(), handle), | |||
env_(env) { | |||
CHECK_EQ(false, handle.IsEmpty()); | |||
// The zero field holds a pointer to the handle. Immediately set it to | |||
// nullptr in case it's accessed by the user before contruction is complete. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: construction
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for catching this.
I don’t know yet whether I have a strong opinion on aborting in some of these cases rather than returning silently, but I’ll sleep on that. And this LGTM either way… anything is better than segfaulting. ;) |
@bnoordhuis I can make a best effort at judging which locations where |
ContextifyScript* wrapped_script; | ||
ASSIGN_OR_RETURN_UNWRAP(&wrapped_script, | ||
args.Holder(), | ||
false); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fits on a single line.
@trevnorris should this be included with the other async wrap changes? |
@thealphanerd Yes. |
@trevnorris it looks like this will have to be manually backported, will you be able to help with that? |
@thealphanerd sure. I can do that. When would you need it by? |
@trevnorris there is no rush. But if it is in sooner it can make the cut for v4.5.0 |
ping @trevnorris would like to include this in v4.6.2 |
I'll take this. |
To make sure casting a class of multiple inheritance from a void* to AsyncWrap succeeds make AsyncWrap the first inherited class. PR-URL: nodejs#6184 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Anna Henningsen <anna@addaleax.net>
In case the handle is stored and accessed after the associated C++ class was destructed, set the internal pointer to nullptr so any getters/setters can return accordingly without aborting the application. PR-URL: nodejs#6184 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Anna Henningsen <anna@addaleax.net>
Though the TLSWrap constructor is only called via TLSWrap::Wrap() (i.e. tls_wrap.wrap()) internally, it is still exposed to JS. Don't allow the application to abort by inspecting the instance before it has been wrap'd by another handle. PR-URL: nodejs#6184 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Anna Henningsen <anna@addaleax.net>
First cast the pointer to the child Base class before casting to the parent class to make sure it returns the correct pointer. PR-URL: nodejs#6184 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Anna Henningsen <anna@addaleax.net>
v8::Object::GetAlignedPointerFromInternalField() returns a random value if Wrap() hasn't been run on the object handle. Causing v8 to abort if certain getters are accessed. It's possible to access these getters and functions during class construction through the AsyncWrap init() callback, and also possible in a subset of those scenarios while running the persistent handle visitor. Mitigate this issue by manually setting the internal aligned pointer field to nullptr in the BaseObject constructor and add necessary logic to return appropriate values when nullptr is encountered. PR-URL: nodejs#6184 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Anna Henningsen <anna@addaleax.net>
To make sure casting a class of multiple inheritance from a void* to AsyncWrap succeeds make AsyncWrap the first inherited class. PR-URL: #6184 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Anna Henningsen <anna@addaleax.net>
In case the handle is stored and accessed after the associated C++ class was destructed, set the internal pointer to nullptr so any getters/setters can return accordingly without aborting the application. PR-URL: #6184 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Anna Henningsen <anna@addaleax.net>
Though the TLSWrap constructor is only called via TLSWrap::Wrap() (i.e. tls_wrap.wrap()) internally, it is still exposed to JS. Don't allow the application to abort by inspecting the instance before it has been wrap'd by another handle. PR-URL: #6184 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Anna Henningsen <anna@addaleax.net>
First cast the pointer to the child Base class before casting to the parent class to make sure it returns the correct pointer. PR-URL: #6184 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Anna Henningsen <anna@addaleax.net>
v8::Object::GetAlignedPointerFromInternalField() returns a random value if Wrap() hasn't been run on the object handle. Causing v8 to abort if certain getters are accessed. It's possible to access these getters and functions during class construction through the AsyncWrap init() callback, and also possible in a subset of those scenarios while running the persistent handle visitor. Mitigate this issue by manually setting the internal aligned pointer field to nullptr in the BaseObject constructor and add necessary logic to return appropriate values when nullptr is encountered. PR-URL: #6184 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Anna Henningsen <anna@addaleax.net>
To make sure casting a class of multiple inheritance from a void* to AsyncWrap succeeds make AsyncWrap the first inherited class. PR-URL: #6184 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Anna Henningsen <anna@addaleax.net>
In case the handle is stored and accessed after the associated C++ class was destructed, set the internal pointer to nullptr so any getters/setters can return accordingly without aborting the application. PR-URL: #6184 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Anna Henningsen <anna@addaleax.net>
Though the TLSWrap constructor is only called via TLSWrap::Wrap() (i.e. tls_wrap.wrap()) internally, it is still exposed to JS. Don't allow the application to abort by inspecting the instance before it has been wrap'd by another handle. PR-URL: #6184 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Anna Henningsen <anna@addaleax.net>
First cast the pointer to the child Base class before casting to the parent class to make sure it returns the correct pointer. PR-URL: #6184 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Anna Henningsen <anna@addaleax.net>
v8::Object::GetAlignedPointerFromInternalField() returns a random value if Wrap() hasn't been run on the object handle. Causing v8 to abort if certain getters are accessed. It's possible to access these getters and functions during class construction through the AsyncWrap init() callback, and also possible in a subset of those scenarios while running the persistent handle visitor. Mitigate this issue by manually setting the internal aligned pointer field to nullptr in the BaseObject constructor and add necessary logic to return appropriate values when nullptr is encountered. PR-URL: #6184 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Anna Henningsen <anna@addaleax.net>
Checklist
Affected core subsystem(s)
stream_base, base_object
Description of change
Previously the 0-index slot from
v8::Object::GetAlignedPointerFromInternalField() would return random
data if Wrap() hadn't been run on the object handle. Now immediately set
the slot to nullptr so we can know for sure whether it's been set or
not. Use this information to return -1 from GetFD() instead of aborting.
R=@bnoordhuis
R=@indutny
CI: https://ci.nodejs.org/job/node-test-pull-request/2254/