News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

HeapAlloc / WriteFile access violation

Started by IanScott, November 26, 2013, 08:48:30 AM

Previous topic - Next topic

IanScott

HeapAlloc / WriteFile

I am working on an program to find and replace text in all files in a folder. The user selects a folder, the file
extension of the files to be searched, the text to search for and the replacement text. Each file in the folder
with the nominated extension is then searched and all instances of the text to search for are replaced with the
replacement text.

To improve my general knowledge and to allow for really long records, I am using HeapAlloc to grab memory for each
record that is read. I am also using HeapAlloc to grab memory for each record edit.

In the code below, the program fails with an Access Violation when WriteFile is executed in the editFile proc. This
is after returning from the replSubString proc where memory has been allocated using HeapAlloc. The pointer to the allocated
memory is in eax upon return from the replSubString proc.

The variables used to hold return values from GetProcessHeap and HeapAlloc are global. I have tried hard coding the length
written by WriteFile as well as resetting the file pointer just prior to writing using SetFilePointer to no avail.

Hope you can help.

Thanks
Ian Scott


include \masm32\include\masm32rt.inc

.data

hFile dd ?
bytesRead dd ?

hHeap dd ?
heapRecord dd ?
heapBuffer1 dd ?
heapBuffer2 dd ?

.code

FileEditStart:
invoke GetModuleHandle, NULL
mov hModule, eax

invoke GetProcessHeap
mov hHeap, eax

................

invoke editFile, addr win32FindData.cFileName, [searchText], [replaceText]

................


; ------------------------------------------------------------------------------------------
; Performs a search and edit operation on a single file. Each record is read, examined and
; edited if the text being searched for is found.
; ------------------------------------------------------------------------------------------
editFile proc fileName:DWORD, searchText:DWORD, replaceText:DWORD

Local written:LPDWORD
Local fileSize:DWORD
Local filePosition:DWORD ; current position in the file. Used by SetFilePointer
Local recordIn:DWORD ; pointer to a record from the file being edited
Local edited:BYTE ; indicates if the file was edited

; Open the file
invoke CreateFile, [fileName], GENERIC_READ+GENERIC_WRITE, FILE_SHARE_READ+FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_ARCHIVE, NULL
mov hFile, eax

invoke GetFileSize, hFile, NULL
mov fileSize, eax

_checkEOF: ; Check for end of file
cmp [filePosition], [filesize]
je _closeFile
invoke SetFilePointer, hFile, [filePosition], NULL, FILE_BEGIN

_readFile: ; Read a record from the file: reads up to the CR
invoke readLine, hFile ;<======= HeapAlloc used in here to allocate memory for record read
mov recordIn, eax

; Look for the string to replace within the record: Position returned in eax if found.
invoke findSubString, [recordIn], [searchText]
cmp eax, 0
jl _moveFilePtr

; Replace the text within the record
invoke replSubString, [recordIn], [searchText], [replaceText], eax

; Write the edited record back to the file
mov recordIn, eax
push eax
invoke lstrlenA, eax
invoke WriteFile, hFile, [recordIn], eax, [written], NULL   ;<===== FAILS HERE

.....................

editFile endp


; ------------------------------------------------------------------------------------------
; Replaces a substring within a string.
;
; string The string containing the substring
; substring The substring to be replaced
; replaceWith The substring will be replaced with this string
; replaceAt The starting position of the substring to be replaced
;
; ------------------------------------------------------------------------------------------
replSubString proc string:DWORD, substring:DWORD, replaceWith:DWORD, replaceAt:DWORD

invoke HeapAlloc, hHeap, HEAP_NO_SERIALIZE, 8000h ; 32k
mov heapBuffer1, eax ; Section of the string before the substring

invoke HeapAlloc, hHeap, HEAP_NO_SERIALIZE, 8000h ; 32k
mov heapBuffer2, eax ; Section of the string after the substring

; From the beginning of the string to the point where the substring will be replaced
invoke lstrcpyn, [heapBuffer1], [string], [replaceAt]

; From the end of the substring to be replaced to the end of the string
invoke lstrlenA, [substring]
mov ecx, eax
add ecx, [replaceAt] ; Add the starting position of the substring to be replaced
push string
add string, ecx
invoke lstrcpy, [heapBuffer2], [string]
pop string

; Append the replacement text for the substring to the first part of the string
mov edi, [heapBuffer1]
add edi, [replaceAt]
dec edi ; -1 to line up on last byte before null char
invoke lstrcpy, edi, [replaceWith] ; append the replacement string to the beginning.

; Append the end of the string after the replaced substring
invoke lstrlenA, edi
add edi, eax
invoke lstrcpy, edi, [heapBuffer2]
invoke HeapFree, hHeap, HEAP_NO_SERIALIZE, heapBuffer2

mov eax, [heapBuffer1]
ret
replSubString endp

; ------------------------------------------------------------------------------------------
; Reads a line of text from a file up to and including the CR character. Replaces the CR
; character with a null character.
;
; return eax : A pointer to the line that was read from the file.
; ------------------------------------------------------------------------------------------
readLine proc fileHandle:DWORD

invoke HeapAlloc, hHeap, HEAP_NO_SERIALIZE, 8000h ; 32k
mov heapRecord, eax

invoke ReadFile, fileHandle, heapRecord, 8000h, addr bytesRead, NULL

; Find the position of CR in the line just read
mov ecx, bytesRead
mov edi, [heapRecord]
mov al, 0dh
repne scasb

mov al, 00h
mov [edi], al ; One byte past CR or at the end of the string
mov eax, heapRecord

ret
readLine endp


Added code tags.

qWord

You should check the return values of API calls and handle the error cases, especially when allocating memory.
e.g.:
invoke CreateFile,...
.if eax != INVALID_HANDLE_VALUE
    ; ...
.else
    ; error case
    print "CreateFile fails: "
    print LastError$(),13,10
.endif

Commonly such constructs help to find the buggy code...

BTW:  the "[written]" in the WriteFile-call looks suspicious.
MREAL macros - when you need floating point arithmetic while assembling!

KeepingRealBusy

I ran into similar problems using XP in 2005. After much discussion with MS, their suggestion was that I should use VirtualAlloc instead. I switched and the problems went away. I have never used HeapAlloc again.

Dave.