arrfile$ macro causing my program to crash with files with odd numbers of lines

Started by bhy56, August 02, 2011, 06:06:32 PM

Previous topic - Next topic

ToutEnMasm

I have just read a little the source code.He need to be rewrite.There is things useful with text files he don't do and there isn't  a structure to avoid a too big number of parameters in use.

hutch--

bhy56,

Attack a couple of test files, one that works for you and one that crashes for you. It take the guesswork out of trying to solve your problem.
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

ToutEnMasm

Hutch,
If you modify the code add this things:
**** a stucture who gives at least the maximum size of the lines (to avoid memory leak).
**** a variable   who said if the last line is ended by  a 13,10  or not.

hutch--

Here is a test piece with two files, one with 4 lines, the other with 3 lines. Works fine here.


IF 0  ; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
                      Build this template with "CONSOLE ASSEMBLE AND LINK"
ENDIF ; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

    include \masm32\include\masm32rt.inc

    .code

start:
   
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

    call main
    inkey
    exit

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

main proc

    LOCAL array :DWORD
    LOCAL acnt  :DWORD
    LOCAL rval  :DWORD
    LOCAL ptxt  :DWORD
    LOCAL cntr  :DWORD

  ; ------------------------------------------

    mov array, arrfile$("4line.txt")
    mov acnt, arrcnt$(array)
    print str$(acnt)," line count",13,10

    mov cntr, 1
  @@:
    mov ptxt, arrget$(array,cntr)
    print ptxt,13,10
    add cntr, 1
    mov eax, acnt
    cmp cntr, eax
    jle @B
   
    mov rval, arrfree$(array)

  ; ------------------------------------------

    mov array, arrfile$("3line.txt")
    mov acnt, arrcnt$(array)
    print str$(acnt)," line count",13,10

    mov cntr, 1
  @@:
    mov ptxt, arrget$(array,cntr)
    print ptxt,13,10
    add cntr, 1
    mov eax, acnt
    cmp cntr, eax
    jle @B

    mov rval, arrfree$(array)

  ; ------------------------------------------

    ret

main endp

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

end start


Test file 1. 3line.txt


line 1
line 2
line 3


Test file 2. 4line.txt


line 1
line 2
line 3
line 4


Output looks like this.


4 line count
line 1
line 2
line 3
line 4
3 line count
line 1
line 2
line 3
Press any key to continue ...


Yves, it does not need either, the array count is stored in the array at member zero and is retrieved by a function from the address. The memory is deallocated by a function "arrfree$".
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

ToutEnMasm


The max size off the lines is needed by the user if he want to copy the line in a buffer.

dedndave

i am able to repeat bhy56's failure
it seems to be with the arrfile function
more specifically, the get_line_count function

i may have a "handle" on it   :lol
let me play some more....

hutch--

You guys must not read documntation.

Yves,

arrlen$
arrlen$ MACRO arr,indx

gets the stored length of each array member. It is stored 4 bytes below the start address like normal with OLE strings.

Dave,

arrcnt$
arrcnt$ MACRO arr

As in the example above.
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

dedndave

well, get_line_count does not seem to be te culprit, as i thought
i'll come back to that.....

i did find a little potential bug in arrfile
   mov hMem, InputFile(file_name)
   mov flen, ecx
   mov lcnt, rv(get_line_count,hMem,flen)
   mov arr, arralloc$(lcnt)

if the file does not end with a carriage return/line feed pair, get_line_count appends a pair and adds 2 to the size
it returns the updated length in ECX
the "flen" value does not reflect that change, however
this simple change would take care of that
   mov hMem, InputFile(file_name)
   mov lcnt, rv(get_line_count,hMem,ecx)
   mov flen, ecx
   mov arr, arralloc$(lcnt)

it may not make a difference, really
when the array is filled, it probably does not need the last cr/lf
but, it makes the function more useful   :8)

now, for the crash   :P
very strange - i am not sure i understand what is happening, here
i will have to look at the arralloc proc a little closer - it may be overwriting memory that doesn't belong to it
maybe there is something going on that is machine or OS dependant - i dunno

at any rate, by allocating the pbuf buffer before allocating the arr buffer, the crash goes away

