- [Q]ddk compiler
- Posted by jeromeCh on October 26th, 2005
Hello,
The code snipset below seems to generate a stack corruption with my ddk
compiler v13.10.2179 in release mode :
--
#include <ntifs.h>
IRP *GetIrp(CCHAR f_nbStckSize)
{return (IRP *)ExAllocatePool(NonPagedPool, f_nbStckSize);}
NTSTATUS TestRelease(IN FILE_OBJECT *fp_fileobj,
IN DEVICE_OBJECT *fp_devobj,
IN ULONG f_major,
IN BOOLEAN f_waitCondition,
IN MDL *fp_usermdl,
IN LARGE_INTEGER f_StartingByte,
IN ULONG f_bytecount,
OUT IO_STATUS_BLOCK *fp_iostatus )
{
NTSTATUS ntstatus = STATUS_SUCCESS;
PVOID systemBuffer = NULL;
IO_STACK_LOCATION *p_curstk = NULL;
IRP *pIrp = NULL;
CCHAR ChrBigPb; <<<<<<<<<<<<<<<<<<<<<<<
KEVENT event; // Synchronous call
ULONG nbretry;
ASSERT(fp_fileobj);
ASSERT(fp_devobj);
ASSERT(fp_usermdl);
ASSERT((f_major == IRP_MJ_READ) || (f_major == IRP_MJ_WRITE));
ASSERT(fp_iostatus);
nbretry = 0;
while (systemBuffer == NULL && nbretry < 10)
{
// This may fail in case of memory exhaution
//
systemBuffer = MmGetSystemAddressForMdlSafe(fp_usermdl,
NormalPagePriority);
nbretry++;
}
if (systemBuffer == NULL)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
KeInitializeEvent(&event, NotificationEvent, FALSE);
ChrBigPb = fp_devobj->StackSize;
pIrp = GetIrp(ChrBigPb);
if (pIrp==NULL)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
if (f_bytecount==0)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
if (f_StartingByte.LowPart == 0)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
if (f_waitCondition==FALSE)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
fp_iostatus->Status = 0;
return ntstatus;
}
--
The assembly gives :
....
_GetIrp@4 ENDP
_TEXT ENDS
PUBLIC _TestRelease@36
EXTRN __imp__MmMapLockedPagesSpecifyCache@24:NEAR
EXTRN __imp__KeInitializeEvent@12:NEAR
; Function compile flags: /Ogsy
; COMDAT _TestRelease@36
_TEXT SEGMENT
_event$ = -16 ; size = 16
_fp_fileobj$ = 8 ; size = 4
_fp_devobj$ = 12 ; size = 4
_f_major$ = 16 ; size = 4
_f_waitCondition$ = 20 ; size = 1
_ChrBigPb$ = 24 ; size = 1 <<<<<<<<<<<<<<<<< use as a parameter instead of
local variable. stack corruption when used.
_fp_usermdl$ = 24 ; size = 4
_f_StartingByte$ = 28 ; size = 8
_f_bytecount$ = 36 ; size = 4
_fp_iostatus$ = 40 ; size = 4
_TestRelease@36 PROC NEAR ; COMDAT
; 19 : {
00000 55 push ebp
00001 8b ec mov ebp, esp
00003 83 ec 10 sub esp, 16 ; 00000010H
00006 53 push ebx
00007 56 push esi
; 20 : NTSTATUS ntstatus = STATUS_SUCCESS;
; 21 : PVOID systemBuffer = NULL;
; 22 : IO_STACK_LOCATION *p_curstk = NULL;
; 23 : IRP *pIrp = NULL;
; 24 : CCHAR ChrBigPb;
; 25 : KEVENT event; // Synchronous call
; 26 : ULONG nbretry;
; 27 :
; 28 :
; 29 : ASSERT(fp_fileobj);
; 30 : ASSERT(fp_devobj);
; 31 : ASSERT(fp_usermdl);
; 32 : ASSERT((f_major == IRP_MJ_READ) || (f_major == IRP_MJ_WRITE));
; 33 : ASSERT(fp_iostatus);
; 34 :
; 35 :
; 36 : nbretry = 0;
....
ChrBigPb variable corrupts the stack (the mdl above), I tried to change its
name w/o effect
Here are the compiler parameters:
'nmake.exe /c BUILDMSG=Stop. -i NTTEST= UMTEST= NOLINK=1 386=1'
cl -nologo -Ii386\ -I. -Ij:\winddk/3790\inc\mfc42 -IJ:\WINDDK\3790.1159\inc\
ifs\wnet -Iobjfre_wnet_x86\i386 -Ij:\winddk/3790\inc\wnet -Ij:\winddk/3790\i
nc\wnet -Ij:\winddk/3790\inc\ddk\wnet -Ij:\winddk/3790\inc\ifs\wnet -Ij:\win
ddk/3790\inc\crt -D_X86_=1 -Di386=1 -DSTD_CALL -DCONDITION_HANDLING=1 -DN
T_INST=0 -DWIN32=100 -D_NT1X_=100 -DWINNT=1 -D_WIN32_WINNT=0x0502
/DWINVER=0x0502 -D_WIN32_IE=0x0600 -DWIN32_LEAN_AND_MEAN=1 -DDEVL=1 -D__B
UILDMACHINE__=WinDDK -DFPO=1 -DNDEBUG -D_DLL=1 -D_WIN2K_COMPAT_SLIST_USAGE
/c /Zel /Zp8 /Gy /Gi- /Gm- -cbstring /GS /FR /FAsc /Fm /WX /Gz /QIfdiv- /G6
/GX- /GR- /GF /GS -Z7 /Oxs /Oy -FIj:\winddk/3790\inc\wnet\warning.h
..\bfu.c
bfu.c
In debug mode the exact same code produces a correct local variable layout
:
_GetIrp@4 ENDP
_TEXT ENDS
PUBLIC _TestRelease@36
EXTRN __imp__MmMapLockedPagesSpecifyCache@24:NEAR
EXTRN __imp__KeInitializeEvent@12:NEAR
EXTRN __imp__RtlAssert@16:NEAR
; COMDAT _TestRelease@36
_TEXT SEGMENT
$SG17764 DB 'j:\winddk\3790\src\general\b\bfu.c', 00H
....
$SG17777 DB 'fp_iostatus', 00H
; Function compile flags: /Odt
tv141 = -64 ; size = 4
tv94 = -60 ; size = 4
tv88 = -56 ; size = 4
tv81 = -52 ; size = 4
tv75 = -48 ; size = 4
tv69 = -44 ; size = 4
_event$ = -40 ; size = 16
_nbretry$ = -24 ; size = 4
_ChrBigPb$ = -17 ; size = 1 <<<<<<<<<<<<<<
_systemBuffer$ = -16 ; size = 4
_ntstatus$ = -12 ; size = 4
_pIrp$ = -8 ; size = 4
_p_curstk$ = -4 ; size = 4
_fp_fileobj$ = 8 ; size = 4
_fp_devobj$ = 12 ; size = 4
_f_major$ = 16 ; size = 4
_f_waitCondition$ = 20 ; size = 1
_fp_usermdl$ = 24 ; size = 4
_f_StartingByte$ = 28 ; size = 8
_f_bytecount$ = 36 ; size = 4
_fp_iostatus$ = 40 ; size = 4
_TestRelease@36 PROC NEAR ; COMDAT
....
Here are the debug flags:
'nmake.exe /c BUILDMSG=Stop. -i NTTEST= UMTEST= NOLINK=1 386=1'
cl -nologo -Ii386\ -I. -Ij:\winddk/3790\inc\mfc42 -IJ:\WINDDK\3790.1159\inc\
ifs\wnet -Iobjchk_wnet_x86\i386 -Ij:\winddk/3790\inc\wnet -Ij:\winddk/3790\i
nc\wnet -Ij:\winddk/3790\inc\ddk\wnet -Ij:\winddk/3790\inc\ifs\wnet -Ij:\win
ddk/3790\inc\crt -D_X86_=1 -Di386=1 -DSTD_CALL -DCONDITION_HANDLING=1 -DN
T_INST=0 -DWIN32=100 -D_NT1X_=100 -DWINNT=1 -D_WIN32_WINNT=0x0502
/DWINVER=0x0502 -D_WIN32_IE=0x0600 -DWIN32_LEAN_AND_MEAN=1 -DDEVL=1 -DDBG
=1 -D__BUILDMACHINE__=WinDDK -DFPO=0 -DNDEBUG -D_DLL=1 -D_WIN2K_COMPAT_SLIS
T_USAGE /c /Zel /Zp8 /Gy /Gi- /Gm- -cbstring /GS /FR /FAsc /Fm /WX /Gz
/QIfdiv- /G6 /GX- /GR- /GF /GS -Z7 /Od /Oi
Oy- -FIj:\winddk/3790\inc\wnet\warning.h .\bfu.c
bfu.c
Is this a known problem in this ddk ? Is there a workaround or fix ?
Thanks,
Jerome.
- Posted by Calvin Guan on October 26th, 2005
This is very common in free build environment (optimized code). Since you
didn't post the entire assembly code for the function, I can't show you how
the code preserved the parameter FIRST AND THEN reuses the caller's stack
frame.
From your code, I'm not clear what you want to do with the IRP. If you want
to build a relay IRP and pass to someone else, the math doesn't sound right.
The alloc size should be at least
sizeof(IRP)+f_nbStckSize*sizeof(IO_STACK_LOCATION) . If you really want to
roll your own IRP (I'd consider it's just asking for trouble), I would use
ExAllocatePoolWithTag.
Why not use IoAllocateIrp? For synchronous I/O, there is better choice, for
instance, IoBuildSynchronousFsdRequest.
Good luck!
--
Calvin Guan (Windows DDK MVP)
NetXtreme Longhorn Miniport Prime
Broadcom Corp. www.broadcom.com
"jeromeCh" <jeromeCh@newsgroups.nospam> wrote in message
news:ugx6iFf2FHA.3600@TK2MSFTNGP12.phx.gbl...
- Posted by Bill McKenzie on October 26th, 2005
Well, I just tried this code with the 14.00.41204.17 version of the compiler
and I didn't have any problems. This is the only version I have installed
with a DDK that has the ntifs.h header.
BTW and just FYI, you use DDK types like IRP * in several places. The DDK
provides pointer types such as PIRP instead. Also, you should never use
ExAllocatePool, rather use ExAllocatePoolWithTag and provide a tag such that
your memory allocations can be tracked by you or others.
Bill M.
"jeromeCh" <jeromeCh@newsgroups.nospam> wrote in message
news:ugx6iFf2FHA.3600@TK2MSFTNGP12.phx.gbl...
- Posted by Maxim S. Shatskih on October 26th, 2005
Use IoAllocateIrp instead of ExAllocatePool to allocate IRPs. It is fast
and optimized.
--
Maxim Shatskih, Windows DDK MVP
StorageCraft Corporation
maxim@storagecraft.com
http://www.storagecraft.com
"jeromeCh" <jeromeCh@newsgroups.nospam> wrote in message
news:ugx6iFf2FHA.3600@TK2MSFTNGP12.phx.gbl...
- Posted by jeromeCh on October 26th, 2005
Hello Calvin & Bill,
Thanks for the help.
GetIrp is a dummy function it is not used in production code, It is just
here to force the compiler to produce code and to simplify the example. I'm
aware and using the various functions you did mentionned in your posts.
I did saw the stack corruption after single stepping with a kernel debugger.
Here is the beginning of the assembly output for this function, ChgBigPb is
not set in a register nor do I see any obvious ebp adjustement:
PUBLIC _TestRelease@36
EXTRN __imp__MmMapLockedPagesSpecifyCache@24:NEAR
EXTRN __imp__KeInitializeEvent@12:NEAR
; Function compile flags: /Ogsy
; COMDAT _TestRelease@36
_TEXT SEGMENT
_event$ = -16 ; size = 16
_fp_fileobj$ = 8 ; size = 4
_fp_devobj$ = 12 ; size = 4
_f_major$ = 16 ; size = 4
_f_waitCondition$ = 20 ; size = 1
_ChrBigPb$ = 24 ; size = 1
_fp_usermdl$ = 24 ; size = 4
_f_StartingByte$ = 28 ; size = 8
_f_bytecount$ = 36 ; size = 4
_fp_iostatus$ = 40 ; size = 4
_TestRelease@36 PROC NEAR ; COMDAT
; 19 : {
00000 55 push ebp
00001 8b ec mov ebp, esp
00003 83 ec 10 sub esp, 16 ; 00000010H
00006 53 push ebx
00007 56 push esi
; 20 : NTSTATUS ntstatus = STATUS_SUCCESS;
; 21 : PVOID systemBuffer = NULL;
; 22 : IO_STACK_LOCATION *p_curstk = NULL;
; 23 : IRP *pIrp = NULL;
; 24 : CCHAR ChrBigPb;
; 25 : KEVENT event; // Synchronous call
; 26 : ULONG nbretry;
; 27 :
; 28 :
; 29 : ASSERT(fp_fileobj);
; 30 : ASSERT(fp_devobj);
; 31 : ASSERT(fp_usermdl);
; 32 : ASSERT((f_major == IRP_MJ_READ) || (f_major == IRP_MJ_WRITE));
; 33 : ASSERT(fp_iostatus);
; 34 :
; 35 :
; 36 : nbretry = 0;
00008 8b 75 18 mov esi, DWORD PTR _fp_usermdl$[ebp]
0000b 57 push edi
0000c 33 db xor ebx, ebx
0000e 33 c0 xor eax, eax
00010 33 ff xor edi, edi
$L17769:
; 37 : while (systemBuffer == NULL && nbretry < 10)
00012 83 ff 0a cmp edi, 10 ; 0000000aH
00015 73 1e jae SHORT $L17770
; 38 : {
; 39 : // This may fail in case of memory exhaution
; 40 : //
; 41 : systemBuffer = MmGetSystemAddressForMdlSafe(fp_usermdl,
; 42 : NormalPagePriority);
00017 f6 46 06 05 test BYTE PTR [esi+6], 5
0001b 74 05 je SHORT $L17803
0001d 8b 46 0c mov eax, DWORD PTR [esi+12]
00020 eb 0e jmp SHORT $L17804
$L17803:
00022 6a 10 push 16 ; 00000010H
00024 53 push ebx
00025 53 push ebx
00026 6a 01 push 1
00028 53 push ebx
00029 56 push esi
0002a ff 15 00 00 00
00 call DWORD PTR __imp__MmMapLockedPagesSpecifyCache@24
$L17804:
; 43 : nbretry++;
00030 47 inc edi
00031 3b c3 cmp eax, ebx
00033 74 dd je SHORT $L17769
$L17770:
; 44 : }
; 45 :
; 46 : if (systemBuffer == NULL)
00035 3b c3 cmp eax, ebx
; 47 : {
; 48 :
; 49 : return STATUS_INSUFFICIENT_RESOURCES;
00037 74 30 je SHORT $L17807
; 50 : }
; 51 :
; 52 : KeInitializeEvent(&event, NotificationEvent, FALSE);
00039 53 push ebx
0003a 53 push ebx
0003b 8d 45 f0 lea eax, DWORD PTR _event$[ebp]
0003e 50 push eax
0003f ff 15 00 00 00
00 call DWORD PTR __imp__KeInitializeEvent@12
; 53 :
; 54 : ChrBigPb = fp_devobj->StackSize;
00045 8b 45 0c mov eax, DWORD PTR _fp_devobj$[ebp]
00048 8a 40 30 mov al, BYTE PTR [eax+48]
0004b 88 45 18 mov BYTE PTR _ChrBigPb$[ebp], al <<<< change the mdl param
; 55 : pIrp = GetIrp(ChrBigPb);
0004e ff 75 18 push DWORD PTR _ChrBigPb$[ebp]
00051 e8 00 00 00 00 call _GetIrp@4
....
--
OK, I'll try to upgrate my ddk.
Thanks again.
Jerome
"Calvin Guan" <hguan@nospam.broadcom.com> wrote in message
news:u4Q04Wg2FHA.3912@TK2MSFTNGP15.phx.gbl...
- Posted by Calvin Guan on October 26th, 2005
The mdl parameter had been saved in esi before [ebp+24] got updated.
always displays local vars or parameters correctly for *free* build code.
trivial case. (Well, I did get burned by a proven nasty ia64 compiler bug
sometime ago). BTW, MS uses DDK compiler to build the entire OS. It should
have fallen apart before making it to your code if that was the case, I
think.
--
Calvin Guan (Windows DDK MVP)
NetXtreme Longhorn Miniport Prime
Broadcom Corp. www.broadcom.com
"jeromeCh" <jeromeCh@newsgroups.nospam> wrote in message
news:%23Uoy65g2FHA.3052@TK2MSFTNGP10.phx.gbl...
- Posted by jeromeCh on October 26th, 2005
Hi,
"Calvin Guan" <hguan@nospam.broadcom.com> wrote in message
news:en6qWbh2FHA.472@TK2MSFTNGP15.phx.gbl...
Thanks, I did miss that. That's explain it.
Ok.
I do agree, I was also surprise that such a simple code could break the
compiler output.
Thanks again.
Kind Regards,
Jerome.
- Posted by jeromeCh on October 26th, 2005
BTW,
The interesting conclusion (at least for me) is that if you do postmortem
analysis on a memory dump you can expect to see what seems to be 'corrupted'
stack frame because of compiler optimization.
Jerome.
"jeromeCh" <jeromeCh@newsgroups.nospam> wrote in message
news:%23iEQfpi2FHA.3188@TK2MSFTNGP12.phx.gbl...