Skip to content

Windows: C++ exceptions in webrtc-sys are never caught - every bridge error path aborts the process instead of returning Err #1309

Description

@TomaszMysliwiec

Summary

On Windows, the C++ code in webrtc-sys signals errors by throwing std::runtime_error,
and the cxx bridge is supposed to convert that into a Rust Err. It doesn't. The throw
escapes the bridge's catch and reaches std::terminate(), which aborts the process.

This means any error returned by libwebrtc that the bridge turns into a throw is fatal
to the host application. There are 16 such throw sites across peer_connection.cpp,
peer_connection_factory.cpp, rtp_sender.cpp, rtp_transceiver.cpp, jsep.cpp and
frame_cryptor.cpp - adding tracks, adding transceivers, creating data channels, and so
on. Callers cannot defend against this: the error never becomes a value they can handle.

Cause

The prebuilt libwebrtc ships a webrtc.ninja whose compiler flags include
-D_HAS_EXCEPTIONS=0. The build script copies every -D from that file onto the same
compiler invocation that builds webrtc-sys's own C++ and the generated cxx bridge.

_HAS_EXCEPTIONS=0 tells the MSVC standard library that the translation unit does not use
exceptions. The bridge's catch (std::exception const&) is then not a working handler, so
a throw from the C++ side unwinds straight past it into the noexcept boundary of the
generated shim and terminates.

Those ninja flags describe how libwebrtc was compiled. They should not be applied
wholesale to webrtc-sys's own C++, which deliberately relies on exceptions as its error
channel.

Verification

Removing -D_HAS_EXCEPTIONS=0 from the prebuilt's webrtc.ninja and
desktop_capture.ninja and rebuilding webrtc-sys fixes it: the same failing call now
returns an Err and the process continues. Verified across several runs, with and
without the change.

Our environment: x86_64-pc-windows-msvc, bridge compiled by MSVC cl.exe, static CRT
(-C target-feature=+crt-static), stock prebuilt consumed via LK_CUSTOM_WEBRTC.

What we haven't verified

We've only reproduced this in our own build, so we can't rule out that something in our
setup is load-bearing - the most likely candidate is the static CRT, which we haven't
tried removing.

That said, we don't see how it could be specific to us: the define comes from your
published prebuilt, the code that copies it onto the bridge is yours, and the scenario is
ordinary. If it doesn't reproduce for you, the quickest check is whether
-D_HAS_EXCEPTIONS=0 appears on the compile line for the generated bridge sources in your
build. If it does, the same failure should be reachable.

This is structurally Windows-only - _HAS_EXCEPTIONS only affects the MSVC standard
library - which may be why it hasn't surfaced before.

Reproduction

  1. Join a room and publish an audio track.
  2. Take the network down so the signalling connection cannot recover.
  3. Wait for the reconnect attempts to be exhausted.

On disconnect, Room::close() unpublishes the local tracks. The peer connection is already
closed by then, so removing the track fails with INVALID_STATE, the C++ side throws, and
the process aborts.

Worth noting: Room::close() already writes let _ = ...unpublish_track(sid).await, i.e.
this error is expected and meant to be ignored. It never gets the chance.

Abridged stack:

abort
terminate
__CxxFrameHandler4                                   <- no handler found
_CxxThrowException
livekit_ffi::PeerConnection::remove_track            peer_connection.cpp:207
rust::behavior::trycatch<...>                        <- present, did not catch
livekit_ffi$cxxbridge1$PeerConnection$remove_track   (noexcept)
...
livekit::room::...::unpublish_track
livekit::room::...::close
livekit::room::...::handle_disconnected

Affected versions

x86_64-pc-windows-msvc, verified on livekit 0.7.53 / webrtc-sys 0.3.39 / libwebrtc 0.3.42.
Still present on livekit 0.8.1 / webrtc-sys 0.3.40 / libwebrtc 0.3.43 - the relevant code is
unchanged.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions