public inbox for gcc-help@gcc.gnu.org
 help / color / mirror / Atom feed
* Explicit instantiation and static objects in different modules
@ 2015-08-04 15:00 Nikolay Vorobyov
  2015-08-04 15:45 ` Jonathan Wakely
  0 siblings, 1 reply; 6+ messages in thread
From: Nikolay Vorobyov @ 2015-08-04 15:00 UTC (permalink / raw)
  To: gcc-help

Hi,

I use gcc-5.1.0 on Windows (x86_64-posix-seh-rev0, Built by MinGW-W64 project). I have the following template class:

template <class T>
struct StaticObject
{
   static T & getInstance()
   {
     static T t;
     std::cout << "static object " << typeid(T).name() << " at " << &t << " = "<< t <<std::endl;
     return t;
   }
};

What i want to achieve is to have one instance of say StaticObject<int> through my EXE and several DLLs modules with use of explicit instantiation.
So in one of my DLLs (inst.dll) i have explicit instantiation of StaticObject<int> - inst.cpp:

#include "static_object.h"

template struct StaticObject<int>;

And there is #include “externs.h” in each source file that use this static object to prevent it from implicit instantiation - externs.h :

#pragma once

#include "static_object.h"

extern template struct StaticObject<int>;

There is calls to StaticObject<int>::getInstance() in EXE and DLL modules and what i get is different behavior with optimisation turned on and off. 
It works as expected:
1) with optimisation turned off and 
2) with following flags: “-Ox -fno-inline”, where ‘x’ is one of optimisation levels 1,2,3.

And it doesn’t work with any (1,2,3) level of optimisation turned on, so i get instances of StaticObject<int> in each DLL and EXE.

Please see my github project for reference - https://github.com/dlardi/mingw_static_test

Is this a gcc's bug?

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Explicit instantiation and static objects in different modules
  2015-08-04 15:00 Explicit instantiation and static objects in different modules Nikolay Vorobyov
@ 2015-08-04 15:45 ` Jonathan Wakely
  2015-08-04 16:53   ` Alexander Monakov
  0 siblings, 1 reply; 6+ messages in thread
From: Jonathan Wakely @ 2015-08-04 15:45 UTC (permalink / raw)
  To: Nikolay Vorobyov; +Cc: gcc-help

On 4 August 2015 at 16:00, Nikolay Vorobyov wrote:
> Is this a gcc's bug?

I believe this is due to how symbol resolution works in DLLs on
Windows, where each DLL has its own copy of the static variable. I
don't know how to make it work as required by the C++ standard.

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Explicit instantiation and static objects in different modules
  2015-08-04 15:45 ` Jonathan Wakely
@ 2015-08-04 16:53   ` Alexander Monakov
  2015-08-04 17:06     ` Jonathan Wakely
  0 siblings, 1 reply; 6+ messages in thread
From: Alexander Monakov @ 2015-08-04 16:53 UTC (permalink / raw)
  To: Jonathan Wakely; +Cc: Nikolay Vorobyov, gcc-help

On Tue, 4 Aug 2015, Jonathan Wakely wrote:

> On 4 August 2015 at 16:00, Nikolay Vorobyov wrote:
> > Is this a gcc's bug?
> 
> I believe this is due to how symbol resolution works in DLLs on
> Windows, where each DLL has its own copy of the static variable. I
> don't know how to make it work as required by the C++ standard.

One way would be to eliminate the inline definition of getInstance() in the
header file, and move it into inst.cpp.

If you inspect generated files with 'nm -C', you'll see that both libinst.dll
and liba.dll have a definition for StaticObject<int>::getInstance()::t.

Jonathan, I think there might be a GCC bug here, but not what Nikolay
originally meant.  With -std=c++11, 'extern template' should prevent the
compiler from instantiating methods of StaticObject, but it doesn't happen.
Here's a minimal example: 

template<int V>
struct S {
static int bar()
{
  return V;
}
};

extern template struct S<42>;

int foo()
{
  return S<42>::bar();
}

Compile with g++ -std=c++11 -S -o- -Os and observe that 'foo' is optimized to
'return 42', although 'bar' should not have been instantiated.  If you don't
have a template class and make 'bar' itself a template function, GCC does not
optimize 'foo', as expected.  WDYT?

