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
- Join a room and publish an audio track.
- Take the network down so the signalling connection cannot recover.
- 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.
Summary
On Windows, the C++ code in
webrtc-syssignals errors by throwingstd::runtime_error,and the cxx bridge is supposed to convert that into a Rust
Err. It doesn't. The throwescapes 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.cppandframe_cryptor.cpp- adding tracks, adding transceivers, creating data channels, and soon. Callers cannot defend against this: the error never becomes a value they can handle.
Cause
The prebuilt libwebrtc ships a
webrtc.ninjawhose compiler flags include-D_HAS_EXCEPTIONS=0. The build script copies every-Dfrom that file onto the samecompiler invocation that builds webrtc-sys's own C++ and the generated cxx bridge.
_HAS_EXCEPTIONS=0tells the MSVC standard library that the translation unit does not useexceptions. The bridge's
catch (std::exception const&)is then not a working handler, soa throw from the C++ side unwinds straight past it into the
noexceptboundary of thegenerated 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=0from the prebuilt'swebrtc.ninjaanddesktop_capture.ninjaand rebuilding webrtc-sys fixes it: the same failing call nowreturns an
Errand the process continues. Verified across several runs, with andwithout the change.
Our environment:
x86_64-pc-windows-msvc, bridge compiled by MSVCcl.exe, static CRT(
-C target-feature=+crt-static), stock prebuilt consumed viaLK_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=0appears on the compile line for the generated bridge sources in yourbuild. If it does, the same failure should be reachable.
This is structurally Windows-only -
_HAS_EXCEPTIONSonly affects the MSVC standardlibrary - which may be why it hasn't surfaced before.
Reproduction
On disconnect,
Room::close()unpublishes the local tracks. The peer connection is alreadyclosed by then, so removing the track fails with
INVALID_STATE, the C++ side throws, andthe process aborts.
Worth noting:
Room::close()already writeslet _ = ...unpublish_track(sid).await, i.e.this error is expected and meant to be ignored. It never gets the chance.
Abridged stack:
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.