0

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;
BuvinJ
  • 10,221
  • 5
  • 83
  • 96

1 Answers1

0

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
}
BuvinJ
  • 10,221
  • 5
  • 83
  • 96
  • there was a proposed change to make building /MT and /MD: https://chromium-review.googlesource.com/c/chromium/src/+/2139834 While generally useful it wasn't merged and hence everyone is forced to reinvent that wheel. – Philipp Hancke May 13 '22 at 06:39
  • Interesting. That seems to be par for the course with WebRTC. It has become painfully apparent to me the developers have no concern for others who need/wish to employ this beast for purposes other than being a Chromium component. I get the impression it started with more broad based intentions then tumbled down that slippery slope. – BuvinJ May 13 '22 at 13:00
  • if you add a comment to that change explaining why it would be useful it might be a chance to revive the discussion – Philipp Hancke May 13 '22 at 15:36
  • Ok. I just did so! Hopefully they add this. It seems like it would be simple enough... – BuvinJ May 13 '22 at 16:34
  • I will note however, In my use case I already manually twiddled the dynamic_crt flag to build the .lib. But, in my app I have still to link to other libs/dlls to get that to compile. I think(?) I built the webrtc.lib correctly, but have mismatches within my implementation of it. Note that I have a pile of other libraries in play, and other contributors on my end. I don't have "full" control of the code base. Regardless, getting your request completed to ease the initial webrtc build, would be nice for sure! – BuvinJ May 13 '22 at 16:46