[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

a bug in printf_fp

From: Cui Huimin
Subject: a bug in printf_fp
Date: Thu, 20 Jan 2005 11:40:24 +0800

    This bug exists in the printf_fp function when glibc is compiled with option -O0, and is related to the x86 instruction(bsf). Following is the bug description:
    Now let's read the following code piece(line 751-762, printf_fp.c,glibc-2.3.1):
              if (exponent > 0)
                   int cnt_l;
                   cy = __mpn_mul_1 (tmp, frac, fracsize, 10);
                   tmpsize = fracsize;
                   assert (cy == 0 || tmp[tmpsize - 1] < 20);
                   count_trailing_zeros (cnt_l, tmp[0]);
                   if (cnt_l < MIN (4, exponent))
                       cy = __mpn_lshift (frac, tmp, tmpsize,
                       BITS_PER_MP_LIMB - MIN (4, exponent));
                       if (cy != 0)
                          frac[tmpsize++] = cy;
                     (void) __mpn_rshift (frac, tmp, tmpsize, MIN (4, exponent));
                fracsize = tmpsize;
                exp10 |= 1;
               assert (frac[fracsize - 1] < 10);
    Note the statement :count_trailing_zeros (cnt_l, tmp[0]); On X86 machines, it will be expanded as a bsf instructon, using the macro defined in longlong.h(line 375,glibc-2.3.1):
        #define count_trailing_zeros(count, x) \
             __asm__ ("bsfl %1,%0" : "=r" (count) : "rm" ((USItype)(x)))
    The series assembly instructions are:
   610ee: 8b 45 9c              mov    0xffffff9c(%ebp),%eax    //0xffffff9c(%ebp) is &tmp[0] ,&& tmp[0]==0
   610f1: 0f bc 00              bsf    (%eax),%eax              //Since (%eax) is zero, %eax is undefined, and keeps no change here
   610f4: 89 85 68 ff ff ff     mov    %eax,0xffffff68(%ebp)    //0xffffff68(%ebp) is cnt_l, and will be used at address 6111c. But it is                                                                         undefined
   610fa: 8b 45 b0              mov    0xffffffb0(%ebp),%eax   
   610fd: 89 85 e0 fe ff ff     mov    %eax,0xfffffee0(%ebp)
   61103: 83 bd e0 fe ff ff 04  cmpl   $0x4,0xfffffee0(%ebp)
   6110a: 7e 0a                 jle    61116 <__printf_fp+0x165a>
   6110c: c7 85 e0 fe ff ff 04  movl   $0x4,0xfffffee0(%ebp)
   61113: 00 00 00
   61116: 8b 95 e0 fe ff ff     mov    0xfffffee0(%ebp),%edx
   6111c: 39 95 68 ff ff ff     cmp    %edx,0xffffff68(%ebp)
   In our example, at address 610f1, %eax is a local variable's address, which is 0xbff..... in x86,  and (%eax) is zero. Base on the x86's manual, if the src of bsf instruction is zero, the its dest should be undefined. So At address 610f4, %eax is undefined. But it is directly used at address 610f4, and we think it is dangerous.
    The program runs well because the first bit of stack address is set, so the comparasion at 6111c (where %edx is zero) fails. Suppose the first bit of stack address is cleared, for example 0x2......., the program will fail.
    We think the undefined register should not be referenced directly. So after 610f1, eax should be checked.
Our test example is very simple:
#include <stdio.h>
float a=0.56;
int   b=0;
int main(){
        printf("double a=%f\n",a);
        return 0;
and the compile command is :gcc -o pf pf.c -g  

Best Regards´╝ü
Chenggang Wu, Cui Huimin

reply via email to

[Prev in Thread] Current Thread [Next in Thread]