[Bug lto/107708] New: LTO causes gnu::constructor functions to not be called with correct arguments if there is more than one constructor

cfsteefel at arista dot com gcc-bugzilla@gcc.gnu.org
Tue Nov 15 19:14:23 GMT 2022


https://gcc.gnu.org/bugzilla/show_bug.cgi?id=107708

            Bug ID: 107708
           Summary: LTO causes gnu::constructor functions to not be called
                    with correct arguments if there is more than one
                    constructor
           Product: gcc
           Version: 11.3.1
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: lto
          Assignee: unassigned at gcc dot gnu.org
          Reporter: cfsteefel at arista dot com
                CC: marxin at gcc dot gnu.org
  Target Milestone: ---

When a function is marked with the constructor attribute, if there is more than
one function marked with the constructor attribute, the function's arguments
are not passed when LTO inlines the function into DT_INIT_ARRAY. If LTO is
disabled, the function will instead be passed argc, argv, and envp by glibc
(other libc implementation may or may not pass anything).

See the following code:
#include <iostream>
namespace {
int c;
char ** a;
[[ gnu::constructor ]]
void foo( int argc, char ** argv ) {
   a = argv;
   c = argc;
}

[[ gnu::constructor ]]
void bar( int argc, char ** argv ) {
   asm( "" );
}
}

int main() {
   std::cerr << "argc: " << c << std::endl;
   std::cerr << std::hex << a << std::endl;

   return 0;
}


When compiled and run as:
> g++ text.cpp -g -shared -o libMain.so -fPIC -O2 -flto -Wall -Wextra
> g++ libMain.so
> LD_LIBRARY_PATH=. ./a.out 4 1 2 4
A sample output is:
argc: -638171435
0x7f20366efdd0

(the use of cerr is only meaningful for actually seeing output, and is not
needed to reproduce the error)

Using a specific and unique priority for the `gnu::constructor` attribute will
lead to the arguments being passed correctly, and argc will end up correct.

If the function is instead not defined inside an anonymous namespace, as just:

int c;
char ** a;
[[ gnu::constructor ]]
void foo( int argc, char ** argv ) {
   a = argv;
   c = argc;
}
g++ instead reports the error (using -Wall -Wextra):
In function '_sub_I_65535_0':
text.cpp:8:6: warning: 'argv' is used uninitialized [-Wuninitialized]
    8 |    a = argv;
      |      ^
lto1: note: 'argv' was declared here
text.cpp:9:6: warning: 'argc' is used uninitialized [-Wuninitialized]
    9 |    c = argc;
      |      ^
lto1: note: 'argc' was declared here

Using a unique constructor priority again will disable that warning.

g++ (GCC) 11.3.1 20220421 (Red Hat 11.3.1-2)
glibc 2.34


More information about the Gcc-bugs mailing list