[Bug 23757] Free Pascal 2.4.0 segfaults (Cygwin 1.5.18 TLS implementation overwrites Wine/glibc/pthread data near Tib->StackBase)

wine-bugs at winehq.org wine-bugs at winehq.org
Sun Dec 14 16:40:17 CST 2014


https://bugs.winehq.org/show_bug.cgi?id=23757

Anastasius Focht <focht at gmx.net> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |focht at gmx.net
            Summary|Free Pascal 2.4.0 segfaults |Free Pascal 2.4.0 segfaults
                   |                            |(Cygwin 1.5.18 TLS
                   |                            |implementation overwrites
                   |                            |Wine/glibc/pthread data
                   |                            |near Tib->StackBase)

--- Comment #14 from Anastasius Focht <focht at gmx.net> ---
Hello folks,

confirming, Wine still core dumps which is of course a serious matter.

Tracing is useless here because the app - or rather Cygwin - really messes with
things at low level, making even debugging hard.

I found some references hinting at Cygwin version cygwin-1.5.18-1 (the
'cygwin1.dll' is from 2005-19-12).

It core dumps on a secondary thread creation.

--- snip ---
61002F43    894424 08       MOV DWORD PTR SS:[ESP+8],EAX
61002F47    31C0            XOR EAX,EAX
61002F49    894424 04       MOV DWORD PTR SS:[ESP+4],EAX
61002F4D    C70424 D8910E61 MOV DWORD PTR SS:[ESP],610E91D8
61002F54    E8 97D30D00     CALL <JMP.&KERNEL32.CreateThread>
...

00CAED2C  610E91D8  ; pSecurity = cygwin1.610E91D8 -> SECURITY_ATTRIBUTES
{Length=12., pSecurityDescriptor=NULL, InheritHandle=FALSE}
00CAED30  00000000  ; StackSize = 0
00CAED34  61003160  ; StartAddress = cygwin1.61003160
00CAED38  610E6D18  ; Parameter = 610E6D18
00CAED3C  00000000  ; CreationFlags = 0
00CAED40  610E6D1C  ; pThreadId = cygwin1.610E6D1C -> 0
--- snip ---

The specified thread entry point is not immediately executed.
Instead, Cygwin injects a nifty thread entry wrapper with the help of 'thread
attach' notification from its 'dllmain' and really starts messing with things.

Starting at TIB StackBase, Cygwin uses a rather large chunk (~1 page) for the
implementation of some TLS concept.

https://sourceware.org/viewvc/src/winsup/cygwin/cygtls.cc?diff_format=h&view=markup&revision=1.38

https://sourceware.org/viewvc/src/winsup/cygwin/cygtls.h?diff_format=h&view=markup&revision=1.38

https://sourceware.org/viewvc/src/winsup/cygwin/sigproc.cc?diff_format=h&revision=1.266&view=markup

--- snip ---
extern exception_list *_except_list asm ("%fs:0");      // exceptions.cc
extern char *_tlsbase __asm__ ("%fs:4");                // cygtls.h
extern char *_tlstop __asm__ ("%fs:8");                 // cygtls.h

#define _my_tls (((_cygtls *) _tlsbase)[-1])            // cygtls.h
--- snip ---

tlsbase = fs:[4] -> Wine TIB StackBase

This stack area (~4K) is padded with zeros (memset).

On all secondary threads, Wine's 'debug_info' structure is partially located in
this stack area.
The main thread uses static storage for this.

http://source.winehq.org/git/wine.git/blob/2fcecdb72e11b7adb03dc797c2ccc60fcb487fcd:/dlls/ntdll/thread.c#l407

The same thing happens for the main thread, one page gets "zapped", destroying
everything that was there - without serious consequences (yet).

The reason for the core dump on secondary threads is indeed interesting ...

Debugging session, thread creation from the caller side ->
'RtlCreateUserThread':

http://source.winehq.org/git/wine.git/blob/2fcecdb72e11b7adb03dc797c2ccc60fcb487fcd:/dlls/ntdll/thread.c#l436

--- snip ---

Wine-dbg>p *info

{teb=0x7ffd0000, entry_point=0x61003160, entry_arg=0x610e6d18}

Wine-dbg>p teb->Tib

{ExceptionList=0xffffffff, StackBase=0x19270000, StackLimit=0x18f92000,
SubSystemTib=0x0(nil), u={FiberData=0x0(nil), Version=0},
ArbitraryUserPointer=0x0(nil), Self=0x7ffd0000}

Wine-dbg>p *thread_data

{dr0=0, dr1=0, dr2=0, dr3=0, dr6=0x4000, dr7=0, fs=0x63, gs=0x6b,
vm86_ptr=0x0(nil), debug_info=0x1926eb84, request_fd=0xc, reply_fd=0x9,
wait_fd={0x10, 0x11}, wow64_redir=0, pthread_id=0x1926fb40, vm86={dpmi_vif=0,
vm86_pending=0}, exit_frame=0x0(nil)}

Wine-dbg>x/10x 0x1926fb4c

0x1926fb4c:  00000000 00000000 00000000 00000000
0x1926fb5c:  00000000 00000000 00000000 00000000
0x1926fb6c:  00000000 00000000

Wine-dbg>n
543        if (pthread_create( &pthread_id, &attr, (void * (*)(void
*))start_thread, info ))

Wine-dbg>x/10x 0x1926fb4c
0x1926fb4c:  00000001 f7774420 41418100 bb4a20c1
0x1926fb5c:  00000000 00000000 00000000 00000000
0x1926fb6c:  00000000 00000000
--- snip ---

The data dumps of certain stack areas will be of importance later.
Just keep in mind that glibc/pthread library code puts internal data here.

Now debugging of the thread initialization from the other side.
'Winedbg' must be used in gdb proxy mode, otherwise the frame switch/locals 
won't yield results.
You can't break directly at 'start_thread' for obvious reasons.

--- snip ---
Wine-gdb> bt

#0  MODULE_DllThreadAttach (lpReserved=0x0) at
/home/focht/projects/wine/wine.repo/src/dlls/ntdll/loader.c:1275
#1  0x7bc8d4cc in start_thread (info=0x7ffd0fb8) at
/home/focht/projects/wine/wine.repo/src/dlls/ntdll/thread.c:424
#2  0xf75009dc in start_thread () from /lib/libpthread.so.0
#3  0xf7433a1e in clone () from /lib/libc.so.6

Wine-gdb> frame 1

#1  0x7bc8d4cc in start_thread (info=0x7ffd0fb8) at
/home/focht/projects/wine/wine.repo/src/dlls/ntdll/thread.c:424
429        call_thread_entry_point( (LPTHREAD_START_ROUTINE)func, arg );

Wine-gdb> info locals

teb = 0x7ffd0000
thread_data = 0x7ffd01bc
func = 0x61003160
arg = 0x610e6d18
debug_info = {str_pos = 0x1926eb8c "", out_pos = 0x1926ef8c "", strings =
'\000' <repeats 1023 times>, output = '\000' <repeats 1023 times>}
--- snip ---

I switched one stack frame up to show the address ranges being used at early
thread initialization stage.
The stack area in question spans [0x1926ebxx..0x1926ffff].

At later point, when the Cygwin thread entry wrapper runs, before switching to
the real entry point:

--- snip ---
Wine-dbg>x/10x 0x1926fb40

0x1926fb40:  1926fb40 7c49d5e0 1926fb40 00000001
0x1926fb50:  f7737420 72241200 98b073c0 00000000
0x1926fb60:  00000000 00000000

...

Wine-dbg>info reg

Register dump:
 CS:0023 SS:002b DS:002b ES:002b FS:0063 GS:006b
 EIP:610c4a77 ESP:1926da40 EBP:1926da48 EFLAGS:00010246(  R- --  I  Z- -P- )
 EAX:00000000 EBX:00000000 ECX:0000012d EDX:00000000
 ESI:1926f07c EDI:1926fb4c

Wine-dbg>si 

0x610c4a77: repe stosl    %es:(%edi)

Wine-dbg>si  

0x610c4a77: repe stosl    %es:(%edi)

Wine-dbg>
Process of pid=0022 has terminated
--- snip ---

0x1926fb40, 0x1926fb48 -> referencing 0x1926fb40 -> pthread_id
...
0x1926fb50 -> referencing 0xf7737420 -> syscall entry in VDSO page

--- snip ---
Wine-dbg>x/10i 0xf7737420

0xf7737420 __kernel_vsyscall in [vdso].so: pushl    %ecx
0xf7737421 __kernel_vsyscall+0x1 in [vdso].so: pushl    %edx
0xf7737422 __kernel_vsyscall+0x2 in [vdso].so: pushl    %ebp
0xf7737423 __kernel_vsyscall+0x3 in [vdso].so: movl    %esp,%ebp
0xf7737425 __kernel_vsyscall+0x5 in [vdso].so: sysenter    
0xf7737427 __kernel_vsyscall+0x7 in [vdso].so: nop    
--- snip ---

By overwriting everything until 'Tib->StackBase' with zero, Cygwin essentially
kills libc/pthread specific stack storage, causing the core dump.
SEH chain/__wine_exception_handler was already broken at this point, unable to
handle SIGSEGV for diagnostics.

Maybe Cygwin changed their implementation in more recent versions to work
differently given the code being 7+ years old.
That rather boring investigation is left as exercise to the interested reader.

To prove my analysis, I modified the call to 'pthread_attr_setstack()', making
it one page smaller than Wine allocated.
This moves the glibc/pthread internal data by one page and also Wine's
'debug_info' which lives below, avoiding Cygwin's TLS code to zap this area.
It makes the app work.

The application/GUI seems rather ancient, like a relict from old DOS times.
It requires wineconsole/ncurses backend.

$ sha1sum fpc-2.4.0.i386-win32.exe 
93b754bdc966e94fe002c624c275c4735e3551ab  fpc-2.4.0.i386-win32.exe

$ du -sh fpc-2.4.0.i386-win32.exe 
35M    fpc-2.4.0.i386-win32.exe
$ wine --version
wine-1.7.33

Regards

-- 
Do not reply to this email, post in Bugzilla using the
above URL to reply.
You are receiving this mail because:
You are watching all bug changes.



More information about the wine-bugs mailing list