; ModuleID = 'main.ll'
source_filename = "main.ll"
target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-pc-windows-msvc19.37.32825"
@.StringLiteral0 = private unnamed_addr constant [3 x i8] c"D\0A\00", align 1
@llvm.global_dtors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @cleanup, ptr null }]
declare i32 @printf(ptr, ...)
define void @cleanup() {
entry:
call i32 (ptr, ...) @printf(ptr @.StringLiteral0)
ret void
}
define i32 @main() {
entry:
; call void @cleanup()
ret i32 0
}
This code is a minimal reproducible example of a code that is supposed to call the destructors of global objects on program termination. Since there might be more than one source file to be linked together, there is a cleanup
function, in which the destructors of all global variables will be called. All cleanup
functions across all files will be appended to the @llvm.global_dtors
array and will be called at the end of the program.
This is not what happens, however. This code results in a segmentation fault.
When I compile it and run it in lldb
, I get the following backtrace:
(lldb) Process 13320 stopped
* thread #1, stop reason = Exception 0xc0000005 encountered at address 0x7ff860fa3aca: Access violation writing location 0x00000024
frame #0: 0x00007ff860fa3aca ntdll.dll`TpWorkOnBehalfClearTicket + 394
ntdll.dll`TpWorkOnBehalfClearTicket:
-> 0x7ff860fa3aca <+394>: incl 0x24(%rax)
0x7ff860fa3acd <+397>: movq 0x18(%rdi), %r12
0x7ff860fa3ad1 <+401>: leaq 0x10(%rdi), %rsi
0x7ff860fa3ad5 <+405>: movq %r12, -0x19(%rbp)
(lldb) bt
error: a.exe :: Class '__crt_cached_ptd_host::cached<int>::guard' has a member '_copy' of type '__crt_cached_ptd_host::cached<int>' which does not have a complete definition.
(lldb) * thread #1, stop reason = Exception 0xc0000005 encountered at address 0x7ff860fa3aca: Access violation writing location 0x00000024
* frame #0: 0x00007ff860fa3aca ntdll.dll`TpWorkOnBehalfClearTicket + 394
frame #1: 0x00007ff860f918e4 ntdll.dll`RtlEnterCriticalSection + 596
frame #2: 0x00007ff860f916d2 ntdll.dll`RtlEnterCriticalSection + 66
frame #3: 0x00007ff6fd3a5761 a.exe`static int __crt_seh_guarded_call<int>::operator(this=0x00007ff6fd4150c8, setup=<unavailable>, setup=0x00000217c1b1aa60, action=0x00000084294ff5c0, action=<unavailable>, action=0x002d0064006c0069, cleanup=0x00000084294ff5b0, cleanup=<unavailable>, cleanup=0x00000084294ff5b0)<<lambda_d854c62834386a3b23916ad6dae2782d>,<lambda_303760bc4008a2b3ec4768a30b06a80c> &,<lambda_4780a7ea4f8cbd2590aec34bd14e2bbf> >(class __acrt_lock_stream_and_call::__l2::<lambda_d854c62834386a3b23916ad6dae2782d> *, class common_vfprintf::__l2::<lambda_303760bc4008a2b3ec4768a30b06a80c> & const, class __acrt_lock_stream_and_call::__l2::<lambda_4780a7ea4f8cbd2590aec34bd14e2bbf> *) at internal_shared.h:201
frame #4: 0x00007ff6fd3cf41a a.exe`__stdio_common_vfprintf(options=<unavailable>, options=<unavailable>, stream=<unavailable>, stream=<unavailable>, format=<unavailable>, format=<unavailable>, locale=<unavailable>, locale=<unavailable>, arglist="", arglist=" \xff?\xfd\xf6\U0000007f") at output.cpp:61
frame #5: 0x00007ff6fd39e789 a.exe`printf(_Format=<unavailable>, _Format=<unavailable>, _Format="D\n") at stdio.h:960
frame #6: 0x00007ff6fd387240 a.exe`cleanup + 16
frame #7: 0x00007ff6fd3a0abd a.exe`_initterm(first=<unavailable>, first=<unavailable>, last=<unavailable>, last=0x00007ff6fd3fff20, last=<unavailable>) at initterm.cpp:21
frame #8: 0x00007ff6fd3a0d2c a.exe`static void <lambda_6e4b09c48022b2350581041d5f6b0c4c>::operator(this=0x0000000000000fa0)() at exit.cpp:242
frame #9: 0x00007ff6fd3a0b6d a.exe`static void __crt_seh_guarded_call<void>::operator(this=0x0000000000000000, setup=<unavailable>, setup=0x0000000000000000, action=0x00000084294ff768, action=<unavailable>, action=0x02100800000906ea, cleanup=0x00000084294ff754, cleanup=<unavailable>, cleanup=0x00000084294ff754)<<lambda_d80eeec6fff315bfe5c115232f3240e3>,<lambda_6e4b09c48022b2350581041d5f6b0c4c> &,<lambda_2358e3775559c9db80273638284d5e45> >(class __acrt_lock_and_call::__l2::<lambda_d80eeec6fff315bfe5c115232f3240e3> *, class common_exit::__l2::<lambda_6e4b09c48022b2350581041d5f6b0c4c> & const, class __acrt_lock_and_call::__l2::<lambda_2358e3775559c9db80273638284d5e45> *) at internal_shared.h:224
frame #10: 0x00007ff6fd3a0ea3 a.exe`static void common_exit(return_code=<unavailable>, return_code=693105488, return_code=693105488, cleanup_mode=<unavailable>, cleanup_mode=<unavailable>, cleanup_mode=_crt_exit_full_cleanup, return_mode=<unavailable>, return_mode=<unavailable>, return_mode=_crt_exit_terminate_process) at exit.cpp:195
frame #11: 0x00007ff6fd389d93 a.exe`static int __scrt_common_main_seh() at exe_common.inl:295
frame #12: 0x00007ff85f1b257d kernel32.dll`BaseThreadInitThunk + 29
frame #13: 0x00007ff860fcaa58 ntdll.dll`RtlUserThreadStart + 40
When I comment this line:
@llvm.global_dtors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @cleanup, ptr null }]
and uncomment this line:
; call void @cleanup()
or in other words, when I run the cleanup
function manually at the end of the main function and get rid of the @llvm.global_dtors
array, the program works as intended.
This error happens only on Windows. The same code works as intended on Linux.