Signature mismatch between side and main module with flto
Enabling LTO in the side module breaks the loading of the side module. To reproduce the error one can use the following code:
catch.hpp:
#include <string>
#include <sstream>
#include "emscripten.h"
// Part of catch2 lib that reproduces error
class StreamBufImpl : public std::streambuf {
public:
StreamBufImpl() = default;
};
class DebugOutStream {
StreamBufImpl m_streamBuf;
public:
DebugOutStream() : m_streamBuf() {}
};
auto makeStream() -> auto const* {
return new DebugOutStream();
}
main_catch2.cpp:
#include "catch.hpp"
EMSCRIPTEN_KEEPALIVE
int main( int argc, char* argv[] ) {
return EXIT_SUCCESS;
}
Test_Impl.cpp:
#include "catch.hpp"
EMSCRIPTEN_KEEPALIVE extern "C" void func() {}
Compiling with
em++ -fPIC -flto -O0 -o libmain_catch2.so -sSIDE_MODULE=1 main_catch2.cpp && em++ -flto -O0 -sMAIN_MODULE=2 -sEXPORTED_FUNCTIONS=_func -sASSERTIONS=2 Test_Impl.cpp -o Test.js libmain_catch2.so
leads to a runtime Error: [LinkError: WebAssembly.instantiate(): Import #8 module="env" function="_ZNSt3__215basic_streambufIcNS_11char_traitsIcEEE7seekoffExNS_8ios_base7seekdirEj" error: imported function does not match the expected type].
em++ --version: 3.1.64 node --version: v18.20.3
I managed to reproduce and simplified a little:
main.c:
int main(int argc, char* argv[]) {
return 0;
}
catch.cpp:
#include "catch.hpp"
$ em++ -flto -c -sSIDE_MODULE=1 catch.cpp
$ em++ -o libside.so -sSIDE_MODULE=1 catch.o
$ emcc -sMAIN_MODULE=2 -sASSERTIONS=2 main.c libside.so
$ node ./a.out.js
node:internal/process/promises:288
triggerUncaughtException(err, true /* fromPromise */);
^
[LinkError: WebAssembly.instantiate(): Import #8 module="env" function="_ZNSt3__215basic_streambufIcNS_11char_traitsIcEEE7seekoffExNS_8ios_base7seekdirEj" error: imported function does not match the expected type]
Node.js v18.20.3
It seems like somehow the signature of that function (which is std::__2::basic_streambuf<char, std::__2::char_traits<char> >::seekoff(long long, std::__2::ios_base::seekdir, unsigned int) by the way) is modified by the LTO process when linking the side module.
I don't know why that would be at this point I'm afraid.