emscripten-core / emscripten-core/emscripten

C++ virtual functions crash when called from global constructor

Open
#17,295 5 comments 0 reactions 0 assignees View on GitHub
Dominant language
C++
Stars
27.6k
Forks
3.6k
Avg merge
1d 1h
Merged PRs (30d)
105

Description

Hello, we have a header with public interface that is exported and private implementation located in shared library(built with SIDE_MODULE=1). In constructor of global object we get reference to public interface and try to call virtual function, which leads to crash. We had similar problem before mentioned here: https://github.com/emscripten-core/emscripten/issues/17150
It was fixed, but now similar issue happens when calling virtual functions in constructors of global objects.

**Version of emscripten/emsdk:**
emcc (Emscripten gcc/clang-like replacement + linker emulating GNU ld) 3.1.14 (4343cbec72b7db283ea3bda1adc6cb1811ae9a73)
clang version 15.0.0 (https://github.com/llvm/llvm-project 7effcbda49ba32991b8955821b8fdbd4f8f303e2)
Target: wasm32-unknown-emscripten
Thread model: posix

```cpp
//Interface.h
#pragma once
#include

class __attribute__((visibility ("default"))) PublicInterface
{
public:
virtual void Foo() = 0;
static PublicInterface& GetInstance();
};

class SomeClass
{
public:
SomeClass() {
std::cout << "SomeClass()" << "\n";
PublicInterface::GetInstance().Foo();
}
};

//Implementation.cpp
#include "Interface.h"

class PrivateImplementation : public PublicInterface
{
public:
void Foo() override {
std::cout << "PrivateImplementation::Foo()" << "\n";
}
};

PublicInterface& PublicInterface::GetInstance() {
std::cout << "PublicInterface::GetInstance()" << "\n";
static PrivateImplementation privateImpl;
return privateImpl;
}

//main.cpp
#include "Interface.h"

SomeClass g_var;

int main() {
return 0;
}
```

**Build commands**
emcc Implementation.cpp -fPIC -fvisibility=hidden -c -o Implementation.o
emcc Implementation.o -sSIDE_MODULE=1 -o dylib1.wasm
emcc main.cpp -fPIC -fvisibility=hidden -c -o main.o
emcc main.o -sMAIN_MODULE=1 -o main.html dylib1.wasm

**Console output**
SomeClass()
PublicInterface::GetInstance()
Uncaught RuntimeError: null function or function signature mismatch

If I reverse runtime callback order in javascript so that global constructors of shared lib run before global constructors of main, problem dissappears, like this
```js
function callRuntimeCallbacks(callbacks) {
callbacks.reverse(); // added this line
while (callbacks.length > 0) {
var callback = callbacks.shift();
if (typeof callback == 'function')
```

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.