Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Emscripten RTTI bug #322

Open
pixelherodev opened this issue Oct 11, 2018 · 4 comments
Open

Emscripten RTTI bug #322

pixelherodev opened this issue Oct 11, 2018 · 4 comments

Comments

@pixelherodev
Copy link
Contributor

pixelherodev commented Oct 11, 2018

Oryol's RTTI doesn't work properly in Emscripten when using dynamic libraries.

A simple test case:

module.h:

class Module : public RefCounted {
    OryolClassDecl(Plugin);
    OryolBaseTypeDecl(Plugin);
public:
    virtual ~Module(){}
};

class ModuleOfSpecificType : public Module {
    OryolClassDecl(ModuleOfSpecificType);
    OryolTypeDecl(ModuleOfSpecificType, Module);
public:
    virtual ~ModuleOfSpecificType(){}
    virtual void doSomething() = 0;
};

side_module.h:

class SideModule : public ModuleOfSpecificType {
    OryolClassDecl(SideModule);
    OryolTypeDecl(SideModule, ModuleOfSpecificType);
    OryolClassCreator(SideModule);
public:
    virtual void doSomething();
}

If the class SideModule is used in, well, a side module in Emscripten and then dlopened by the main code and constructed via e.g.

extern "C" Ptr<Module> create(){
    return new Module;
}

and dlsym(side_module, "create") is used to instantiate it and get a Ptr named m:

if (m->IsA<ModuleOfSpecificType>()) {
    // On desktop, this code is run. On Emscripten... not so much
    m->DynamicCast<ModuleOfSpecificType>()->doSomething();
}

If that's changed to use a raw pointer access and manual cast e.g.

((ModuleOfSpecificType*)m.p)->doSomething();

then it works fine.

Importantly, it works on native platforms, and it works with a manual cast. The only thing that's broken is the RTTI.

I suspect that Emscripten gives each module its own address space, which makes Oryol's RTTI fundamentally incompatible with Emscripten with libdl.

A possible solution: once the module support is added behind a Fips option, have that option also change to a different RTTI implementation that functions differently.

One idea that occurs to me: if it's possible to override specific templates which IIRC it is, the RTTI can be changed to overload for the specific class.

@floooh
Copy link
Owner

floooh commented Oct 12, 2018

Hmm... I haven't worked with side modules yet, but I don't believe they have their own address space, that would isolate them completely from the main module and other side modules. As far as I can see from the documentation the difference is that they are 'pure code', without attached runtime (I guess they access the shared runtime from the main module)

I suspect instead that something's wrong about the allocation of the static char _type_id; here when running in the context of a side module:

template<class T> static Oryol::TypeId getTypeId() { static char _type_id; return &_type_id; };\

Maybe the side module's static "allocation counter" is running independent from the main module (and other side modules), so that statics setup in the main and side modules end up in the same memory location.

@floooh
Copy link
Owner

floooh commented Oct 12, 2018

PS: also googling for smth like "emscripten side module static initialization" brings up this fairly recent bug:

emscripten-core/emscripten#6991

Is your emscripten version uptodate?

@pixelherodev
Copy link
Contributor Author

Yeah - locally I build with the incoming branch as per fips's default, and I have a script for Travis that patches fips to use 1.38.12, which is already after the bug was fixed (definitely fixed before 1.38.11 according to that).

@pixelherodev
Copy link
Contributor Author

One (unpleasant) option is an alternative system for Emscripten: global symbols are clearly visible from side modules - I use ImGui built into my main module from my plugins - so we could set a global int - a 32-bit number should be plenty (even if it's an extra 3 bytes per class), and have each class declare a static int that's initialized to the global from the main module ++ on startup. That quadruples the size of the RTTI, but should (if implemented properly) work as a temporary hack until this bug is fixed in Emscripten.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants