http://bugs.winehq.org/show_bug.cgi?id=10467
--- Comment #55 from Anastasius Focht focht@gmx.net 2008-03-26 17:49:05 --- Hello,
--- quote --- StackLimit is supposed to point above the guard page, it's the start of the valid area (and yes there are apps that depend on this). So if .NET starts looking from StackLimit, creating a Windows-style guard page is not going to help. --- quote ---
As I already explained, there is currently no other way - there has to be a PAGE_GUARD page between StackLimit and current thread stack addr (< StackBase).
I illustrate the problem for other interested people a bit more...
Consider the following common scenario...
--- memory map for typical PE ---
address size contains type mapped as 00240000 00001000 guard page private (no access) 00241000 0010F000 main thread stack private read-write .. 00400000 00001000 PE header image read-write-copy 00401000 00047000 .text (code,imports) image read-write-copy 00448000 00007000 .rsrc (data, res) image read-write-copy 0044F000 00001000 image read-write-copy 00450000 00001000 .reloc (relocations) image read-write-copy .. --- memory map for typical PE ---
stack_lower_bound == 0x240000 == NtCurrentTeb()->DeallocationStack
--- retrieve lower stack bound --- MEMORY_BASIC_INFORMATION info; DWORD addr; VirtualQuery( &addr, &info, sizeof(MEMORY_BASIC_INFORMATION)); --- retrieve lower stack bound ---
offset value comment $+00 0034F000 BaseAddress $+04 00240000 AllocationBase $+08 00000004 AllocationProtect $+0C 00001000 RegionSize $+10 00001000 State $+14 00000004 Protect $+18 00020000 Type
stack_lower_bound = info.AllocationBase;
stack_base = NtCurrentTeb()->Tib.StackBase; ( == 0x350000)
--- retrieve stack base --- mov eax, large fs:[18h] ; NtCurrentTeb() mov eax, [eax+4] ; NtCurrentTeb()->Tib.StackBase --- retrieve stack base ---
guard page search algorithm (TRUE = found):
--- algorithm to search for guard page ---
search_start_addr = NtCurrentTeb()->Tib.StackLimit (= stack_lower_bound + page_size) == 0x241000 (page_size = 0x1000 for x86)
{ addr = search_start_addr; while( addr < stack_base) { VirtualQuery( addr, &info, sizeof(MEMORY_BASIC_INFORMATION)); if( info.Protect & PAGE_GUARD) return TRUE; addr += info.RegionSize; } return FALSE; }
--- algorithm to search for guard page ---
From first iteration:
offset value comment $+00 00241000 BaseAddress $+04 00240000 AllocationBase $+08 00000004 AllocationProtect $+0C 0010F000 RegionSize $+10 00001000 State $+14 00000004 Protect $+18 00020000 Type
Trace snippet of .NET 2.0 app (C++ -> managed exception transition + unwinding):
--- snip trace --- .. 003d:Call KERNEL32.RaiseException(e06d7363,00000001,00000003,0033e28c) ret=78158dd3 003d:trace:seh:raise_exception code=e06d7363 flags=1 addr=0x7b8419a0 003d:trace:seh:raise_exception info[0]=19930520 003d:trace:seh:raise_exception info[1]=0033e300 003d:trace:seh:raise_exception info[2]=79f9acc4 003d:trace:seh:raise_exception eax=7b82c3e9 ebx=7b8af3a4 ecx=00000000 edx=0033e278 esi=0033e278 edi=0033e1f0 003d:trace:seh:raise_exception ebp=0033e1d8 esp=0033e174 cs=0073 ds=007b es=007b fs=0033 gs=003b flags=00000216 .. 003d:Call KERNEL32.RaiseException(e0434f4d,00000001,00000001,0033e294) ret=79f97065 003d:trace:seh:raise_exception code=e0434f4d flags=1 addr=0x7b8419a0 003d:trace:seh:raise_exception info[0]=80004001 003d:trace:seh:raise_exception eax=7b82c3e9 ebx=7b8af3a4 ecx=00000000 edx=0033e274 esi=0033e274 edi=0033e1f0 003d:trace:seh:raise_exception ebp=0033e1d8 esp=0033e174 cs=0073 ds=007b es=007b fs=0033 gs=003b flags=00000212 ... 003d:Ret ntdll.RtlUnwind() retval=00000000 ret=79f9608c 003d: eax=00000000 ebx=00000001 ecx=0013de68 edx=0033dc34 esi=00000000 edi=0013de68 ebp=0033db50 esp=0033db44 ds=007b es=007b fs=0033 gs=003b flags=00000246 ... 003d:Call KERNEL32.VirtualQuery(00241000,0033d3d4,0000001c) ret=79f992fc 003d:Ret KERNEL32.VirtualQuery() retval=0000001c ret=79f992fc 003d:Call KERNEL32.VirtualQuery(00241000,0033e478,0000001c) ret=79f992fc 003d:Ret KERNEL32.VirtualQuery() retval=0000001c ret=79f992fc 003d:Call KERNEL32.VirtualProtect(0033d000,00000001,00000104,0033e498) ret=79e74b61 003d:trace:virtual:NtProtectVirtualMemory 0xffffffff 0x33d000 00000001 00000104 003d:trace:virtual:VIRTUAL_SetProt 0x33d000-0x33dfff cgrw- <segfault here> --- snip trace ---
First VirtualQuery() -> page guard search algorithm Second VirtualQuery() + VirtualProtect() -> page guard enabling code.
I'm not going to waste more time with explanations.
Please show me the offending apps which ought to break when a guard page is located at StackLimit. I might find a way to satisfy both - but I have to see the app code.
Regards