original arrfile code (crashes)
   mov hMem, InputFile(file_name)
   mov flen, ecx
   mov lcnt, rv(get_line_count,hMem,flen)
   mov arr, arralloc$(lcnt)
   mov pbuf, alloc(flen)


modified arrfile code (does not crash)
   mov hMem, InputFile(file_name)
   mov lcnt, rv(get_line_count,hMem,ecx)
   mov flen, ecx
   mov pbuf, alloc(flen)
   mov arr, arralloc$(lcnt)


it can be simplified a little more....
   mov hMem, InputFile(file_name)
   mov lcnt, rv(get_line_count,eax,ecx)
   mov flen, ecx
   mov pbuf, alloc(ecx)
   mov arr, arralloc$(lcnt)


now, back to get_line_count
get_line_count proc mem:DWORD,blen:DWORD

 ; mem = address of loaded file
 ; blen = length of loaded file

   mov ecx, blen
   mov edx, ecx
   sub edx, 2
   mov eax, mem
   cmp WORD PTR [eax+edx], 0A0Dh       ; if no trailing CRLF
   je cntlf

   mov WORD PTR [eax+ecx], 0A0Dh       ; append CRLF
   mov BYTE PTR [eax+ecx+2], 0         ; add terminator
   add blen, 2                         ; correct blen by 2

 cntlf:
   or ecx, -1
   xor eax, eax
   mov edx, mem
 @@:
   add ecx, 1
   cmp BYTE PTR [edx+ecx], 0
   je @F
   cmp BYTE PTR [edx+ecx], 10          ; count the line feed character
   jne @B
   add eax, 1
   jmp @B
 @@:

   mov ecx, blen                       ; return count in EAX, length in ECX

   ret

get_line_count endp


not sure why a null is written with the added cr/lf   :P
the allocation is zero-init
the loop looks a little strange
maybe i am off, here, but a single access to memory seems like it would be more efficient
get_line_count proc mem:DWORD,blen:DWORD

 ; mem = address of loaded file
 ; blen = length of loaded file

       mov     edx,mem
       push    ebx
       mov     ecx,blen
       mov     eax,0A0Dh
       xor     ebx,ebx
       cmp     ax,[edx+ecx-2]
       jz      cntlf

       mov     [edx+ecx],ax
       add     ecx,2

cntlf:  mov     eax,ebx
       jmp short cloop1

cloop0: inc     edx
       cmp     bl,0Ah
       jnz     cloop1

       inc     eax

cloop1: mov     bl,[edx]
        or      ebx,ebx
       jnz     cloop0

       pop     ebx
       ret

get_line_count endp


ToutEnMasm


This counter of lines have the same entries as  get_line_count proc mem:DWORD,blen:DWORD.
He is faster .Number of lines in eax



Quote
CompteurLignes PROC uses ebx edi esi pmem:DWORD,taille:DWORD
         Local  Nblines:DWORD,count,reste
         local  theEnd:dword
   ;init
   mov Nblines,0
   mov reste,0   
   mov edx,pmem
   add edx,taille
   mov theEnd,edx
   mov edx,pmem
   mov esi,edx   
   and edx,0Fh
   .if edx != 0
      ;search lines in the non align memory
      mov ecx,16
      sub ecx,edx
      @@:
      .if byte ptr [esi] != 0
         .if word ptr [esi] == 0A0Dh
            inc Nblines         
         .endif
      .else
         mov eax,Nblines
         jmp FindeCompteurLignes
      .endif
      inc esi
      dec ecx
      jnz @B      
   .endif
   ;esi point on a 16 aligned memory
   ;count the number  of 32 bytes parts
   mov edx,0
   mov eax,theEnd
   sub eax,esi
   .if eax == 0
      mov eax,Nblines
      jmp FindeCompteurLignes      
   .endif
   .if eax < 32
      mov reste,eax
      mov eax,Nblines      
      jmp EndNonaligned
   .endif
   mov edx,0
   mov ecx,32
   div ecx
   mov count,eax      
   mov reste,edx
   ;--------------------------  search in aligned part -------------      
   ;init of various register
   mov eax, 0d0d0d0dh   ; Ascii 10, linefeed
   movd xmm6, eax
   pshufd xmm6, xmm6, 0   ; linefeeds for comparison in xmm2   
   mov eax,Nblines   ;line counter
   ;ready
   NewBloc:
      ;------ align 16 needed ----------
      ;1731187 cycles for 22274 lines
      movdqa xmm1,xmm6         ;charge 13
      movdqa xmm2,xmm6         ;charge 13      
      pcmpeqb  xmm1,[esi]      ;cmp with memory align 16      
      pcmpeqb  xmm2,[esi+16]      ;cmp with memory ,align 16                  
      pmovmskb ecx, xmm1 ; result in ecx
      pmovmskb edx, xmm2 ; result +16 edx
      shl edx,16
      add ecx,edx
      jz suite
      NbLineBreak:
      bsf   edx,   ecx
      jz suite
      .if    word   ptr [edx+esi] == 0A0Dh
         inc   eax
      .endif
      btr   ecx,   edx
      jmp NbLineBreak
   suite:
   lea esi,[esi+32]
   dec count
   jnz NewBloc
   
