Hello everybody,

I've got this huge project that does alot of writing, reading deleteing files.  Sometimes the app crashes with this os generated (Windows XP) message:
The instruction at "0x7c911629" referenced memory at :0x00000000".  The memory coould not be "written".

Sounds like a bad pointer but I've been trying to find the cause for a week now with no success.  Any ideas/suggestions appreciated.

best regards,

czDrillard
Posted on 2005-08-28 11:20:02 by czDrillard
0x7c911629 is a location in kernel/system code - coupled with memory at 0, this really sounds like a register preservation problem somewhere. Try attaching a just-in-time debugger like OllyDbg, ESI,EDI or EBX will most likely be 0.
Posted on 2005-08-28 11:42:41 by f0dder
You might want to add exception handling to your application. That way you can get the module name that is failing and you can unroll the stack to find out what called it. Jeremy Gordon has a fairly decent tutorial on his website...

http://www.jorgon.freeserve.co.uk/Except/Except.htm
Posted on 2005-08-28 11:56:42 by donkey
Thanks f0dder and donkey.

I'm using Visual Studio as jit debugger.  And the event occurs in Nt kernel.  Will check register preservation again and try some exception handling.

best regards,

czDrillard
Posted on 2005-08-28 12:09:40 by czDrillard
As donkey said, check the stack callback - this is even easier when using a decent debugger like the visual studio one.

If the last address that's in your program is a callback (most often offenders would be wndproc or dlgproc), it's most likely register preservation that's a problem :)
Posted on 2005-08-28 12:11:37 by f0dder
Now this error keeps popping up:
Unhandled exception in czSecure.exe(NTDLL.DLL):  0xc0000005:  Access Violation

I've googled around and this seems to be a common enough error message.  I just don't know how it applies to me.
After clicking ok the relevant portion of the stack looks like this:

NTDLL! 7c9106c3()
.
.
.
COMCTL32! 7741c898()
.
.
.
USER32! 77d48734()
.
.
.
ShowIndexInfo(unsigned long, unsigned long)
ShowMSH_IndexDat(unsigned long)                   
CZSECURE! ProgramManager@16
.
.
.

Does this mean the error is in one of the modules on the stack? 

Btw, this program is huge, by assembly standards anyways.  The main asm file has 29,202 lines.  There are 16 additional smaller asm files and 4 dll's. So any help is greatly appreciated
Posted on 2005-08-28 19:49:06 by czDrillard

Does this mean the error is in one of the modules on the stack? 

Find the first address in the call stack that is inside your application - this will most likely be near the location where you have an error.

By the look of things, I would assume that CZSECURE is your appname, and that ProgramManager@16 is a wndproc or dlgproc? You will need to isolate what conditions cause the error, and from that, infer which window message you're processing wrongly (whether that be register preservation, stack trashing, passing wrong parameters to an API, or whatever :)).
Posted on 2005-08-28 21:59:52 by f0dder
Thanks f0dder,

Yep, CZSECURE is my app and ProgramManager is a windows proc.  I'm just not clear on how I correlate the addresses on the stack to address in my program.  My addresses are all much lower like 004xxxxx while the ones on the stack are 7xxxxxxx.  ShowIndexInfo(unsigned long, unsigned long)
ShowMSH_IndexDat(unsigned long)
  are both my procedures called by my app.  Since they are still on the stack could that mean the error is in one or both of them?

best regards,

czDrillard
Posted on 2005-08-28 23:26:20 by czDrillard

I'm just not clear on how I correlate the addresses on the stack to address in my program.  My addresses are all much lower like 004xxxxx while the ones on the stack are 7xxxxxxx

Main process will be 004xxxxx, DLL modules will depend on a couple of things (use /BASE:xxx when linking the libraries).


ShowIndexInfo(unsigned long, unsigned long)
ShowMSH_IndexDat(unsigned long)  are both my procedures called by my app.  Since they are still on the stack could that mean the error is in one or both of them?

It depends on how far your errors propagate; from the stack trace it would seem like the wndproc calls indexdat which in turn calls showindexinfo (I originally mistook these for some obscure shell functions :)).

I would try putting a breakpoint on ShowMSH_IndexDat, then "step over" (rather than "step into") the call to ShowIndexInfo. If this causes a crash, you have narrowed down the bug location, and should the try stepping into the ShowIndexInfo call, and notice when the crash happens, and why.
Posted on 2005-08-29 00:24:28 by f0dder
Thanks, now I do some work and less talking.  I'll post the outcome so others avoid my mistake.  (If I find it  ;))

