wlav / cppyy

Other
400 stars 41 forks source link

Thread local storage access fails for inline functions #60

Closed levy closed 10 months ago

levy commented 2 years ago

If I change the function to be out-of-line, then it works.

pip3 list

cppyy                   2.3.1
cppyy-backend           1.14.8
cppyy-cling             6.25.3
CPyCppyy                1.12.10

test.h

#include <thread>

class Simulation
{
  public:
    static thread_local Simulation *activeSimulation;

    static Simulation *getActiveSimulation() {return activeSimulation;}
};

test.cc

#include "test.h"

thread_local Simulation *Simulation::activeSimulation = nullptr;

test_thread_local.py

import cppyy

cppyy.add_include_path(".")
cppyy.add_library_path(".")
cppyy.load_library("libtest")
cppyy.include("test.h")

print(cppyy.gbl.Simulation.activeSimulation)
print(cppyy.gbl.Simulation.getActiveSimulation())

compiling

clang++ -fPIC -shared -o libtest.so test.cc

running

levy@valardohaeris:~$ python3 test_thread_local.py 
<cppyy.gbl.Simulation* object at 0x(nil)>
IncrementalExecutor::executeFunction: symbol '_ZTHN10Simulation16activeSimulationE' unresolved while linking symbol '__cf_5'!
You are probably missing the definition of TLS init function for Simulation::activeSimulation
Maybe you need to load the corresponding shared library?
IncrementalExecutor::executeFunction: symbol '__emutls_v._ZN10Simulation16activeSimulationE' unresolved while linking symbol '__cf_5'!
<cppyy.gbl.Simulation object at 0x(nil)>
wlav commented 2 years ago

Yes, this is known: the JIT in the current version of LLVM underlying Cling uses emulated TLS even if the platform supports it natively. More recent gcc no longer does that and so linking will fail. Have to see whether this improves with LLVM13 (upstream has ported Cling, is now fixing up the last failing tests). Certainly JITLink supports TLS.

levy commented 2 years ago

Thanks for the heads up.

avarga commented 1 year ago

A simpler example to check/reproduce the bug:

import cppyy
cppyy.cppdef("class Foo { static thread_local int x; public: static int getX() {return x;} }; int thread_local Foo::x;")
cppyy.gbl.Foo.getX() # IncrementalExecutor::executeFunction: symbol '__emutls_v._ZN3Foo1xE' unresolved while linking symbol '__cf_5'!

When deleting the two thread_local modifiers, the error goes away. It also goes away if getX() is changed to be out-of-line:

import cppyy
cppyy.cppdef("class Foo { static thread_local int x; public: static int getX(); }; int thread_local Foo::x; int Foo::getX() {return x;}")
cppyy.gbl.Foo.getX() #ok
wlav commented 10 months ago

Missed this bug report somehow ... the thread_local has been fixed since 3.0.0 (which uses Clang13).