Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/Unity-Technologies/bdwgc.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHamayama <hamay1010@gmail.com>2019-02-08 00:51:25 +0300
committerJonathan Chambers <jonathan@unity3d.com>2022-03-16 20:49:48 +0300
commitbe26f03dee11d1d5ee04940dc6e4ac5d02e06922 (patch)
tree22e52632a2deb9c5cb795fc0aa7c9d434e20c6b1
parentb8a4d0dfcd7545e2a422237db0af75f72cf10e96 (diff)
Fix GetThreadContext stale register values use if WoW64 (Win32)
Issue #262 (bdwgc). * misc.c [MSWIN32 && !MSWINRT_FLAVOR && !MSWIN_XBOX1] (GC_win32_MessageBoxA): Do not define unless SMALL_CONFIG. * misc.c [MSWIN32 && !_WIN64 && GC_WIN32_THREADS && CHECK_NOT_WOW64] (GC_init): Do not call IsWow64Process() and GC_win32_MessageBoxA(). * win32_threads.c [I386] (isWow64): New static variable. * win32_threads.c [I386] (GC_push_stack_for): If isWow64 then set also CONTEXT_EXCEPTION_REQUEST and CONTEXT_SEGMENTS bits in ContextFlags; if isWow64, and CONTEXT_EXCEPTION_REPORTING and CONTEXT_EXCEPTION_ACTIVE are set on return from GetThreadContext then call GetThreadSelectorEntry and use StackLimit of FS selector to set sp local variable (instead of context.Esp); add comment. * win32_threads.c [I386 && DEBUG_THREADS] (GC_push_stack_for): Call GC_log_printf() to report TIB stack limit/base and the case when CONTEXT_EXCEPTION_REQUEST is not supported. * win32_threads.c [I386] (GC_thr_init): Set isWow64 by IsWow64Process() if the later is available.
-rw-r--r--misc.c29
-rw-r--r--win32_threads.c79
2 files changed, 78 insertions, 30 deletions
diff --git a/misc.c b/misc.c
index f312352b..54ff79fb 100644
--- a/misc.c
+++ b/misc.c
@@ -812,9 +812,8 @@ GC_API int GC_CALL GC_is_init_called(void)
}
#endif
-#if defined(MSWIN32) && !defined(MSWINRT_FLAVOR) && (!defined(SMALL_CONFIG) \
- || (!defined(_WIN64) && defined(GC_WIN32_THREADS) \
- && defined(CHECK_NOT_WOW64))) && !defined(_XBOX_ONE)
+#if defined(MSWIN32) && !defined(MSWINRT_FLAVOR) && !defined(MSWIN_XBOX1) \
+ && !defined(SMALL_CONFIG)
STATIC void GC_win32_MessageBoxA(const char *msg, const char *caption,
unsigned flags)
{
@@ -902,30 +901,6 @@ GC_API void GC_CALL GC_init(void)
initial_heap_sz = MINHINCR * HBLKSIZE;
# endif
-# if defined(MSWIN32) && !defined(_WIN64) && defined(GC_WIN32_THREADS) \
- && defined(CHECK_NOT_WOW64) && !defined(_XBOX_ONE)
- {
- /* Windows: running 32-bit GC on 64-bit system is broken! */
- /* WoW64 bug affects SuspendThread, no workaround exists. */
- HMODULE hK32 = GetModuleHandle(TEXT("kernel32.dll"));
- if (hK32) {
- FARPROC pfn = GetProcAddress(hK32, "IsWow64Process");
- BOOL bIsWow64 = FALSE;
- if (pfn
- && (*(BOOL (WINAPI*)(HANDLE, BOOL*))pfn)(GetCurrentProcess(),
- &bIsWow64)
- && bIsWow64) {
- GC_win32_MessageBoxA("This program uses BDWGC garbage collector"
- " compiled for 32-bit but running on 64-bit Windows.\n"
- "This is known to be broken due to a design flaw"
- " in Windows itself! Expect erratic behavior...",
- "32-bit program running on 64-bit system",
- MB_ICONWARNING | MB_OK);
- }
- }
- }
-# endif
-
DISABLE_CANCEL(cancel_state);
/* Note that although we are nominally called with the */
/* allocation lock held, the allocation lock is now */
diff --git a/win32_threads.c b/win32_threads.c
index 252335cd..a3f02158 100644
--- a/win32_threads.c
+++ b/win32_threads.c
@@ -1410,6 +1410,10 @@ static GC_bool may_be_in_stack(ptr_t s)
&& !(last_info.Protect & PAGE_GUARD);
}
+#if defined(I386)
+ static BOOL isWow64; /* Is running 32-bit code on Win64? */
+#endif
+
STATIC word GC_push_stack_for(GC_thread thread, DWORD me)
{
ptr_t sp, stack_min;
@@ -1422,8 +1426,25 @@ STATIC word GC_push_stack_for(GC_thread thread, DWORD me)
} else if ((sp = thread -> thread_blocked_sp) == NULL) {
/* Use saved sp value for blocked threads. */
/* For unblocked threads call GetThreadContext(). */
- /* we cache context when suspending the thread since it may require looping */
- CONTEXT context = thread->saved_context;
+ CONTEXT context;
+# if defined(I386)
+# ifndef CONTEXT_EXCEPTION_ACTIVE
+# define CONTEXT_EXCEPTION_ACTIVE 0x08000000
+# define CONTEXT_EXCEPTION_REQUEST 0x40000000
+# define CONTEXT_EXCEPTION_REPORTING 0x80000000
+# endif
+
+ if (isWow64) {
+ context.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL
+ | CONTEXT_EXCEPTION_REQUEST
+ | CONTEXT_SEGMENTS;
+ } else
+# endif
+ /* else */ {
+ context.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL;
+ }
+ if (!GetThreadContext(THREAD_HANDLE(thread), &context))
+ ABORT("GetThreadContext failed");
/* Push all registers that might point into the heap. Frame */
/* pointer registers are included in case client code was */
@@ -1433,7 +1454,45 @@ STATIC word GC_push_stack_for(GC_thread thread, DWORD me)
# define PUSH4(r1,r2,r3,r4) (PUSH2(r1,r2), PUSH2(r3,r4))
# if defined(I386)
PUSH4(Edi,Esi,Ebx,Edx), PUSH2(Ecx,Eax), PUSH1(Ebp);
- sp = (ptr_t)context.Esp;
+ /* WoW64 workaround. */
+ if (isWow64
+ && (context.ContextFlags & CONTEXT_EXCEPTION_REPORTING) != 0
+ && (context.ContextFlags & (CONTEXT_EXCEPTION_ACTIVE
+ /* | CONTEXT_SERVICE_ACTIVE */)) != 0) {
+ LDT_ENTRY selector;
+ PNT_TIB tib;
+
+ if (!GetThreadSelectorEntry(THREAD_HANDLE(thread), context.SegFs,
+ &selector))
+ ABORT("GetThreadSelectorEntry failed");
+ tib = (PNT_TIB)(selector.BaseLow
+ | (selector.HighWord.Bits.BaseMid << 16)
+ | (selector.HighWord.Bits.BaseHi << 24));
+ /* GetThreadContext() might return stale register values, so */
+ /* we scan the entire stack region (down to the stack limit). */
+ /* There is no 100% guarantee that all the registers are pushed */
+ /* but we do our best (the proper solution would be to fix it */
+ /* inside Windows OS). */
+ sp = (ptr_t)tib->StackLimit;
+# ifdef DEBUG_THREADS
+ GC_log_printf("TIB stack limit/base: %p .. %p\n",
+ (void *)tib->StackLimit, (void *)tib->StackBase);
+# endif
+ GC_ASSERT(!((word)thread->stack_base
+ COOLER_THAN (word)tib->StackBase));
+ } else {
+# ifdef DEBUG_THREADS
+ {
+ static GC_bool logged;
+ if (isWow64 && !logged
+ && (context.ContextFlags & CONTEXT_EXCEPTION_REPORTING) == 0) {
+ GC_log_printf("CONTEXT_EXCEPTION_REQUEST not supported\n");
+ logged = TRUE;
+ }
+ }
+# endif
+ sp = (ptr_t)context.Esp;
+ }
# elif defined(X86_64)
PUSH4(Rax,Rcx,Rdx,Rbx); PUSH2(Rbp, Rsi); PUSH1(Rdi);
PUSH4(R8, R9, R10, R11); PUSH4(R12, R13, R14, R15);
@@ -2466,6 +2525,20 @@ GC_INNER void GC_thr_init(void)
}
# endif
+# if defined(I386)
+ /* Set isWow64 flag. */
+ {
+ HMODULE hK32 = GetModuleHandle(TEXT("kernel32.dll"));
+ if (hK32) {
+ FARPROC pfn = GetProcAddress(hK32, "IsWow64Process");
+ if (pfn
+ && !(*(BOOL (WINAPI*)(HANDLE, BOOL*))pfn)(GetCurrentProcess(),
+ &isWow64))
+ isWow64 = FALSE; /* IsWow64Process failed */
+ }
+ }
+# endif
+
/* Add the initial thread, so we can stop it. */
# ifdef GC_ASSERTIONS
sb_result =