The MASM Forum

General => The Laboratory => Topic started by: TouEnMasm on May 16, 2013, 05:56:12 PM

Title: A memory bug
Post by: TouEnMasm on May 16, 2013, 05:56:12 PM

This one is a bug not easy to find.
Run the exe,select a file and right clic to get the context menu.
The exe will just quit.
Responsible is the dynamic change of stack size who show no problem.
If someone could find some enlightment it would be very usefull.
There is differents problems with various number of stack pages required.
Windbg give this result when he find one:
Quote
(d54.5d0): Access violation - code c0000005 (first chance)
MSVCR80!_setusermatherr+0x4b5:
78131637 8500            test    dword ptr [eax],eax  ds:0023:00125000=????????
Title: Re: A memory bug
Post by: sinsi on May 16, 2013, 06:33:08 PM
I get no crash or anything, just a context menu. Selecting cancel takes me to the exe's window.
Under windbg I also get no crash, but every right click loads a bunch of dlls over and over.
In the middle is this error:
(c6c.1744): Unknown exception - code 000006ba (first chance)
Title: Re: A memory bug
Post by: jj2007 on May 16, 2013, 08:13:20 PM
That's a known problem of GetOpenFileName. (http://masm32.com/board/index.php?topic=1656.msg16859#msg16859) Nothing serious, though, it seems the dll handles it internally.
Title: Re: A memory bug
Post by: TouEnMasm on May 16, 2013, 10:34:15 PM

I have windows XP 3 and the "nothing serious" is just a fast exitprocess without saving anything.
The state of the msvrc80.dll seem responsible of that.
I have tried to load it,to view it's version,this failed with a prompt it is "loaded incorrectly",but I had no bug after the prompt.
Title: Re: A memory bug
Post by: dedndave on May 16, 2013, 11:43:27 PM
the silent exit may be caused by a stack allocation that is beyond the current commit
you could probe the stack down, say 4 kb or 8 kb - even 32 kb, then call it to verify
        ASSUME  FS:Nothing

        mov     eax,esp
        mov     edx,esp
        sub     eax,32768

@@:     push    edx
        mov     esp,fs:[8]
        cmp     eax,esp
        jb      @B

        mov     esp,edx

        ASSUME  FS:ERROR
Title: Re: A memory bug
Post by: TouEnMasm on May 17, 2013, 01:50:30 AM

I don't see really what do this test.
For me , if the stack commit is not > stack reserve,all is good.
Title: Re: A memory bug
Post by: jj2007 on May 17, 2013, 03:55:53 AM
Quote from: ToutEnMasm on May 16, 2013, 10:34:15 PM
I have windows XP 3 and the "nothing serious" is just a fast exitprocess...

Me too Windows XP SP3, and it works fine. Maybe it doesn't like French Windows ::)
Title: Re: A memory bug
Post by: KeepingRealBusy on May 17, 2013, 06:07:17 AM
What usually gets me in trouble is that I allocate all of memory with Virtual Alloc - and leave none to load the debugger. If any exception occurs, then you get an instant termination with no messages, no way to find out what went wrong.

Dave.
Title: Re: A memory bug
Post by: qWord on May 17, 2013, 06:48:58 AM
Unfortunately I don't speak French, thus I'm not able to read the comments nor the identifiers, but the problem is caused by "AgrandirPile", which calls VirtualAlloc for memory that belongs to the stack. After I NOP'ed out the "call AgrandirPile", the executable work perfect (Win7, x64) - you might simply let Windows manage the stack.
Title: Re: A memory bug
Post by: TouEnMasm on May 17, 2013, 03:48:12 PM

Quote
After I NOP'ed out the "call AgrandirPile", the executable work perfect (Win7, x64) - you might simply let Windows manage the stack.
It is what i have done,but i want to know if there is a way to avoid the problem.
I have verify the function step by step and don't see only one reason for what openfinename is on trouble.

I have simplify it a little.