best regards,

czDrillard
Posted on 2005-08-29 02:30:01 by czDrillard
It would be better if you post the line the code crashes (and some asm code before and after the crash instruction). Also posting a register dump would be helpful.

Personally there are 3 reasons why you can get a crash.
1) You pass the wrong parameter to a function (Very tricky bug to hunt down).
2) You did not preserve some register.
3) Stack thrashing.
Posted on 2005-08-29 06:58:26 by roticv
Hello roticv,

Unfortunately I can't find where in my asm code the program is crashing.  Events leading to the crash as follows:

-Display the contensts of mshistory index.dat file.
-select shred
-program overwrites associated index.dat file entries in all index.dat files
-displays success message
-terminates normally

Sometimes, maybe one out of ten or one out of two times during this operation the unhandled exception dialog as mentioned above is displayed and my debugger kicks in.  Sometimes the program vanishes as though exit process called.  There is no consistency in error occurances.

Clicking ok on the Unhandled exception dialog box always leads to this:

stack=NTDLL! 7c9106c3

eax=003a000c
edi=003a003b

7c9106c3 mov byte ptr ,al single stepping does not execute this line.  Instead control jumps to
7c90eaf0 mov ebx, dword ptr
.
.
.
7c90eb10 call 7990e252  jumps back to the exception

does any of this mean anything?

best regards,

czDrillard
Posted on 2005-08-29 12:42:11 by czDrillard
Hmm. So even the exact same sequence of operations only triggers the bug "sometimes"?

This might be a heap related problem, and could be caused by overflowing buffers, or improper use of Global/LocalAlloc - just to name a few culprits. Could also be something to do with thread race conditions, if your app is multithreaded.

Do you, by chance, use the gif/jpg routines by Ernie in the masm32lib?
Posted on 2005-08-29 15:13:57 by f0dder
That's the worst part of the problem...the sequence of events leading to the crash are not necessarily the same as the previous or next sequence making it impossible to analyse in any logical way.  If I hadn't put so much time into this project I'd scrap it now.

There are a few calls to GlobalAllocate but I think I've been pretty careful to ensure buffers aren't being overrun.  I'll check them all again.  Should have used HeapAllocate ;)  The program is multi-threaded but it's still in the main thread when the exception occurs.  I'm not using any routines by Ernie.

best regards,

czDrillard
Posted on 2005-08-29 18:38:59 by czDrillard

There are a few calls to GlobalAllocate but I think I've been pretty careful to ensure buffers aren't being overrun.  I'll check them all again.  Should have used HeapAllocate

HeapAlloc buffers can also be overrun, but at least you don't have the potential locked/unlocked problems. Note that there are a few situations where you *do* have to use local/globalalloc, like when dealing with CreateStreamOnHGlobal and the clipboard.

I'd suggest you to change all memory allocation, reallocation and deallocation to use a set of macros instead of directly using invoke (this will take some editing, but with "find in files" it should be doable without too much effort). This will allow you to change the allocation method around easily.

The real advantage of this is that you can use a "checked" memory allocator - one that matches up allocs/frees, and uses "canaries" to detect buffer overruns... it's a really brilliant thing.
Posted on 2005-08-29 21:07:06 by f0dder


Clicking ok on the Unhandled exception dialog box always leads to this:

stack=NTDLL! 7c9106c3

eax=003a000c
edi=003a003b

7c9106c3 mov byte ptr ,al single stepping does not execute this line.  Instead control jumps to
7c90eaf0 mov ebx, dword ptr
.
.
.
7c90eb10 call 7990e252  jumps back to the exception

does any of this mean anything?


Yeah, it does mean alot of things. f0dder has managed to decode what it means for you.
1) It is a crash in RtlAllocateHeap, which means something went wrong with memory allocation (check all your memory allocation - as suggested by f0dder).
2) btw the control jumps are due to exception handlers which obviously are not working well.
3) Anyway, it looks like RtlpAllocateFromHeapLookaside is not returning a valid memory.

You mentioned that your program does reading of files. Did you do proper memory allocation? Also do attach ProgramManager proc because I get the feeling that the bug is hidding somewhere around it.
Posted on 2005-08-29 22:08:52 by roticv
ProgramManager is 963 kb so I can't post as code and don't see where I can put attachment.  Only other thing I could email it to who ever is interested. I attached code for ShowIndexDat which uses GlobalAlloc and is typical of the procs allocating memory. 


