Bug 52477

Summary: Wrong initialization order? __attribute__((constructor)) vs static data access
Product: gcc Reporter: Przemysław Pawełczyk <przemoc>
Component: c++Assignee: Not yet assigned to anyone <unassigned>
Status: NEW ---    
Severity: major CC: iains, jason, marxin, msebor, pawel_sikora, ro, webrown.cpp
Priority: P3    
Version: 4.7.0   
Target Milestone: ---   
Host: Target:
Build: Known to work:
Known to fail: Last reconfirmed: 2017-03-16 00:00:00
Attachments: Short exemplary code showing the problem

Description Przemysław Pawełczyk 2012-03-04 12:50:09 UTC
Created attachment 26821 [details]
Short exemplary code showing the problem

Attached file compiles flawlessly on 4.7.0, but the output binary segfaults. Works fine in 4.6.2 though (as expected).

Looks like a serious regression.

g++-4.7 (GCC) 4.7.0 20120304 (prerelease)
built on debian wheezy x64 with:
--enable-languages=c,c++ --prefix=/opt/gcc-4.7 --program-suffix=-4.7

svn+ssh://gcc.gnu.org/svn/gcc/branches/gcc-4_7-branch@184878
Comment 1 Pawel Sikora 2012-03-04 13:54:09 UTC
looks like .init_array vs. .ctors problem.
Comment 2 Pawel Sikora 2012-03-04 14:16:29 UTC
you should specify explicit initialization order to avoid gpf, e.g.:

static std::map<int, int> m __attribute__((init_priority(101)));
static void insert() __attribute__((constructor(102)));
Comment 3 Przemysław Pawełczyk 2012-03-04 14:24:10 UTC
Thanks for solution, but...

Isn't such order obvious or isn't it at least the most widely used one? I mean that by default static data initialization should precede constructor-functions, no? It worked in gcc 4.6 and is there any good reason to break it?
Comment 4 Richard Biener 2012-03-05 10:20:37 UTC
I think it's undefined what you relied upon.
Comment 5 Martin Sebor 2017-03-15 23:00:48 UTC
Resolving as invalid based on comment #3.  The manual does seem to suggest that this should work:

   "The priorities for constructor and destructor functions are the same as those specified for namespace-scope C++ objects (see C++ Attributes)."

Let me add a blurb to make clear that the order between C++ ctors and functions declared attribute constructor is unspecified.

Blurb posted for review:
https://gcc.gnu.org/ml/gcc-patches/2017-03/msg00863.html
Comment 6 Jason Merrill 2017-03-16 04:46:52 UTC
I don't think this is undefined; it seems natural for these functions to be ordered with a translation unit along with dynamic initialization of non-local variables.  So for

---
extern "C" int printf (const char *, ...);

struct A { A() { printf ("A\n"); } } a;

static void B() __attribute__((constructor));
static void B()
{
  printf ("B\n");
}

struct C { C() { printf ("C\n"); } } c;

int main() {}
---

I would expect A B C, and gcc currently outputs B A C.  Instead of emitting constructor functions directly into .init_array as we do now, we should remember them and call them from __static_initialization_and_destruction_0.

Note that 4.6 gave the differently wrong A C B, due to running .init_array in the opposite order, so this isn't really a regression.
Comment 7 Martin Sebor 2017-03-20 18:34:03 UTC
Author: msebor
Date: Mon Mar 20 18:33:31 2017
New Revision: 246288

URL: https://gcc.gnu.org/viewcvs?rev=246288&root=gcc&view=rev
Log:
PR c++/52477 - Wrong initialization order __attribute__((constructor)) vs static data access

* doc/extend.texi (attribute constructor): Document present limitation.

Modified:
    trunk/gcc/ChangeLog
    trunk/gcc/doc/extend.texi
Comment 8 Martin Sebor 2017-03-20 18:35:47 UTC
r246288 updates the manual for GCC 7 and documents the limitation (as per commetn #6) but the issue itself remains unresolved.
Comment 9 Martin Liška 2017-08-10 19:12:49 UTC
*** Bug 81337 has been marked as a duplicate of this bug. ***
Comment 10 Martin Liška 2017-08-10 19:13:38 UTC
I will try to look at it.
Comment 11 Rainer Orth 2018-02-01 10:24:49 UTC
(In reply to Martin Liška from comment #10)
> I will try to look at it.

Do you see a chance to look at this before GCC 8?

Thanks.
  Rainer
Comment 12 Martin Liška 2018-02-13 08:24:48 UTC
(In reply to Rainer Orth from comment #11)
> (In reply to Martin Liška from comment #10)
> > I will try to look at it.
> 
> Do you see a chance to look at this before GCC 8?
> 
> Thanks.
>   Rainer

I'm sorry but probably after the release in next stage1.
Comment 13 Martin Liška 2018-08-16 10:31:26 UTC
Well, after we documented that can we simply close it?
Comment 14 Rainer Orth 2018-08-16 11:30:42 UTC
(In reply to Martin Liška from comment #13)
> Well, after we documented that can we simply close it?

Quite the contrary: that documents a *current* limitation!  See Jason's comment #6
for what needs to happen.
Comment 15 Martin Liška 2018-08-16 11:44:36 UTC
(In reply to Rainer Orth from comment #14)
> (In reply to Martin Liška from comment #13)
> > Well, after we documented that can we simply close it?
> 
> Quite the contrary: that documents a *current* limitation!  See Jason's
> comment #6
> for what needs to happen.

I see, thanks for clarification.
Comment 16 Martin Liška 2018-10-03 13:34:28 UTC
Leaving for now..
Comment 17 Iain Sandoe 2019-07-26 07:53:09 UTC
(In reply to Jason Merrill from comment #6)

I was looking into this area trying to diagnose/solve a testsuite fail on Darwin (see pr91087).

> 
> I would expect A B C, and gcc currently outputs B A C.

I assume that's because the SysV ABI says:
"Termination functions specified by users via the atexit mechanism must be executed before any termination functions of shared objects.” 

and, therefore (for PIC at least) we would get incorrect nesting of CTORs and DTORs if the __attribute__((constructor)) was not run first.

>  Instead of emitting
> constructor functions directly into .init_array as we do now, we should
> remember them and call them from __static_initialization_and_destruction_0.

Implementing this would probably also provide a workaround for the Darwin bug (by avoiding the use of special sections for the attributed ctor/dtors.

Is there any specification that demands a specific section for the __attribute__((constructor/destructor))s?