AgrandirPile PROC uses esi edi ebx Nbpages:DWORD ,Affichage:DWORD
Local  adrRegion:DWORD,Pagedemande,tailletotale
Local  TailleRegion:DWORD,TailleMemTemp,plusregion,NewbaseAdress
Local  Tampon[100]:BYTE
Local  PageAlloue:DWORD,flAllocationType,flProtect
LOCAL  Tempmemorybasic:MEMORY_BASIC_INFORMATION,sysinfo:SYSTEM_INFO
Local  retour:DWORD
ZEROLOCALES retour
invoke GetSystemInfo,addr sysinfo ;SYSTEM_INFO
;first read ,get the BaseAdress of the pointer on memory
invoke VirtualQuery,esp,addr Tempmemorybasic,sizeof Tempmemorybasic
PuPo   TailleMemTemp,Tempmemorybasic.RegionSize
lecturezone:
;loop decreasing the BaseAdress by one page until he failed
;the region size increase by one page
mov edx,Tempmemorybasic.BaseAddress
sub edx,sysinfo.dwPageSize
invoke VirtualQuery,edx,addr Tempmemorybasic,sizeof Tempmemorybasic
mov edx,TailleMemTemp
add edx,sysinfo.dwPageSize
mov eax,Tempmemorybasic.RegionSize
.if eax == edx   ;same region
;keep the good values
PuPo   TailleMemTemp,Tempmemorybasic.RegionSize
PuPo   NewbaseAdress,Tempmemorybasic.BaseAddress
jmp lecturezone
.endif
;------ fill the Tempmemorybasic with the good values --------
invoke VirtualQuery,NewbaseAdress,addr Tempmemorybasic,sizeof Tempmemorybasic


;-------- get the properties of the region for Vitualalloc
;flAllocationType,flProtect
;invoke VirtualAlloc,Tempmemorybasic.BaseAddress,edx,\
; MEM_COMMIT or MEM_TOP_DOWN ,PAGE_READWRITE
;mov eax,Tempmemorybasic.type1  ;type1=MEM_IMAGE,MEM_MAPPED,MEM_PRIVATE
;mov flAllocationType,eax
mov eax,Tempmemorybasic.State  ;State=MEM_COMMIT,MEM_FREE,MEM_RESERVE
mov flAllocationType,eax
;-----------------------------------
mov ecx,Tempmemorybasic.AllocationProtect ;PAGE_EXECUTE ..
mov flProtect,ecx
;
;-------------- memory is read -------------------------------------------------------
;find the base adress and the size for the new region
mov eax,TailleMemTemp ;Tempmemorybasic.RegionSize
mov ecx,sysinfo.dwPageSize
xor edx,edx
div ecx
mov PageAlloue,eax
.if eax < Nbpages
;tout va bien
jmp @F    ;continuer
.else
mov retour,0
jmp FindeAgrandirPile
.endif

@@:
;we can do it
mov eax,Nbpages
mov edx,0
mov ecx,sysinfo.dwPageSize
mul ecx
mov tailletotale,eax ;total size of new region
mov eax,Nbpages
sub eax,PageAlloue ;pages already allocated
mov Pagedemande,eax ;number of pages to increase
mov edx,0
mov ecx,sysinfo.dwPageSize
mul ecx
mov plusregion,eax
;adresse a alloué
mov edx,Tempmemorybasic.BaseAddress
sub edx,plusregion
;on tient une adresse
invoke VirtualAlloc,edx,tailletotale,\
flAllocationType,flProtect
; MEM_COMMIT or MEM_TOP_DOWN ,PAGE_READWRITE


.if eax == 0
mov retour,0
jmp FindeAgrandirPile
.else
invoke LecturePile,0

.endif


FindeAgrandirPile:
         mov eax,retour
         ret
AgrandirPile endp

Title: Re: A memory bug
Post by: jj2007 on May 17, 2013, 04:23:45 PM
Why AgrandirPile? As qWord wrote already, Windows manages the stack quite well. If it's not sufficient, use a stackprobe macro...
Title: Re: A memory bug
Post by: TouEnMasm on May 17, 2013, 07:27:40 PM

If by a stackprobe macro (unknown in this forum),you want to say "use the linker" to solve this,it is what i have done.
The problem stay without a soluce.I have read that another system use another dialog API to open files.Must be the soluce.
Thanks at all.
Title: Re: A memory bug
Post by: dedndave on May 17, 2013, 10:37:12 PM
you can use the code in reply #4 to probe the stack
i used 32768 bytes, but you can probe it down to whatever depth you like

