LibWeb: Don't die when transferring the same MessagePort more than once

One MessagePort can be entangled with another MessagePort, either in the
same agent, or in another agent.

In the same-agent case, the MessagePort objects point to each other via
the MessagePort::m_remote_port field.

In the separate-agent case, they live in separate processes entirely and
thus can't point at each other.

In both cases, the MessagePorts have an underlying transport channel,
which means they are "entangled". However, we can't assume that being
entangled means having a non-null m_remote_port.

This patch simply adds a missing null check for m_remote_port and thus
makes https://vscode.dev/ stop crashing with a null dereference.
This commit is contained in:
Andreas Kling 2025-08-28 12:57:55 +02:00 committed by Andreas Kling
commit a26007f195
Notes: github-actions[bot] 2025-08-28 11:43:13 +00:00
3 changed files with 34 additions and 1 deletions

View file

@ -99,7 +99,11 @@ WebIDL::ExceptionOr<void> MessagePort::transfer_steps(HTML::TransferDataEncoder&
// 3. If value is entangled with another port remotePort, then:
if (is_entangled()) {
// 1. Set remotePort's has been shipped flag to true.
m_remote_port->m_has_been_shipped = true;
// NOTE: We have to null check here because we can be entangled with a port living in another agent.
// In that case, we'll have a transport, but no remote port object.
if (m_remote_port)
m_remote_port->m_has_been_shipped = true;
auto fd = MUST(m_transport->release_underlying_transport_for_transfer());
m_transport.clear();

View file

@ -0,0 +1,2 @@
first receipt: re-transferring same port
we good

View file

@ -0,0 +1,27 @@
<!doctype html>
<script src="../include.js"></script>
<script>
asyncTest(done => {
function onFirst(e) {
const port = (e.data && e.data.port) || (e.ports && e.ports[0]);
if (!port) return;
println("first receipt: re-transferring same port");
window.removeEventListener("message", onFirst);
window.addEventListener("message", onSecond);
window.postMessage({ port }, "*", [port]);
}
function onSecond(e) {
println("we good");
done();
}
window.addEventListener("message", onFirst);
const { port1, port2 } = new MessageChannel();
port1.onmessage = e => println("main saw: " + e.data);
window.postMessage({ port: port2 }, "*", [port2]);
});
</script>