From e98d31d697f8f0dd5623d309680eb6edede27662 Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Fri, 28 Jul 2017 21:56:51 -0400 Subject: [PATCH] Force hidden visibility on functions needing distinct static locals This commit adds a PYBIND11_UNSHARED_STATIC_LOCALS macro that forces a function to have hidden visibility under gcc and gcc-compatible compilers. gcc, in particular, needs this to to avoid sharing static local variables across modules (which happens even under a RTLD_LOCAL dlopen()!). clang doesn't appear to have this issue, but the forced visibility on internal pybind functions certainly won't hurt it and icc. This updates the workaround from #862 to use this rather than the version-specific template. --- include/pybind11/cast.h | 10 ++++------ include/pybind11/common.h | 10 ++++++++++ 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index 5db03e2f..cb66e769 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -60,12 +60,10 @@ struct type_info { bool default_holder : 1; }; -// Store the static internals pointer in a version-specific function so that we're guaranteed it -// will be distinct for modules compiled for different pybind11 versions. Without this, some -// compilers (i.e. gcc) can use the same static pointer storage location across different .so's, -// even though the `get_internals()` function itself is local to each shared object. -template -internals *&get_internals_ptr() { static internals *internals_ptr = nullptr; return internals_ptr; } +PYBIND11_UNSHARED_STATIC_LOCALS PYBIND11_NOINLINE inline internals *&get_internals_ptr() { + static internals *internals_ptr = nullptr; + return internals_ptr; +} PYBIND11_NOINLINE inline internals &get_internals() { internals *&internals_ptr = get_internals_ptr(); diff --git a/include/pybind11/common.h b/include/pybind11/common.h index 240f6d8e..518e2456 100644 --- a/include/pybind11/common.h +++ b/include/pybind11/common.h @@ -68,6 +68,16 @@ # endif #endif +// Attribute macro for a function containing one or more static local variables that mustn't share +// the variable across shared objects (for example, because the value might be incompatible for +// modules compiled under different pybind versions). This is required under g++ (depending on the +// specific compiler and linker options), and won't hurt under gcc-compatible compilers: +#if defined(__GNUG__) +# define PYBIND11_UNSHARED_STATIC_LOCALS __attribute__ ((visibility("hidden"))) +#else +# define PYBIND11_UNSHARED_STATIC_LOCALS +#endif + #if defined(_MSC_VER) # define PYBIND11_NOINLINE __declspec(noinline) #else