News:

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

FloatToStr2 bug

Started by CDW, June 04, 2007, 11:51:33 AM

Previous topic - Next topic

CDW

OS: Win XP SP1,SP2
MASM32 v9.0

Writing some infix/postfix interpreter stuff, i got some kind of a bufferoverflow with
this term: 1/11(-1)*3

It turned out that FloatToStr2, used in this kind:

mycallback proc

LOCAL num1_string [20]:BYTE

invoke FloatToStr2,num1,addr num1_string
invoke Output,addr num1_string,0


needs sometimes 21 Bytes insteat of 19
quote from MASMLIB help:
Quote
Comments
The buffer for the string should be at least 19 bytes long as the procedure
always write an 18 byte long string in szDbl. For alignment considerations,
a 20 byte long buffer is recommended.

Here some (quick&dirty) code:



.486
.model flat,stdcall
option casemap:none

include \masm32\include\windows.inc
include \masm32\include\masm32.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
   
;     libraries
;     ~~~~~~~~~
includelib \masm32\lib\masm32.lib

includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib   

mycallback proto   
; ««««««««««««««««««««««««««««««««««««««««««««««««««
.data
hInstance dd 0
.code
start:     
      invoke GetModuleHandle,NULL
      mov hInstance,eax
      invoke mycallback
      invoke ExitProcess,0

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««


mycallback proc
LOCAL num1_string [20]:BYTE


.data
  mynum REAL8 -0.0909090909090909116
.code
invoke FloatToStr2,mynum,addr num1_string

ret
mycallback endp
end start


using ollydbg you can step over the mycallback call

00401007  |.  A3 00304000   MOV DWORD PTR DS:[403000],EAX
0040100C  |.  E8 07000000   CALL rechner.00401018
00401011  |.  6A 00         PUSH 0                                   ; /ExitCode = 0


and see, that last byte of the EBP value is changed
(i know, this is because of the proc-macro ;) :

00401018  /$  55            PUSH EBP
00401019  |.  8BEC          MOV EBP,ESP
0040101B  |.  83C4 EC       ADD ESP,-14

....

LEAVE
ret

EBP is pushed onto stack and than LOCAL reserve the 20 bytes buffer, FloatToStr2 writes 21 bytes
to this buffer -> "saved" EBP value is changed ->LEAVE and RET ->EBP changed

I think this is because of (some code from fptoa2.asm)


; Check for a negative number.

    .if (sdword ptr [fpin][4] < 0)
      and byte ptr [fpin][7], 07fh ; change to positive
      mov byte ptr [edi], '-' ; store a minus sign
      inc edi
    .endif

1 sign byte + inserting "0." (2 bytes) + rep movsb (16 bytes)=1+2+16+1=20

.IF (SDWORD PTR ecx <= 0)
        mov word ptr [edi], '.0'  <--- +2 Bytes
add edi, 2
neg ecx
mov al, '0'   <--- +1 Byte
rep stosb
mov ecx, 16
      .ELSE
        rep movsb
        mov byte ptr [edi], '.'
        inc edi
        mov ecx, 16
        sub ecx, [iExp]
      .ENDIF
      rep movsb   <---------+16 Bytes

after all, EDI points to [EDI+20] and


; Clean up and go home.

ftsExit:
    mov byte ptr [edi], 0

writes the 0 "outside" of the buffer.

Of course, using buffers >20 bytes is a work around, but it would be better to fix that bug ;).

   




raymond

QuoteOf course, using buffers >20 bytes is a work around, but it would be better to fix that bug ;).

Or use the FpuFLtoA in the fpu.lib. :8)

BTW, initializing a REAL8 with a value containing more than 16 significant digits is not of much use. The excess digits may be used by some ascii-to-fp algos but would be lost anyway when the float is rounded and stored with REAL8 precision.

Raymond
When you assume something, you risk being wrong half the time
http://www.ray.masmcode.com

CDW

Quote from: raymond on June 05, 2007, 01:04:50 AM
BTW, initializing a REAL8 with a value containing more than 16 significant digits is not of much use. The excess digits may be used by some ascii-to-fp algos but would be lost anyway when the float is rounded and stored with REAL8 precision.
Raymond
This is only a working example to show this bug   :wink. .
I got this "bufferoverflow" in my application during the calculation of this term: 1/11(-1)*3,
and I am using a REAL8/QWORD to store the FPU result and pass the value to the FloatToStr2. -0.0909090909090909116 is the value in ST(0) after 1/11*(-1)  (copied out to the example code from OllyDbg FPU-output). This value is passed (in ST(0)) to my callback procedure, the procedure pop it in a REAL8, call FloatToStr2 and output this string, so this is not my "standard" initialisation value :wink:


 
Off topic: (application is fixed and works fine, but maybe someone is interested in it)
complete code:

mycallback proc

LOCAL num1_string [20]:BYTE
LOCAL num2_string [20]:BYTE
LOCAL num1:QWORD
LOCAL num2:QWORD
;in ST0,ST1 beide Zahlen
;in eax operator

fstp qword ptr [num1]
cmp al,'='
je @f ;bei = nur einen Operator ausgeben
  fst qword ptr [num2]
@@:
fld qword ptr [num1] ;widerherstellen

movzx ebx,al
mov dword ptr[num2_string],ebx
invoke FloatToStr2,num1,addr num1_string

cmp bl,'='
jne @f
  invoke Output,addr num2_string,0
  invoke Output,addr num1_string,0
  invoke Output, addr CRLF,0
  ret
@@: ;ansonsten: x+y

invoke Output,addr num1_string,0 ;x

invoke Output,addr num2_string,0 ;OP
invoke FloatToStr2,num2,addr num2_string
invoke Output,addr num2_string,0 ;y


ret

mycallback endp

Ok - this is some kind of quck&dirty code, but it works fine - it takes in eax a math operator (ascii) and if it is not '=' ->  pop ST(0), output it, output the operator and the second value, then restore the poped value and return. If the operator is '=' -> output only ST(0)


Here the code and the binary. You can enter (first input field) infix-terms like (1.2+(3-4)*123.123) or (second input field) postfix terms like 1 2 + 3 4+ *


[attachment deleted by admin]