the last line of code, MOV ESP,EDX sets ESP to the original value
but, i would normally use MOV ESP,EAX to adjust ESP to the desired depth
Title: Re: A memory bug
Post by: qWord on May 17, 2013, 11:04:27 PM
I don't understand why the stack size must be changed, but at least increasing it is easy (see above).
For your code I see the problem that it removes the guarded page blow the current stack, which is used by system to detected if an application needs more stack-memory. Also, the question is how to inform the system that you have changed the stack size - I've doubts that the TIB entry is sufficient.

EDIT: for stack probe I would use this one: I would use dave's approach too
mov edx,esp
and edx,NOT (4096-1)
sub edx,4096
xor ecx,ecx
.while ecx < 10 ; 10 = number of pages
or BYTE ptr [edx],0
sub edx,4096
add ecx,1
.endw
Title: Re: A memory bug
Post by: dedndave on May 17, 2013, 11:46:50 PM
that code assumes what ? 4 kb pages ?
i thought they were 2 kb - lol
no matter

Yves uses GetSystemInfo to determine the page size
and - i think it is a constant over all versions of windows, to date

but, in my probe code, i use the value at FS:[8]
whatever the page size is, it will be correct, as it uses the current stack commit as the next probe address   :P
that also ensures a minumum number of probe loop passes, i.e. faster
Title: Re: A memory bug
Post by: qWord on May 17, 2013, 11:58:36 PM
Quote from: dedndave on May 17, 2013, 11:46:50 PM
that code assumes what ? 4 kb pages ?
i thought they were 2 kb - lol
please show me a x86 processor that supports 2 kb pages.
Title: Re: A memory bug
Post by: dedndave on May 18, 2013, 12:03:14 AM
you're right - they are 4 kb
as i said, you don't have to know what the page size is if you use my code   :P
Title: Re: A memory bug
Post by: qWord on May 18, 2013, 12:12:31 AM
Quote from: dedndave on May 18, 2013, 12:03:14 AM
as i said, you don't have to know what the page size is if you use my code   :P
indeed, your solution is better because it is page-size-independent :icon14:
Title: Re: A memory bug
Post by: dedndave on May 18, 2013, 12:26:01 AM
a little demo
you can watch the bottom-of-stack (TIB.StackLimit) value change at each loop pass

actually, i think that's the top-of-stack, but the wiki page calls it the bottom   :P
Title: Re: A memory bug
Post by: TouEnMasm on May 18, 2013, 01:33:48 AM

Perhaps an explain on how it work,the FS[8] change,How ?.
And where did you find this ?
Title: Re: A memory bug
Post by: dedndave on May 18, 2013, 01:57:03 AM
the operating system maintains the value in the thread information block
as you use more stack space, it commits additional pages, as required

i didn't find it - i wrote it
Title: Re: A memory bug
Post by: dedndave on May 18, 2013, 02:06:09 AM
i was using some other code previously - it used GetSystemInfo to find the page size
but, i wanted a faster method for inline probing to create buffers for an EnumReg function i was writing
so, i did a little research and found that the TIB had the stack limit value
it dawned on me that the page size isn't needed if you use the current stack limit value   :P
how ever much the OS commits (even if it were more than 1 page), you probe the current limit until you get what you want
Title: Re: A memory bug
Post by: TouEnMasm on May 18, 2013, 02:23:01 AM

Ok , your method is an answer to the memory problem with openfilename.
There is no problem after changing the stack size with the right clic.
:t
I find just an error,the stack is full when you exit,modify it like below:

bytes_required = 0A000h
mov keepesp,esp  ;keep the actual esp in data

        ASSUME  FS:Nothing

        mov     eax,esp
        sub     eax,bytes_required
        and     al,-16                ;let's use 16-align for demo purposes

@@:     push    eax
        ;call    ShowStackBottom       ;for demo purposes only
        mov     esp,fs:[8]
        cmp     eax,esp
        jb      @B

        mov     esp,keepesp    ;old position

        ASSUME  FS:ERROR