Thanks.
Alexander

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Explicit instantiation and static objects in different modules
  2015-08-04 16:53   ` Alexander Monakov
@ 2015-08-04 17:06     ` Jonathan Wakely
  2015-08-04 17:32       ` Alexander Monakov
  0 siblings, 1 reply; 6+ messages in thread
From: Jonathan Wakely @ 2015-08-04 17:06 UTC (permalink / raw)
  To: Alexander Monakov; +Cc: Nikolay Vorobyov, gcc-help

On 4 August 2015 at 17:52, Alexander Monakov wrote:
> On Tue, 4 Aug 2015, Jonathan Wakely wrote:
>
>> On 4 August 2015 at 16:00, Nikolay Vorobyov wrote:
>> > Is this a gcc's bug?
>>
>> I believe this is due to how symbol resolution works in DLLs on
>> Windows, where each DLL has its own copy of the static variable. I
>> don't know how to make it work as required by the C++ standard.
>
> One way would be to eliminate the inline definition of getInstance() in the
> header file, and move it into inst.cpp.
>
> If you inspect generated files with 'nm -C', you'll see that both libinst.dll
> and liba.dll have a definition for StaticObject<int>::getInstance()::t.
>
> Jonathan, I think there might be a GCC bug here, but not what Nikolay
> originally meant.  With -std=c++11, 'extern template' should prevent the
> compiler from instantiating methods of StaticObject, but it doesn't happen.
> Here's a minimal example:
>
> template<int V>
> struct S {
> static int bar()
> {
>   return V;
> }
> };
>
> extern template struct S<42>;
>
> int foo()
> {
>   return S<42>::bar();
> }
>
> Compile with g++ -std=c++11 -S -o- -Os and observe that 'foo' is optimized to
> 'return 42', although 'bar' should not have been instantiated.  If you don't
> have a template class and make 'bar' itself a template function, GCC does not
> optimize 'foo', as expected.  WDYT?

The extern template tells the compiler it doesn't *need* to
instantiate the template, because it will be explicitly instantiated
in another translation unit. But that doesn't mean it *must not*
instantiate it. The compiler can choose to inline the function and in
that case it will implicitly instantiate it. That should be
unobservable because the One Definition Rule means that the implicitly
instantiated definition that gets inlined and the explicitly
instantiation definition in the other translation unit must be
identical. The Windows linkage model seems to break that assumption
... so I don't know what the right behaviour is.

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Explicit instantiation and static objects in different modules
  2015-08-04 17:06     ` Jonathan Wakely
@ 2015-08-04 17:32       ` Alexander Monakov
  2015-08-05 17:22         ` Nikolay Vorobyov
  0 siblings, 1 reply; 6+ messages in thread
From: Alexander Monakov @ 2015-08-04 17:32 UTC (permalink / raw)
  To: Jonathan Wakely; +Cc: Nikolay Vorobyov, gcc-help

On Tue, 4 Aug 2015, Jonathan Wakely wrote:
> The extern template tells the compiler it doesn't *need* to
> instantiate the template, because it will be explicitly instantiated
> in another translation unit. But that doesn't mean it *must not*
> instantiate it. The compiler can choose to inline the function and in
> that case it will implicitly instantiate it. That should be
> unobservable because the One Definition Rule means that the implicitly
> instantiated definition that gets inlined and the explicitly
> instantiation definition in the other translation unit must be
> identical. The Windows linkage model seems to break that assumption
> ... so I don't know what the right behaviour is.

OK, thanks.  AFAIU, a very similar problem existed with GCC on Linux prior to
introduction of STB_GNU_UNIQUE (consider what happened when multiple DSOs with
a common singleton are loaded with RTLD_LOCAL -- they didn't have a way to end
up with a common location).

In light of that, perhaps it's best to structure code in a way that prevents
implementation of a singleton from being visible in translation units that can
be linked into different libraries.

Alexander

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Explicit instantiation and static objects in different modules
  2015-08-04 17:32       ` Alexander Monakov
@ 2015-08-05 17:22         ` Nikolay Vorobyov
  0 siblings, 0 replies; 6+ messages in thread
From: Nikolay Vorobyov @ 2015-08-05 17:22 UTC (permalink / raw)
  To: Alexander Monakov; +Cc: Jonathan Wakely, gcc-help


On Aug 4, 2015, at 20:32, Alexander Monakov <amonakov@ispras.ru> wrote:

> On Tue, 4 Aug 2015, Jonathan Wakely wrote:
>> The extern template tells the compiler it doesn't *need* to
>> instantiate the template, because it will be explicitly instantiated
>> in another translation unit. But that doesn't mean it *must not*
>> instantiate it. The compiler can choose to inline the function and in
>> that case it will implicitly instantiate it. That should be
>> unobservable because the One Definition Rule means that the implicitly
>> instantiated definition that gets inlined and the explicitly
>> instantiation definition in the other translation unit must be
>> identical. The Windows linkage model seems to break that assumption
>> ... so I don't know what the right behaviour is.
> 
> In light of that, perhaps it's best to structure code in a way that prevents
> implementation of a singleton from being visible in translation units that can
> be linked into different libraries.

Thanks for pointing this out. I’ll use __attribute__ (noinline) for functions with static variables.

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2015-08-05 17:22 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-08-04 15:00 Explicit instantiation and static objects in different modules Nikolay Vorobyov
2015-08-04 15:45 ` Jonathan Wakely
2015-08-04 16:53   ` Alexander Monakov
2015-08-04 17:06     ` Jonathan Wakely
2015-08-04 17:32       ` Alexander Monakov
2015-08-05 17:22         ` Nikolay Vorobyov

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).