From: Jinoh Kang jinoh.kang.kr@gmail.com
Today, NtCurrentTeb() has a single asm statement when compiling for the i386, x86-64, or ARM architecture with GCC. This single asm statement has neither the "volatile" qualifier nor the "memory" clobber.
This can provoke undefined behavior if the current TEB changes between NtCurrentTeb() calls. This is because GCC assumes that the asm statement does not depend on memory or the thread-local register. In fact, given the same address of the "teb" variable, GCC assumes that the asm statement produces exactly the same value on every invocaton.
This primarily causes issues when switching to another fiber from a thread that is different from the thread on which the fiber was last executed. Theoretically, however, this may also cause issues when the optimizer aliases the "teb" variable to another variable that is shared between threads, and perform global optimization that can work across multiple threads in runtime (if any).
Fix this by adding the "memory" clobber to the asm statements that computes the current TEB address. --- include/winnt.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/include/winnt.h b/include/winnt.h index 66f6b7ad809..97a9deac21d 100644 --- a/include/winnt.h +++ b/include/winnt.h @@ -2238,7 +2238,7 @@ struct _TEB; static FORCEINLINE struct _TEB * WINAPI NtCurrentTeb(void) { struct _TEB *teb; - __asm__(".byte 0x64\n\tmovl (0x18),%0" : "=r" (teb)); + __asm__(".byte 0x64\n\tmovl (0x18),%0" : "=r" (teb) :: "memory"); return teb; } #elif defined(__i386__) && defined(_MSC_VER) && !defined(WINE_UNIX_LIB) @@ -2253,7 +2253,7 @@ static FORCEINLINE struct _TEB * WINAPI NtCurrentTeb(void) static FORCEINLINE struct _TEB * WINAPI NtCurrentTeb(void) { struct _TEB *teb; - __asm__(".byte 0x65\n\tmovq (0x30),%0" : "=r" (teb)); + __asm__(".byte 0x65\n\tmovq (0x30),%0" : "=r" (teb) :: "memory"); return teb; } #elif defined(__x86_64__) && defined(_MSC_VER) && !defined(WINE_UNIX_LIB) @@ -2267,7 +2267,7 @@ static FORCEINLINE struct _TEB * WINAPI NtCurrentTeb(void) static FORCEINLINE struct _TEB * WINAPI NtCurrentTeb(void) { struct _TEB *teb; - __asm__("mrc p15, 0, %0, c13, c0, 2" : "=r" (teb)); + __asm__("mrc p15, 0, %0, c13, c0, 2" : "=r" (teb) :: "memory"); return teb; } #elif defined(__arm__) && defined(_MSC_VER) && !defined(WINE_UNIX_LIB)