FTcpListener crash. Expects to be running in "game" thread, but spawns its own.ad - crashes.p

Hi,

If I create a FTcpListener in the main thread, I get an error message saying:

4.2\Engine\Source\Runtime\Core\Private\Modules\ModuleManager.cpp(33):
Ensure condition failed:
IsInGameThread()

This is the callstack:

FWindowsPlatformMisc::LocalPrint(const wchar_t * Message) Line 654
FGenericPlatformMisc::LowLevelOutputDebugString(const wchar_t * Message) Line 216
FGenericPlatformMisc::LowLevelOutputDebugStringf(const wchar_t * Fmt, ...) Line 222
FailDebug(const wchar_t * Error, const char * File, int Line, const wchar_t * Description) Line 138
FDebug::EnsureFailed(const char * Expr, const char * File, int Line, const wchar_t * Msg) Line 207
FModuleManager::Get() Line 42
FModuleManager::LoadModuleChecked<FSocketSubsystemModule>(const FName ModuleName) Line 255
ISocketSubsystem::Get'::`2'::FStatic::FStatic() Line 210
ISocketSubsystem::Get(const FName & SubsystemName) Line 218
FTcpSocketBuilder::Build() Line 183
FTcpListener::Init() Line 145
FRunnableThreadWin::Run() Line 68
FRunnableThreadWin::GuardedRun() Line 47
FRunnableThreadWin::_ThreadProc(void * pThis) Line 118

Hi Stefan,

I’m afraid you have discovered some code rot. The FTcpListener class will in fact no longer work as is. The problem is that, as your callstack indicates the socket creation is dependent on loading the Sockets module on demand. Module loading is not thread-safe, so we added an assertion a few months ago, which is what you’re seeing.

The FTcpListener class needs to be redesigned, properly taking into account the module loading limitations. In the meantime you can use the following workaround:

  1. Build your own socket on the game thread, i.e.using the same code that is in FTcpListener::Init()
  2. Use the FTcpListener constructor that takes an existing socket instead of an IP endpoint

This will prevent the socket creation code in Init() from being executed. The thread’s Run() function also depends on the Sockets module for creating FInternetAddr instances, but that should be OK as the platform’s socket subsystem module should already be loaded at that point, so that no module load is necessary.

Development on the Networking module was suspended last year, and it needs a major overhaul. I’m hoping to get back to it later this Summer or early Fall. Until then it should be considered experimental.

Let me know if you run into any other issues!

Thanks a lot Max, I appreciate all the info!

Is this still a problem with 4.15.x?

I’m getting strange nullptr crashes for code that I swear was working, Socket is 0x0:

Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7fff969bd700 (LWP 31226)]
0x00007fff7b79d34b in FTcpListener::Init (this=0x7fff4392d700) at /home/sgundry/UnrealEngine/Engine/Source/Runtime/Networking/Public/Common/TcpListener.h:144
144                Socket->SetReceiveBufferSize(2*1024*1024, NewSize);

I think your error is different. It looks like the TcpSocketBuilder failed to create a socket. Either SocketSubsystem is null, or CreateSocket failed.

The code in FTcpListener::Init is broken, because it does not check for Socket == nullptr. That’s why you’re seeing the run-time crash.

The other issue discussed in the original question is probably still present as well. I don’t recall anyone working on this code since. It’s on the to-do list, but super low priority. I don’t expect to get to this before the last quarter of this year.

I suggest a similar workaround as before:

  1. Build your own socket
  2. Make sure it is not null. If it is null, then something else is broken. Maybe the socket subsystem isn’t initialized, or maybe you’re missing a module dependency to the Sockets module.
  3. Use the FTcpListener constructor that takes the socket you created