blob: 3befaf4520b7e4aef4884185647267462cb4ea93 [file]
#include <assert.h>
#include <stddef.h>
#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"
extern int __cdecl __tlregdtor(void (__cdecl*func)(void));
/* Tentative symbol __mingw_register_thread_local_exe_atexit_callback_ptr is
* mingw-w64 internal symbol only for EXE applications. It is non-NULL if the
* EXE application is using __tlregdtor.
*/
void (__cdecl *const __mingw_register_thread_local_exe_atexit_callback_ptr)(void) __attribute__((common)); /* tentative */
static int thread_dtor_counter = 0;
static int process_dtor_counter = 0;
static void __cdecl thread_dtor_callback(void)
{
thread_dtor_counter++;
}
static void __cdecl process_dtor_callback(void)
{
if (process_dtor_counter != 0) {
printf("Error after main: dtor TLS callback on main process thread was called more times\n");
/* exit, _exit, or ExitProcess calls TLS callbacks, so use TerminateProcess() which is not calling them */
TerminateProcess(GetCurrentProcess(), 1);
}
process_dtor_counter++;
}
#if defined(__i386__)
/* We need to make sure that we align the stack to 16 bytes for the sake of SSE */
__attribute__((force_align_arg_pointer))
#endif
static DWORD WINAPI thread_main(LPVOID user_data __attribute__((unused)))
{
/* Register thread_dtor_callback as oneshot dtor TLS callback */
if (__tlregdtor(&thread_dtor_callback) != 0) {
printf("Error: __tlregdtor() on second thread failed\n");
return 1;
}
return 0;
}
int main(void)
{
mingw_test_init();
/* Asserts that PE image is valid for parsing DataDirectory[] */
extern IMAGE_DOS_HEADER __ImageBase;
assert(__ImageBase.e_magic == IMAGE_DOS_SIGNATURE);
IMAGE_NT_HEADERS *nt_headers = (IMAGE_NT_HEADERS *)((BYTE *)&__ImageBase + __ImageBase.e_lfanew);
assert(nt_headers->Signature == IMAGE_NT_SIGNATURE);
assert(nt_headers->FileHeader.SizeOfOptionalHeader >= offsetof(IMAGE_OPTIONAL_HEADER, DataDirectory));
assert(nt_headers->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR_MAGIC);
assert(nt_headers->FileHeader.SizeOfOptionalHeader >= offsetof(IMAGE_OPTIONAL_HEADER, DataDirectory[nt_headers->OptionalHeader.NumberOfRvaAndSizes]));
int ret = 0;
if (nt_headers->OptionalHeader.NumberOfRvaAndSizes <= IMAGE_DIRECTORY_ENTRY_TLS ||
nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size == 0 ||
nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress == 0) {
printf("Error: Missing PE TLS section\n");
ret = 1;
} else {
printf("PE TLS section is present\n");
}
if (!__mingw_register_thread_local_exe_atexit_callback_ptr) {
printf("Error: __mingw_register_thread_local_exe_atexit_callback_ptr is NULL\n");
ret = 1;
}
if (_osplatform == VER_PLATFORM_WIN32_WINDOWS) {
printf("PE TLS callbacks are not supported on Win9x\n");
if (ret)
return ret;
return 77;
}
/* Register process_dtor_callback as oneshot dtor TLS callback */
if (__tlregdtor(&process_dtor_callback) != 0) {
printf("Error: __tlregdtor() on main process thread failed\n");
ret = 1;
}
printf("Creating new thread\n");
HANDLE thread = CreateThread(NULL, 0, thread_main, NULL, 0, &(DWORD){0} /*out: ThreadId*/);
if (!thread) {
if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) {
printf("Error: failed: %lu\n", GetLastError());
ret = 1;
} else {
printf("Skipped: not supported\n");
}
} else {
DWORD tret;
WaitForSingleObject(thread, INFINITE);
GetExitCodeThread(thread, &tret);
CloseHandle(thread);
if (tret) {
printf("Error: thread failed\n");
ret = 1;
}
if (thread_dtor_counter != 1) {
printf("Error: dtor TLS callback on second thread was not called\n");
ret = 1;
} else {
printf("dtor TLS callback on second thread was called\n");
}
}
if (process_dtor_counter != 0) {
printf("Error: dtor TLS callback on main process thread was called before exiting process\n");
ret = 1;
}
if (ret) printf("FAILED\n"); else printf("PASSED\n");
return ret;
}