-
Notifications
You must be signed in to change notification settings - Fork 949
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
fix(websocket-websys): change close code in drop implementation to 1000 #5229
fix(websocket-websys): change close code in drop implementation to 1000 #5229
Conversation
Here is a basic reproduction which I used to create this PR: https://github.com/sisou/libp2p-websocket-reproduction |
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.
Hi, and thanks for the thorough report! Looks good to me, can you also add an entry in the CHANGELOG.md
?
cc @thomaseizinger you were the one adding the code, you may want to review it, and probably have an opinion on the use after free situation.
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.
Wow, that is surprising!
Great find. Yeah needs a version bump and changelog entry.
Thanks for reviewing it. We just added the version bump and changelog entry. |
In browsers, only the code 1000 and codes between 3000-4999 are allowed to be set by userland code: https://websockets.spec.whatwg.org/#dom-websocket-close
Thanks! Just waiting on #5253 so we can get CI green again |
@jsdanielh do you require a release? |
Yeah, that would be great |
In browsers, only the code 1000 and codes between 3000-4999 are allowed to be set by userland code: https://websockets.spec.whatwg.org/#dom-websocket-close I found this while debugging use-after-free errors in our WASM application. Turns out, when connections are timing out, libp2p in rust drops them, but does not seem to close them explicitly (we are using libp2p-swarm). This led to these WebSockets still emitting events, the handlers of which were already dropped on the rust side, though. A long investigation led me to have a look into the `Result` that gets returned from `close_with_code_and_reason`, and it turns out it's an error! Specifically: ``` InvalidAccessError: Failed to execute 'close' on 'WebSocket': The code must be either 1000, or between 3000 and 4999. 1001 is neither. ``` This PR only fixes the failing closing of the WebSocket, not the remaining use-after-free problem. Pull-Request: #5229.
sorry for the delay @jsdanielh and thanks for your patience. |
Description
In browsers, only the code 1000 and codes between 3000-4999 are allowed to be set by userland code: https://websockets.spec.whatwg.org/#dom-websocket-close
I found this while debugging use-after-free errors in our WASM application. Turns out, when connections are timing out, libp2p in rust drops them, but does not seem to close them explicitly (we are using libp2p-swarm). This led to these WebSockets still emitting events, the handlers of which were already dropped on the rust side, though.
A long investigation led me to have a look into the
Result
that gets returned fromclose_with_code_and_reason
, and it turns out it's an error! Specifically:This PR only fixes the failing closing of the WebSocket, not the remaining use-after-free problem.
Notes & open questions
Not ignoring error results
Can
Err
results not be ignored, but instead logged? That would have shown this problem a long time ago.Use-after-free event handlers
Calling
.close()
on the WebSocket leads to the WebSocket still emitting its"close"
event (and also an"error"
event, if the connection is still pending and ran into the time-out), for which thewebsocket-websys
transport registers a handler. This handler is dropped though together with the connection, so when the event comes into WASM, the handler is already free'd and this error is thrown (by wasm-bindgen?):This error is not critical in browsers (only annoying in the console) but exits NodeJS programs due to an uncaught exception.
A quick-fix would be to unregister the relevant event handlers in the
Drop
implementation, like so:According to @nibhar, there must be a better way, though. He suggests storing the socket's event handlers outside the connection, having them clean-up themselves when the onclose handler is called.
Change checklist