Title: Re: A memory bug
Post by: qWord on May 18, 2013, 02:37:17 AM
Quote from: ToutEnMasm on May 18, 2013, 02:23:01 AMOk , your method is an answer to the memory problem with openfilename.
There is no problem after changing the stack size with the right clic.
The simples method is to leave the stack as it is. I'm really curios what you want to archive...
Title: Re: A memory bug
Post by: TouEnMasm on May 18, 2013, 03:00:19 AM

Quote
The simples method is to leave the stack as it is. I'm really curios what you want to archive...
The increase of the stack size allow fast load (see microsoft) .
Sample,when you load mutiples files an put them in a richedit,the work is faster with a modify stack.The result is visible.

Title: Re: A memory bug
Post by: dedndave on May 18, 2013, 03:10:51 AM
if you go back to reply #4, you will see that the original ESP is stored in EDX, then restored when done probing
you only need to change the 32768 to 0A000h in that code
Title: Re: A memory bug
Post by: qWord on May 18, 2013, 03:30:02 AM
Quote from: ToutEnMasm on May 18, 2013, 03:00:19 AMThe increase of the stack size allow fast load (see microsoft)
where can I read about that (link)?
Title: Re: A memory bug
Post by: jj2007 on May 18, 2013, 03:41:39 AM
Quote from: ToutEnMasm on May 18, 2013, 03:00:19 AMSample,when you load mutiples files an put them in a richedit,the work is faster with a modify stack.The result is visible.

I am very curious to see a comparison. Seriously - I'd love to speed up my RichMasm editor (http://www.masmforum.com/board/index.php?topic=9044).
Title: Re: A memory bug
Post by: TouEnMasm on May 18, 2013, 03:19:19 PM
Quote
I am very curious to see a comparison. Seriously - I'd love to speed up my RichMasm editor.

Simple,made test on your IDE changing the stack size with the linker,you will have an answer.
Title: Re: A memory bug
Post by: TouEnMasm on May 18, 2013, 04:42:51 PM
Here a full explain of the method and a proc who give the amount of desired memory in bytes rounded to the next upper page.

comment µ
NT_TIB STRUCT DEFALIGNMASM ;winnt.sdk
ExceptionList DWORD ?
StackBase DWORD ?
StackLimit DWORD ?
SubSystemTib DWORD ?
IF DEFINED(_MSC_EXTENSIONS)
union
FiberData DWORD ?
Version DWORD ?
ENDS
ELSE
FiberData DWORD ?
ENDIF
ArbitraryUserPointer DWORD ?
Self DWORD ?
NT_TIB ENDS
µ
;nbytes,desired sizeof stack,rounded to the next upper page
;################################################################
SystemIncreaseStack PROC nbytes:DWORD
Local keepesp:DWORD
mov ecx,0
mov keepesp,esp
ASSUME  FS:Nothing
stackloop:
mov edx,FS:[ecx].NT_TIB.StackLimit
mov eax,FS:[ecx].NT_TIB.StackBase
sub eax,edx  ;allocated stack
.if eax < nbytes   ;let's the system made a round in page
mov esp,FS:[ecx].NT_TIB.StackLimit
push eax ;write outside this limit and let the system increase the stack
jmp stackloop
.endif
ASSUME  FS:ERROR
mov     esp,keepesp
;eax new size
         ret
SystemIncreaseStack endp

Title: Re: A memory bug
Post by: jj2007 on May 18, 2013, 05:23:46 PM
Quote from: ToutEnMasm on May 18, 2013, 03:19:19 PM
Quote
I am very curious to see a comparison. Seriously - I'd love to speed up my RichMasm editor.

Simple,made test on your IDE changing the stack size with the linker,you will have an answer.

Good proposal. So here is the answer:
Loading a 13,000 lines source into a RichEdit control:
- stack 12 MB: 1.0 seconds
- stack 0.5 MB: 0.75 seconds

Your turn 8)
Title: Re: A memory bug
Post by: MichaelW on May 18, 2013, 06:10:11 PM
I can't see any significant difference either. Running on my Windows XP P3 system, loading the current MASM32 windows.inc 10 times, whether I use the default stack size, or /STACK:10000000,10000000, I get ~1720ms.