EndNonaligned:   
   .if reste != 0
      mov ecx,reste
      @@:
      .if word ptr [esi] == 0A0Dh
         inc eax
      .endif   
      inc esi
      dec ecx
      jnz @B                  
   .endif
   
FindeCompteurLignes:
ret
CompteurLignes endp


ToutEnMasm

Here the same sample with other routines ( improved)
Made a modify to view the mx size

dedndave

i like it, Yves   :bg
but - it does not use the oleaut32 functions
which - i am not sure what the advantage is in doing so - lol
i read some documents about BSTR's and i now know less than i did before   :red
i can't afford to read many such documents, as i am losing IQ points, fast

ToutEnMasm


perhaps i can enlight you a little on the BSTR.
First they are unicode strings
Second : they are not put anywhere in memory.Its a memory  accessible by com object,like dll implementing an interface and having hard need of shared memory.There is a lot of theorie on the subject.
It's not the case here (hopefully).

bhy56

Quote from: hutch-- on August 04, 2011, 05:59:48 AM
bhy56,

Attack a couple of test files, one that works for you and one that crashes for you. It take the guesswork out of trying to solve your problem.

I tested from one to twenty lines. I did not test with long ( 40 +char ) lines. It does not seem to make any difference if there is a empty line at the end or not. I made these files in notepad.  When it does not work I get a little pause and then "t01.exe has stopped working. Windows can check online for a solution to the problem." I attached two files one that works and one that does not. Notice that I ended the lines with a b if it broke the program, and a w if it worked (when that was the last line in the file). The files look something like this. Notice that there are a few odd numbered lines that worked (namely three and seven) .


one b
two w
three w
four w
five b
six w
seven w
eight w
nine b
ten w
elven b
twelve w
thirteen b
fourteen w
fifteen b
sixteen w
seventeen b
eighteen w
nineteen b
twenty w

dedndave

well - there is something wrong with the arr macros
i fixed one thing, and another pops up
i suspect that the spos macro is crashing for some reason
the oleaut32 stuff seems to be very picky about BSTR's and allocation/deallocation
to make matters worse, the bugs may be OS dependant

jj2007

0       one b
1       two w
2       three w
3       four w
4       five b
5       six w
6       seven w
7       eight w
8       nine b
9       ten w
10      elven b
11      twelve w
12      thirteen b
13      fourteen w
14      fifteen b
15      sixteen w
16      seventeen b
17      eighteen w
18      nineteen b
19      twenty w
0       one b
1       two w
2       three w
3       four w
4       five b
5       six w
6       seven w
7       eight w
8       nine b
9       ten w
10      elven b
11      twelve w
12      thirteen b
13      fourteen w
14      fifteen b
15      sixteen w
16      seventeen b
17      eighteen w
18      nineteen b


The textfiles are ok.

Quoteinclude \masm32\MasmBasic\MasmBasic.inc   ; download
   Init
   Recall "testworked.txt", L1$()
   For_ n=0 To eax-1
      Print Str$(n), Tb$, L1$(n), CrLf$
   Next
   Recall "testbrok.txt", L2$()
   For_ n=0 To eax-1
      Print Str$(n), Tb$, L2$(n), CrLf$
   Next
   Inkey "bye"
   Exit
end start