;//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;//displays the contents of the index.dat files
;//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

ShowIndexDat proc uses edi IndexPath:DWORD

    LOCAL  hFile        :DWORD



    invoke RemoveBackSlash,IndexPath
    invoke CreateFile,IndexPath,GENERIC_READ or GENERIC_WRITE,\
                      FILE_SHARE_READ or FILE_SHARE_WRITE,NULL,\
                      OPEN_EXISTING,NULL,NULL

    mov hFile,eax
    cmp eax,-1        ;//open index.dat file
    jz @not_exist

    invoke GetFileSize,hFile,ADDR FileSize
    mov IndexSize,eax
push eax
    invoke dwtoa,eax,ADDR szCurrentIndexSize
pop eax
    mov edi,OFFSET szCurrentIndexSize
    xor ecx,ecx
    xor eax,eax
    mov ecx,-1
    cld
    repne scasb
    not ecx
    cmp ecx,03h
    jle @f
    sub ecx,01h
    invoke CommaProc,ADDR szCurrentIndexSize,ecx
    invoke lstrcpy,ADDR szCurrentIndexSize,ADDR szTotalBytes
   
    invoke GlobalAlloc,GMEM_MOVEABLE or GMEM_ZEROINIT,IndexSize
    mov hMemory,eax
    invoke GlobalLock,hMemory
    mov ptrMemory,eax
    invoke ReadFile,hFile,ptrMemory,IndexSize,ADDR WriteSize,NULL

    mov edi,ptrMemory  ;//copy file to memory
    mov ecx,IndexSize
    cld

    @@:
    push ecx
    invoke SendMessage,hwndProgress,PBM_STEPIT,0,0
    sub CurrentStep,1
    pop ecx
    cmp ecx,00h
    jle @f
    xor eax,eax   
    mov al,55h
    repne scasb
    cmp ecx,00h
    jle @f
     
    mov al,
    cmp al,52h
    jnz @b

    inc edi
    dec ecx
    mov al,
    cmp al,04ch
    jnz @b
    inc edi
    dec ecx
    mov al,
    cmp al,020h
    jnz @b
   
xor eax,eax
mov eax,
sub eax,03h
add edi,eax
    ; add edi,65h          ;//set edi to start of string
    sub ecx,eax
    push edi
    push ecx

    invoke RtlZeroMemory,OFFSET szTempPathBuf,1024
    invoke lstrcpy,ADDR szTempPathBuf,edi  ;//copy index entry
                                            ;//to buffer
    mov dwProtectIndex,00h
    xor eax,eax
    sub edi,02h    ;//edi points 2 bytes before string entry 
    mov al,
    cmp al,0deh    ;//is entry protected?
    jnz @protect
    inc edi
    mov al,
    cmp al,0adh    ;//is entry protected?
    jnz @protect
    mov dwProtectIndex,01h
    jmp lb1

    @protect:
    mov dwProtectIndex,00h

    lb1:
    invoke ShowIndexInfo,addr szTempPathBuf,\
                        ADDR szIndexBytes

    pop ecx
    pop edi

.if ecx>00h
jmp @b

.endif

    @@:
    invoke CloseHandle,hFile
    invoke GlobalUnlock,ptrMemory
    invoke GlobalFree,hMemory
    @not_exist:

    ret

ShowIndexDat endp



Thanks and best regards,

czDrillard
Posted on 2005-08-30 00:05:00 by czDrillard
You are committing a crime.  ;)

Why are you doing

    invoke GlobalUnlock,ptrMemory
    invoke GlobalFree,hMemory


when you don't allocate memory all the time? That's a sin. Also, I don't think you need to convert your filesize to a string just to check the magnitude of the number right? I think a simple compare would do. I would shudder in fear if all your code is like this.  ;)
Posted on 2005-08-30 07:12:56 by roticv
Doh! 

I hope not too roticv.  This is an early proc and I'm hoping the later ones have improved as my experience increased.  I fixed the jumps in this code so I'm not trying to de-allocate memory that's not been allocated.  I've checked all the other GlobalAlloc's and I'm sure each instance is freed and unlocked.

Btw, the string conversion is used in the CommaProc procedure that puts delimiters into the number like: 1234567 ->1,234,567  I guess I should have done the dword to string conversion in that proc just to keep things ordered in a more logical fashion.

Thanks and best regards,

czDrillard
Posted on 2005-08-30 10:50:48 by czDrillard
You are welcome and good luck with your project.  ;)
Posted on 2005-08-30 12:13:25 by roticv