The MASM Forum

Projects => MASM32 => Topic started by: qWord on November 04, 2013, 09:37:17 AM

Title: bug in arralloc / arralloc$()
Post by: qWord on November 04, 2013, 09:37:17 AM
Running under a debugger, the function arrfree / arrfree$() does cause an exception when freeing the memory of the pointer-array (GlobalFree). The actual problem is the function arralloc/arralloc$(), which does write to the unallocated array element [esi+mcnt*4+4]. Furthermore the loop condition should be checked before accessing the array to avoid problems when mcnt == 0.
Quotearralloc proc mcnt:DWORD

  ; ----------------------------------------------------------------
  ; return values = handle of pointer array or 0 on allocation error
  ; ----------------------------------------------------------------
    push esi

    mov eax, mcnt                               ; load the member count into EAX
    add eax, 1                                  ; correct for 1 based array
    lea eax, [0+eax*4]                          ; multiply it by 4 for memory size

    invoke GlobalAlloc,GMEM_FIXED,eax
    mov esi, eax

    test eax, eax                               ; if allocation failure return zero
    jz quit

    mov eax, esi
    mov ecx, mcnt
    mov DWORD PTR [eax], ecx                    ; write count to 1st member

    xor edx, edx
  @@:
    add edx, 1                                  ; write adress of null string to all members
    mov [eax+edx*4], OFFSET d_e_f_a_u_l_t__n_u_l_l_$
    cmp edx, ecx
    jle @B <----------- should be JL or JB

    mov eax, esi                                ; return pointer array handle

  quit:
    pop esi

    ret

arralloc endp
Title: Re: bug in arralloc / arralloc$()
Post by: dedndave on November 04, 2013, 10:09:19 AM
i seem to recall we had troubles with something related a couple years ago

http://www.masmforum.com/board/index.php?topic=17159.0 (http://www.masmforum.com/board/index.php?topic=17159.0)
Title: Re: bug in arralloc / arralloc$()
Post by: jj2007 on November 04, 2013, 10:43:22 AM
It could also be shortened a little bit:

arralloc proc mcnt:DWORD

  ; ----------------------------------------------------------------
  ; return values = handle of pointer array or 0 on allocation error
  ; ----------------------------------------------------------------
    mov eax, mcnt                         ; load the member count into EAX
    push eax
    lea eax, [eax*4+4]                    ; correct for 1 based array, multiply it by 4 for memory size

    invoke GlobalAlloc,GMEM_FIXED,eax

    test eax, eax                        ; if allocation failure return zero
    pop ecx
    jz quit

    mov DWORD PTR [eax], ecx             ; write count to 1st member

  @@:
    mov [eax+ecx*4], OFFSET d_e_f_a_u_l_t__n_u_l_l_$
    dec ecx
    ja @B

; return pointer array handle

  quit:

    ret

arralloc endp
Title: Re: bug in arralloc / arralloc$()
Post by: dedndave on November 04, 2013, 11:04:19 AM
 :biggrin:  a little tidier...
    mov     ecx,mcnt
    lea     eax,[4*ecx+4]
    push    ecx
    INVOKE  GlobalAlloc,GMEM_FIXED,eax
    test    eax,eax
    pop     ecx
    jz      quit
Title: Re: bug in arralloc / arralloc$()
Post by: jj2007 on November 04, 2013, 11:22:58 AM
Oops, you are right, the pop must come before the jz :redface:
Title: Re: bug in arralloc / arralloc$()
Post by: dedndave on November 04, 2013, 11:32:50 AM
well - maybe not - there is always LEAVE
but - it's clearer if you pop first

it wouldn't cost anything to preserve EBX, ESI, or EDI for that value
Title: Re: bug in arralloc / arralloc$()
Post by: hutch-- on November 04, 2013, 01:26:49 PM
The problem I have had with these algos is that every time someone had a problem you suggested a mod then never got any feedback so I was always left in the lurch as to whether they worked properly.
Title: Re: bug in arralloc / arralloc$()
Post by: jj2007 on November 04, 2013, 06:48:56 PM
Quote from: dedndave on November 04, 2013, 11:32:50 AM
it wouldn't cost anything to preserve EBX, ESI, or EDI for that value

What's the advantage of using ebx instead of ecx?
Title: Re: bug in arralloc / arralloc$()
Post by: dedndave on November 04, 2013, 09:24:57 PM
i guess the main advantage is, it's easier to read :)

the cost is - you push/pop EBX (or ESI or EDI) at entry and exit
which is ok - it replaces a push/pop on ECX - so no cost, really
arralloc proc uses ebx mcnt:DWORD

  ; ----------------------------------------------------------------
  ; return values = handle of pointer array or 0 on allocation error
  ; ----------------------------------------------------------------
    mov ebx, mcnt                         ; load the member count into EBX
    lea eax, [ebx*4+4]                    ; correct for 1 based array, multiply it by 4 for memory size
    invoke GlobalAlloc,GMEM_FIXED,eax
    test eax, eax                        ; if allocation failure return zero
    jz quit

    mov DWORD PTR [eax], ebx             ; write count to 1st member

  @@:
    mov [eax+ebx*4], OFFSET d_e_f_a_u_l_t__n_u_l_l_$
    dec ebx
    ja @B

; return pointer array handle

  quit:
    ret

