I'm writing a WebRTC client in C++. It needs to work cross platform. I'm starting with a POC on Windows. I can connect and disconnect to/from the example peerconnection_server.exe.
Per the Microsoft "getting started" tutorial (https://learn.microsoft.com/en-us/winrtc/getting-started), I'm using the WebRTC "M84" release.
I'm aware of this similar SO post, but it is not the same issue, so please don't point me to that: WebRTC crash at line webrtc::PeerConnectionInterface::RTCConfiguration config; for Native Linux application That's a constructor matter on Linux. My problem is the destructor on Windows... (clearly that class must have flaws in general..)
Getting to the point, I've found that I can't ever destroy a webrtc::PeerConnectionInterface::RTCConfiguration
object. If I do, a fatal error is produced saying something about the app writing to the heap in some illegal manner. It makes no difference how or when I use that class - it always blows up on destruction. All one needs to do test this is the following:
webrtc::PeerConnectionInterface::RTCConfiguration *config
= new webrtc::PeerConnectionInterface::RTCConfiguration();
delete config;
On the delete
line - kaboom!
I've found assorted examples of this config class being used. No one looks to have any such issues, and don't appear to be jumping through hoops to deal with this. Typically, one of those objects is created when a PeerConnection is, and then just allowed to scope out of a local function. Considering it's a "config" object, it ought to be rather benign - but apparently not!
What secret trick is involved here?
Looking at the source, the definition of the default constructor & destructors are maximally trivial. So, is the bug in some member object in the config?
PeerConnectionInterface::RTCConfiguration::RTCConfiguration() = default;
...
PeerConnectionInterface::RTCConfiguration::~RTCConfiguration() = default;
Turns out this is specific to not only Windows/MSVC, but to DEBUG mode. In release mode, this doesn't happen for me. Apparently, it's caused by some linkage mismatch. If you compile with a given /MDd
or /MT
switch, etc. you'll run into such issues if you link to other libs or dlls which don't agree on that detail. (It's notable, however, that I have yet to see any other such problems in my build - only this one destructor is misbehaving. Weird!) Getting WebRTC to build in Windows requires assorted linkage to Windows SDK and system libraries. At least one of them must be mismatched for me. So, here's the workaround - just automatically ignore the errors!
First, for convenience, set a #define to identify to the conditional scenario. I'm using Qt, so that looks like this for me:
#if defined(QT_DEBUG) && defined(Q_CC_MSVC)
#define MSVC_DEBUG
#endif
Then, include this Windows api header:
#ifdef MSVC_DEBUG
#include <crtdbg.h>
#endif
I'm managing my config object via an std::unique_ptr (using STL rather than Qt in this .cpp since WebRTC doesn't use Qt of course, and it's cleaner to use a "When in Rome..." approach):
std::unique_ptr<webrtc::PeerConnectionInterface::RTCConfiguration> connConfig_;
Finally, when I want to destroy this object, I call a function resembling the following:
// Note: in Windows debug mode this destructor produces a heap assertion
// failure, which would create an ugly popup if not for the explicit
// suppression code surrounding the reset() below
void SomeClass::destroyConnectionConfig()
{
if( !connConfig_.get() ) return;
#ifdef MSVC_DEBUG
// Temporarily disabled popup error messages on Windows
auto warnCrtMode( _CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE ) );
auto warnCrtFile( _CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDERR ) );
auto errorCrtMode( _CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_FILE ) );
auto errorCrtFile( _CrtSetReportFile( _CRT_ERROR, _CRTDBG_FILE_STDERR ) );
auto assertCrtMode( _CrtSetReportMode( _CRT_ASSERT, _CRTDBG_MODE_FILE ) );
auto assertCrtFile( _CrtSetReportFile( _CRT_ASSERT, _CRTDBG_FILE_STDERR ) );
auto errorMode( _set_error_mode( _OUT_TO_STDERR ) );
#endif
connConfig_.reset();
#ifdef MSVC_DEBUG
// Restore error handling setttings
_CrtSetReportMode( _CRT_WARN, warnCrtMode );
_CrtSetReportFile( _CRT_WARN, warnCrtFile );
_CrtSetReportMode( _CRT_ERROR, errorCrtMode );
_CrtSetReportFile( _CRT_ERROR, errorCrtFile );
_CrtSetReportMode( _CRT_ASSERT, assertCrtMode );
_CrtSetReportFile( _CRT_ASSERT, assertCrtFile );
_set_error_mode( errorMode );
#endif
}