Just put these 3 simple lines in your project’s GameMode::StartPlay and watch Unreal crash!
ss << "aaaaaaaaaaaaaaaaaaaaaaaaaaa";
std::string s = ss.str();
Here are the interesting thing about this crash:
- Crash doesn’t occur in Windows, it only occurs in Linux.
- Crash occurs in 4.15 as well as 4.16.
- Crash doesn’t occur if this code is in usual standard C++ executable, even when you compile it against Clang and libc++ with exact same version and command line options as Unreal does.
- Crash doesn’t occur for bit shorter string, for example
"aaaaaaaaaaaaaaaaa" instead of above works fine.
- Crash occurs if you put above code in pretty much any function anywhere when that function will be called.
- The crash occurs when local variable
s goes out of scope and
std::string destructor gets run. Probably Unreal’s custom allocator kicks in? If that’s the case there is a serious bug in custom allocator.
Unfortunately, not using std::string or std::stringstream is not an option as this is happening inside 3rd party code. Rewriting all that in to Unreal’s own standard lib is not practical. Crashes like these are extremely difficult to debug because they only happen on Linux where IDE and debugging support is abysmal and rarely works. I spent about 5 days of excruciating debugging in 3rd party code to finally boil down in to above reproducible case, the days I could have spent in actually working on useful features for my users.
I really hope folks at Unreal would look in to this seriously and we have some solution.
Attached: Simple project that reproduces crash, crash log files
This was a side effect of hiding new/delete symbols in the linker script: STL could not use them consistently: code inlined in the engine binary (like e.g. std::string constructor or anything that was #include’d by a .cpp) was calling UE4’s new/delete (and allocating memory through its malloc), while code remaining in the dynamic library (like non-inlined STL functions) was going through its own new/delete (and perhaps using libc malloc()/free()).
This hiding was implemented in one of early UE4 versions (UE 4.2 or so) because Steam runtime library uses some custom new signature that UE4 cannot overload, so Steam would allocate a class instance using new(their parameters) Class that would use different malloc than UE4’s and then would use global delete (alas there are no custom delete signatures in C++ alas) which would attempt to free the pointer through UE4’s malloc, resulting in a crash.
For 4.17 I have removed the linker script, so now we don’t hide new/delete. We have also reported the problem to Valve and they have libsteam_api.so library changed, so the linker script should not be needed at least for Steam (there may still be other third party libs that need to be corrected similarly).
You reported the issue against 4.17 preview, but you only mention 4.15 and 4.16. Could you please test it with 4.17, since it should be solved there. Or alternatively, you can delete the linker script in 4.16 by commenting out everything between lines 1241 and 1272 in LinuxToolChain.cs, see https://github.com/EpicGames/UnrealEngine/blob/4.16/Engine/Source/Programs/UnrealBuildTool/Linux/LinuxToolChain.cs#L1241
“Rewriting all that in to Unreal’s own standard lib is not practical”
Note that you don’t have to rewrite, just to recompile using libc++ (either bundled with UE or a system one). This will remove the dependency on system libstdc++ (which you cannot bundle with Unreal, at least without consulting your lawyer), making it easier to redistribute the resulting binary.
Thanks so much. I’ll test this out and report my findings.
Update: test on 4.17 was success. On 4.15, above patch makes Unreal crash on startup. I probably won’t get chance to test 4.16.
It probably refuses to start rather than crashes. You need to disable CEF3 for this to work (UEBuildLinux.cs, ValidateTarget() function, Target.bCompileCEF3=false; )
This change has also fixed a crash I encountered with the use of std::thread in a plugin in 4.16.3.