arralloc endp
Title: Re: bug in arralloc / arralloc$()
Post by: qWord on November 06, 2013, 04:12:43 AM
Quote from: hutch-- on November 04, 2013, 01:26:49 PM
The problem I have had with these algos is that every time someone had a problem you suggested a mod then never got any feedback so I was always left in the lurch as to whether they worked properly.
to give a feed back now, I would use the following version, which avoids partial flag stalls, access the memory in ascending order and also handle the case mcnt==0:
stackframe off
align 16
arralloc2 proc mcnt:DWORD

  ; ----------------------------------------------------------------
  ; return values = handle of pointer array or 0 on allocation error
  ; ----------------------------------------------------------------
    mov eax, [esp+4]                     ; load the member count into EAX
    push eax
    lea eax, [eax*4+4]                   ; correct for 1 based array, multiply it by 4 for memory size
    invoke GlobalAlloc,GMEM_FIXED,eax
    test eax, eax                        ; if allocation failure return zero
    pop edx                              ; load the member count into EDX
    jz quit
     
    mov [eax],edx                        ; write count to 1st member
    and ecx,0                            ; loop alignment
    jmp @1
@@: db 3Eh                               ; DS prefix for alignment
    mov [eax+ecx*4+4], OFFSET d_e_f_a_u_l_t__n_u_l_l_$
    add ecx,1
@1: cmp ecx,edx
    jb @B

    ; return pointer array handle

  quit:
    ret 4

arralloc2 endp
stackframe on


Generally, how should one report bugs in the MASM32 SDK? Over the time I've got the impression that a subforum is not that efficient...
Title: Re: bug in arralloc / arralloc$()
Post by: hutch-- on November 06, 2013, 04:38:29 AM
Its probably the case that I am not always that efficient. I have to find the originals, the test pieces then enough brain space to digest the problem and I don't always have the time. I do have a good look at the posted problems but don't always have the time/brain space to work on it.
Title: Re: bug in arralloc / arralloc$()
Post by: dedndave on November 06, 2013, 05:01:57 AM
as i recall, we had a lot of participation in the old forum on this set of routines
and we resolved the problem as it was reported
but this is a slightly different issue, i think

qWord is a great coder
but........
if they call the function with 0, they get what they deserve   :lol:
aligning short loops yields little advantage, if any
Title: Re: bug in arralloc / arralloc$()
Post by: qWord on November 06, 2013, 06:02:05 AM
Quote from: dedndave on November 06, 2013, 05:01:57 AMif they call the function with 0, they get what they deserve   :lol:
you should think out of the box ;)

Quote from: dedndave on November 06, 2013, 05:01:57 AMaligning short loops yields little advantage, if any
the cost are minimal in this case, thus we should use that potential.
Title: Re: bug in arralloc / arralloc$()
Post by: dedndave on November 06, 2013, 06:10:06 AM
Quote from: qWord on November 06, 2013, 06:02:05 AM
you should think out of the box ;)

:biggrin:
giving you a hard time - lol
Title: Re: bug in arralloc / arralloc$()
Post by: dedndave on November 06, 2013, 06:47:54 AM
well - to be fair.....
if you are going to test for 0, do it before allocating any space   :P
arralloc proc uses ebx mcnt:DWORD

  ; ----------------------------------------------------------------
  ; return values = handle of pointer array or 0 on allocation error
  ; ----------------------------------------------------------------
    mov ebx, mcnt                         ; load the member count into EBX
    test ebx, ebx
    mov eax, ebx
    jz  quit
Title: Re: bug in arralloc / arralloc$()
Post by: qWord on November 06, 2013, 07:15:21 AM
Quote from: dedndave on November 06, 2013, 06:47:54 AMif you are going to test for 0, do it before allocating any space
As being a dynamic data structure, it should be allowed to create a empty array (at least that is my humble opinion).
Title: Re: bug in arralloc / arralloc$()
Post by: jj2007 on November 06, 2013, 09:52:47 AM
Quote from: qWord on November 06, 2013, 07:15:21 AMAs being a dynamic data structure, it should be allowed to create a empty array

Semi-dynamic, maybe. Example from hlhelp.chm:
LOCAL hArray  :DWORD
......
mov hArray, arralloc$(2048)
......
mov hArray, arrealloc$(hArray,4096)


Slightly more dynamic:
include \masm32\MasmBasic\MasmBasic.inc        ; download (http://masm32.com/board/index.php?topic=94.0)
  Init                        ; ## create a dynamic string array ##
  Dim My$()
  xor ecx, ecx
  .Repeat
        Let My$(ecx)=Str$("String %i", ecx)
        inc ecx
  .Until ecx>=20000
  Inkey "ok"
  Exit
end start


But in both cases, a "true" empty array makes little sense. You wouldn't create it if you didn't want to use it, right?

P.S.: Your version is better than mine. I had not thought of accessing memory from bottom to top. I wonder, however, if the direction really matters. Testbed?  ;)

Here it is:
Intel(R) Celeron(R) M CPU        420  @ 1.60GHz (SSE3)
9947    kCycles for 5 * down
10274   kCycles for 5 * up

10205   kCycles for 5 * down
10284   kCycles for 5 * up

10155   kCycles for 5 * down
10212   kCycles for 5 * up

35      bytes for down
38      bytes for up
Title: Re: bug in arralloc / arralloc$()
Post by: qWord on November 06, 2013, 10:39:10 AM
OK, I didn't consider the reallocation strategy, which change the pointer/handle. Regardless that, under certain conditions it can make sense to have empty containers.