;==============================================================================
; Build as a console app.
;==============================================================================
include \masm32\include\masm32rt.inc
;==============================================================================
IDC_RE equ 100
;==============================================================================

  ;----------------------------------------------------------------------
  ; This is a general-purpose control definition macro that adds support
  ; for controls of any type to the MASM32 In-Memory Dialogs. For this
  ; macro the control class is specified as a quoted string, instead of
  ; being hard coded.
  ;----------------------------------------------------------------------

    DlgControl MACRO quoted_caption,quoted_class,dstyle,tx,ty,wd,ht,ctlID
      align_4 edi
      mov DWORD PTR [edi+0],  WS_VISIBLE or WS_CHILD or dstyle
      mov WORD  PTR [edi+8],  tx
      mov WORD  PTR [edi+10], ty
      mov WORD  PTR [edi+12], wd
      mov WORD  PTR [edi+14], ht
      mov WORD  PTR [edi+16], ctlID
      add edi, 18
      ustring quoted_class
      ustring quoted_caption
      ;-------------------------------------------
      ; Advance edi past the creation data array.
      ;-------------------------------------------
      add edi, 2
    ENDM

;==============================================================================
    .data
      hInst       HMODULE 0
      hwndRE      HWND    0
      hFile       HANDLE  0
      flag        dd      0
      editstream  EDITSTREAM <1,,EditStreamCallback>
      filename    db      "\masm32\include\windows.inc",0
    .code
;==============================================================================

EditStreamCallback proc dwCookie:DWORD, pbBuff:DWORD, cb:DWORD, pcb:DWORD

    invoke ReadFile, hFile, pbBuff, cb, pcb, NULL
    xor eax, eax
    ret

EditStreamCallback endp

;==============================================================================

DlgProc proc hwndDlg:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM

    LOCAL rc:RECT

    SWITCH uMsg

        CASE WM_INITDIALOG

            invoke CreateFile, ADDR filename, GENERIC_READ, FILE_SHARE_READ,
                               NULL, OPEN_EXISTING, NULL, NULL
            mov hFile, eax

            invoke GetDlgItem, hwndDlg, IDC_RE
            mov hwndRE, eax

            invoke SendMessage, hwndRE, EM_EXLIMITTEXT, 1000000*10, 0

         CASE WM_SYSCOMMAND

            .IF flag == 0
                inc flag
                invoke GetTickCount
                push eax

                REPEAT 10
                    invoke SendMessage, hwndRE,
                                        EM_STREAMIN,
                                        SF_TEXT,
                                        ADDR editstream
                    invoke SetFilePointer, hFile, 0, NULL, FILE_BEGIN
                ENDM

                invoke GetTickCount
                pop edx
                sub eax, edx
                printf("%dms\n", eax)
            .ENDIF

        CASE WM_SIZE

            invoke GetClientRect, hwndDlg, ADDR rc
            invoke MoveWindow, hwndRE, 0, 0, rc.right, rc.bottom, TRUE

        CASE WM_COMMAND

            SWITCH wParam
                Case IDCANCEL
                    invoke CloseHandle,hFile
                    invoke EndDialog, hwndDlg, NULL
            ENDSW

        CASE WM_CLOSE

            invoke CloseHandle,hFile
            invoke EndDialog, hwndDlg, NULL

    EndSw

    return 0

DlgProc endp

;==============================================================================
start:
;==============================================================================

    invoke LoadLibrary, chr$("RICHED20.DLL")

    invoke GetModuleHandle, NULL
    mov hInst, eax

    Dialog  "Click title bar to start test", \
            "Courier New",8, \
            WS_OVERLAPPED or WS_SYSMENU or DS_CENTER, \
            1, \
            0,0,200,150, \
            1024

    DlgControl 0, \
               "RichEdit20A", \
               WS_VSCROLL or \
               WS_HSCROLL or \
               ES_SUNKEN or \
               ES_MULTILINE or \
               ES_AUTOVSCROLL or \
               ES_AUTOHSCROLL or \
               ES_NOHIDESEL or \
               ES_WANTRETURN, \
               0,0,0,0,IDC_RE

    CallModalDialog hInst, 0, DlgProc, NULL
    exit

;==============================================================================
end start


I didn't think to test the effect of the RE control styles, and I am apparently testing a Rich Edit 3.0 control.

Title: Re: A memory bug
Post by: jj2007 on May 18, 2013, 07:10:54 PM
Quote from: MichaelW on May 18, 2013, 06:10:11 PM
I can't see any significant difference either. Running on my Windows XP P3 system...

