[cfe-dev] strange behavior when compile with -fvisibility-inlines-hidden flag

Richard Smith via cfe-dev cfe-dev at lists.llvm.org
Wed Dec 2 16:15:45 PST 2015


On Wed, Dec 2, 2015 at 4:11 PM, Richard Smith <richard at metafoo.co.uk> wrote:

> On Wed, Dec 2, 2015 at 1:41 AM, Weitian Leung via cfe-dev <
> cfe-dev at lists.llvm.org> wrote:
>
>> Hi all,
>>
>> Consider the following code (full source code can be found in attachment)
>>
>> object.h
>>
>> #define _DESTRUCTOR_IN_HEADER
>>
>> class Object
>> {
>> public:
>>     Object();
>> #ifdef _DESTRUCTOR_IN_HEADER
>>     ~Object()
>>     {
>>     }
>> #else
>>     ~Object();
>> #endif
>>
>> private:
>>     class Counter
>>     {
>>     public:
>>         Counter()
>>             : _count(0)
>>         {
>>             printf("Counter: %p %d\n", this, _count);
>>         }
>>
>>         ~Counter()
>>         {
>>             printf("~Counter: %p %d\n", this, _count);
>>         }
>>
>>         void operator++()    { ++_count; }
>>         void operator--()    { --_count; }
>>
>>     private:
>>         int _count;
>>     };
>>
>>     class Foo
>>     {
>>     public:
>>         Foo() { ++counter(); }
>>         ~Foo() { --counter(); }
>>
>>     private:
>>         Counter& counter()
>>         {
>>             static Counter s_counter;
>>             return s_counter;
>>         }
>>
>>
> When you use -fvisibility-inlines-hidden, you give this function hidden
> visibility, so each DSO gets its own copy of the function. We also give
> each DSO its own copy of each inline function's static local variables.
> Thus the Object::Object() constructor in your shared library increments one
> counter, and the Object::~Object() destructor in your main binary
> decrements a different counter.
>
> GCC appears to not make the static local variable hidden when it makes the
> surrounding function hidden. That makes sense, since
> -fvisibility-inlines-hidden is supposed to not change the semantics of the
> program unless you're comparing addresses of inline functions.
>

It also looks like this may have changed since the flag was originally
designed.

https://gcc.gnu.org/wiki/Visibility says "However,
-fvisibility-inlines-hidden can be used with no source alterations, unless
you need to override it for inlines where address identity is important
either for the function itself *or any function local static data.*"
(Clearly this is somewhat bogus: if the addresses of function local statics
are different, their contents may also be different.)

https://gcc.gnu.org/onlinedocs/gcc/C_002b_002b-Dialect-Options.html says:
"This switch declares that the user does not attempt to compare pointers to
inline functions or methods where the addresses of the two functions are
taken in different shared objects. [...] The behavior of this switch is not
quite the same as marking the methods as hidden directly, because it *does
not affect static variables local to the function* or cause the compiler to
deduce that the function is defined in only one shared object."

In any case, this is a Clang bug.

>     } foo;
>> };
>>
>> object.cpp
>>
>> #include "object.h"
>>
>> Object::Object()
>> {
>> }
>>
>> #ifndef _DESTRUCTOR_IN_HEADER
>> Object::~Object()
>> {
>>
>> }
>> #endif
>>
>>
>> Build the source to a shared library (compile with
>> -fvisibility-inlines-hidden flag),
>> uses in main (another module)
>>
>>     Object *obj = new Object;
>>     delete obj;
>>
>> you may see the strange output when running
>>
>> Counter: 0x7f2ded933efc 0
>> Counter: 0x6012d4 0
>> ~Counter: 0x6012d4 -1
>> ~Counter: 0x7f2ded933efc 1
>>
>>
>> The Counter construct/destruct twice, the second one (Counter: 0x6012d4
>> 0) construct from
>>  delete obj > Object::Foo::~Foo() > Object::Foo::counter()
>>
>> when comment out the line *#define _DESTRUCTOR_IN_HEADER *or remove the
>> *-fvisibility-inlines-hidden* flag, it works as expected
>> remove the compile flag
>>
>> Counter: 0x6013a4 0
>> ~Counter: 0x6013a4 0
>>
>> comment out #define _DESTRUCTOR_IN_HEADER
>>
>> Counter: 0x7f1eaa16629c 0
>> ~Counter: 0x7f1eaa16629c 0
>>
>>
>> A bit difference, as the address isn't the same (heap and stack)
>>
>> this code works with GCC (as least 5.2 as my test) with or without the
>> -fvisibility-inlines-hidden
>> flag, of course it works with MSVC too.
>>
>> I don't known is this a bug with the flag or because the silly code makes
>> it (as when constructor and
>> destructor defined in the same file, it works).
>>
>> It seems that my last post failed, seems no body answers me, so I repost
>> again, sorry.
>> If this is the wrong place, please let me know where to post, thanks.
>>
>>
>> _______________________________________________
>> cfe-dev mailing list
>> cfe-dev at lists.llvm.org
>> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20151202/a746b561/attachment-0001.html>


More information about the cfe-dev mailing list