News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Small problem with dwtoa documentation

Started by MichaelW, December 04, 2005, 12:01:31 AM

Previous topic - Next topic

MichaelW

The documentation for the MASM32 dwtoa procedure (and sstr$ macro) fails to mention that the procedure cannot properly handle values that are outside of the range +2147483647 to –2147483648. It seems that INVOKE cannot detect that a signed value is out of range even when the parameter has type SDWORD.

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    include \masm32\include\masm32rt.inc

    _dwtoa PROTO :SDWORD,:DWORD
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    .data
       buff db 30 dup(0)
    .code
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
start:
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    invoke dwtoa,2147483647,ADDR buff
    print ADDR buff,13,10
    invoke dwtoa,2147483648,ADDR buff
    print ADDR buff,13,10
    invoke dwtoa,-2147483648,ADDR buff
    print ADDR buff,13,10
    invoke dwtoa,-2147483649,ADDR buff
    print ADDR buff,13,10,13,10

    invoke _dwtoa,2147483647,ADDR buff
    print ADDR buff,13,10
    invoke _dwtoa,2147483648,ADDR buff
    print ADDR buff,13,10
    invoke _dwtoa,-2147483648,ADDR buff
    print ADDR buff,13,10
    invoke _dwtoa,-2147483649,ADDR buff
    print ADDR buff,13,10,13,10
   
    invoke crt__ltoa,2147483647,ADDR buff,10
    print ADDR buff,13,10
    invoke crt__ltoa,2147483648,ADDR buff,10
    print ADDR buff,13,10
    invoke crt__ltoa,-2147483648,ADDR buff,10
    print ADDR buff,13,10
    invoke crt__ltoa,-2147483649,ADDR buff,10
    print ADDR buff,13,10

    mov   eax, input(13,10,"Press enter to exit...")
    exit
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
_dwtoa proc dwValue:SDWORD, lpBuffer:DWORD

    ; -------------------------------------------------------------
    ; convert DWORD to ascii string
    ; dwValue is value to be converted
    ; lpBuffer is the address of the receiving buffer
    ; EXAMPLE:
    ; invoke dwtoa,edx,ADDR buffer
    ;
    ; Uses: eax, ecx, edx.
    ; -------------------------------------------------------------

    push ebx
    push esi
    push edi

    mov eax, dwValue
    mov edi, [lpBuffer]

    test eax,eax
    jnz sign

  zero:
    mov word ptr [edi],30h
    jmp dtaexit

  sign:
    jns pos
    mov byte ptr [edi],'-'
    neg eax
    add edi, 1

  pos:
    mov ecx, 3435973837
    mov esi, edi

    .while (eax > 0)
      mov ebx,eax
      mul ecx
      shr edx, 3
      mov eax,edx
      lea edx,[edx*4+edx]
      add edx,edx
      sub ebx,edx
      add bl,'0'
      mov [edi],bl
      add edi, 1
    .endw

    mov byte ptr [edi], 0       ; terminate the string

    ; We now have all the digits, but in reverse order.

    .while (esi < edi)
      sub edi, 1
      mov al, [esi]
      mov ah, [edi]
      mov [edi], al
      mov [esi], ah
      add esi, 1
    .endw

  dtaexit:

    pop edi
    pop esi
    pop ebx

    ret

_dwtoa endp
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
end start


2147483647
-2147483648
-2147483648
2147483647

2147483647
-2147483648
-2147483648
2147483647

2147483647
-2147483648
-2147483648
2147483647

eschew obfuscation

Jimg

So this is yet another bug of invoke, not dwtoa.  The dw means 32 bits.  Aren't those the maximums you can represent in a signed 32 bit word?

MichaelW

The returned strings for the values 2147483648 and –2147483649 are not correct because the value is out of range. I added a test of the CRT _ltoa function to the code and it behaves the same as dwtoa. I am not suggesting that this is a bug in dwtoa, or invoke, or _ltoa. The CRT has seen too much scrutiny for this behavior to be anything other than by design. I do think, however, that silently returning an incorrect value is not the best design, and this behavior should at least be documented.

eschew obfuscation

GregL

MASM doesn't complain until you hit 4294967296 which is ULONG_MAX + 1. It doesn't matter whether you use invoke or push+call.

I agree, dwtoa should be able to handle all unsigned values, 0 to 4294967295. With standard convention a dw prefix means unsigned and an l prefix means signed. There is an ltoa function in MASM32 that does the exact same thing that dwtoa does. dwtoa could be rewritten without breaking old programs (unless it is being used to print negative values).  

MASM seems to pretty much just treat SDWORD as an alias for DWORD. The only time it makes a difference, that I can think of, is when doing .IF compares. I like to use it for documentation purposes to differentiate signed vs. unsigned.

Jimg

I must be missing something here, but dwtoa is returning the correct signed value.  –2147483649 is not a possible value in a 32 bit word.  It's invoke that's screwing up by passing the incorrect value.  If you want a purely unsigned dwtoa, that should easy to make.  If you are just saying the documentation for dwtoa should say SIGNED dword, then I agree.

Actually, it's masm in general that's screwing up.  Try-

        push -2147483649

and run it throug  debug.  This comes out to
   
       push 7FFFFFFF

which is the truncated value.  There should have been a warning of some kind.

GregL

JimG,

I see what you are saying about the truncation with -2147483649 and 2147483648. MASM should give an error.

Visual C++ gives a warning about printf("(LONG_MIN - 1) = %d \n", -2147483649); and prints 2147483647.

But no warning aboutprintf("(LONG_MAX + 1) = %d \n", 2147483648); and prints -2147483648.



MASM does give an error about push 4294967296
error A2084: constant value too large
But Visual C++ gives no warning or error about
printf("ULONG_MAX+1 = %u \n", 4294967296); and prints 0.



Quotethe documentation for dwtoa should say SIGNED dword
at least  :thumbu