| /** |
| * Testcase for https://github.com/mingw-w64/mingw-w64/issues/181: |
| * "Global constructors run twice when linking against -lgcc (since c3da0827)". |
| * |
| * This file is self-contained and can be built standalone: |
| * |
| * gcc -o t_global_ctors.exe t_global_ctors.c |
| * -> PASSED (global constructors run exactly once) |
| * |
| * gcc -o t_global_ctors.exe t_global_ctors.c -lgcc -static |
| * -> FAILED (global constructors run twice) -- reproduces the issue |
| * |
| * The trigger is the LINK ORDER: an explicit -lgcc placed AFTER this object |
| * file (but before the implicit -lmingw32) pulls in libgcc's __main.o, which |
| * provides its own __do_global_ctors / __do_global_dtors runners alongside the |
| * mingw-w64 runtime's __mingw_do_global_ctors / __mingw_do_global_dtors. Both |
| * walk __CTOR_LIST__ (and __DTOR_LIST__) with their own static cursors, so |
| * every global constructor (and destructor) is executed twice. Putting -lgcc |
| * BEFORE the object file does not reproduce the issue. |
| */ |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| |
| #ifndef WIN32_LEAN_AND_MEAN |
| #define WIN32_LEAN_AND_MEAN |
| #endif |
| #include <windows.h> |
| |
| /* mingw-w64 headers */ |
| #include "libtest.h" |
| |
| /* Counts how many times global constructors have been invoked. */ |
| static int ctor_count = 0; |
| |
| /* Counts how many times global destructors have been invoked. */ |
| static int dtor_count = 0; |
| |
| __attribute__((constructor)) |
| static void |
| ctor (void) |
| { |
| ctor_count++; |
| } |
| |
| __attribute__((destructor)) |
| static void |
| dtor (void) |
| { |
| dtor_count++; |
| if (dtor_count > 1) { |
| /* Global destructors were invoked more than once; abort() so that this is |
| * reported as a test failure (the exit code of main() has already been |
| * determined by the time global destructors run). */ |
| fprintf (stderr, "FAILED: global destructors were invoked %d times, expected 1\n", |
| dtor_count); |
| abort (); |
| } |
| } |
| |
| int |
| main (void) |
| { |
| mingw_test_init (); |
| |
| HMODULE lib = LoadLibraryA("libglbctors.dll"); |
| if (!lib) { |
| printf ("FAILED: Cannot load libglbctors.dll: %lu\n", GetLastError()); |
| return 1; |
| } |
| |
| int (*lib_get_count)(void); |
| lib_get_count = (typeof(lib_get_count))(void(*)(void))GetProcAddress(lib, "get_ctor_count"); |
| if (!lib_get_count) { |
| printf ("FAILED: Cannot resolve get_ctor_count: %lu\n", GetLastError()); |
| return 1; |
| } |
| |
| void (*lib_set_var)(int *var); |
| lib_set_var = (typeof(lib_set_var))(void(*)(void))GetProcAddress(lib, "set_dtor_count_var"); |
| if (!lib_set_var) { |
| printf ("FAILED: Cannot resolve set_dtor_count_var: %lu\n", GetLastError()); |
| return 1; |
| } |
| |
| int lib_ctor_count = lib_get_count(); |
| int lib_dtor_count = 0; |
| lib_set_var(&lib_dtor_count); |
| |
| if (lib_ctor_count != 1) { |
| printf ("FAILED: library constructors were invoked %d times, expected 1\n", |
| lib_ctor_count); |
| return 1; |
| } else { |
| printf ("PASSED: library constructors were invoked exactly once\n"); |
| } |
| |
| FreeLibrary(lib); |
| |
| if (lib_dtor_count != 1) { |
| printf ("FAILED: library destructors were invoked %d times, expected 1\n", |
| lib_dtor_count); |
| return 1; |
| } else { |
| printf ("PASSED: library destructors were invoked exactly once\n"); |
| } |
| |
| if (ctor_count != 1) { |
| printf ("FAILED: global constructors were invoked %d times, expected 1\n", |
| ctor_count); |
| return 1; |
| } |
| |
| printf ("PASSED: global constructors were invoked exactly once\n"); |
| return 0; |
| } |