|
From: | Cui Huimin |
Subject: | a bug in printf_fp |
Date: | Thu, 20 Jan 2005 11:40:24 +0800 |
Hi,
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; } else (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 |
[Prev in Thread] | Current Thread | [Next in Thread] |