[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.html>
More information about the cfe-dev
mailing list