With Celeron M, XP SP3:
- 400k stack: 407 ms
- 8M stack: 407 ms

In fact, my own tests tell the same story (the 0.75 secs were an outlier :biggrin:).

It is a nice habit to measure things instead of just declaring "truths" as if Moses himself had been giving a helping hand ;-)
Title: Re: A memory bug
Post by: TouEnMasm on May 18, 2013, 10:05:39 PM

Quote
It is a nice habit to measure things instead of just declaring "truths" as if Moses himself had been giving a helping hand ;-)
I have just declared truth in one particular case,not on all.
Everybody can test it if it is usefull or not in his case.

Title: Re: A memory bug
Post by: hutch-- on May 18, 2013, 11:19:26 PM
There is an image you regularly get in medieval movies in times of plague where lines of pilgrims walk along the streets chanting and self flagelating and every time I have read this thread the image comes back to me. In 32 bit PE executables that stack is set by the linker and is part of the OS design, it is not a dynamic resizable stack. Now while there are various reasons why you vary these two parameters, upwards for recursion or downwards if a particular application must have the smallest memory footprint possible, trying to dynamically size the stack looks and sounds like those folks of long ago who deliberately harm themselves.
Title: Re: A memory bug
Post by: dedndave on May 18, 2013, 11:26:04 PM
there are times when the amount of stack space required is not known until runtime
i don't see any harm in probing the stack to increase the space available by TIB.StackLimit

QuoteIn 32 bit PE executables that stack is set by the linker and
is part of the OS design, it is not a dynamic resizable stack.

i would say it's dynamic, as the OS continually balances the need for stack space with the need for heap space
Title: Re: A memory bug
Post by: TouEnMasm on May 19, 2013, 12:16:56 AM

Make this simple test ,put in the WM_DESTROY message and you will see the amount of stack memory reserved dynamically by the system .
On my XP SP3 it start at 3000h bytes,for my IDE it end at 16000h bytes

Take care with 64 bits there is a NT_TIB64:

NT_TIB64 STRUCT DEFALIGNMASM
ExceptionList QWORD ?
StackBase QWORD ?
StackLimit QWORD ?
SubSystemTib QWORD ?
IF DEFINED(_MSC_EXTENSIONS)
union
FiberData QWORD ?
Version DWORD ?
ENDS
ELSE
FiberData QWORD ?
ENDIF
ArbitraryUserPointer QWORD ?
Self QWORD ?
NT_TIB64 ENDS




WM_DESTROY
invoke StackSize
mov edx,eax
invoke BaseN,edx,16,addr ZoneMessagesErreurs
invoke MessageBox,NULL,ADDR ZoneMessagesErreurs,SADR("Taille Pile"),MB_OK

;################################################################
StackSize PROC
ASSUME  FS:Nothing
mov ecx,0
mov edx,FS:[ecx].NT_TIB.StackLimit ;FS:[8]
mov eax,FS:[ecx].NT_TIB.StackBase  ;FS:[4]
sub eax,edx  ;allocated stack
ASSUME  FS:ERROR
         ret
StackSize endp
Title: Re: A memory bug
Post by: TouEnMasm on June 10, 2013, 01:17:33 AM
Found where is the bug:
windbg give me
Quote;MSVCR80!_chkstk+27 [crt\src\intel\chkstk.asm @ 99] 78131637 8500  test    dword ptr [eax],eax
The "chkstk.asm " is in the c++express crt source code.
Viewing it:
Quote
; Find next lower page and probe
cs20:
        sub     eax, _PAGESIZE_         ; decrease by PAGESIZE
        test    dword ptr [eax],eax     ; probe page.  <<< comment is clear
        jmp     short cs10
What i have done is just read the size of the stack at the end,using the openfile fialog.Size stack needed by the dialog in pages is 13 pages.
Now using the  dynamic  allocation of stack with virtualloc i choose 16 pages to allocate and no more bug with a right clic on a file.

This show that virtualloc uninstall the guard page interrupt  (_XCPT_GUARD_PAGE_VIOLATION).
If someone know how to reinstall it,put it here. (Found Virtual Protect PAGEGUARD)