snprintf会在末尾加上一个‘\0',来标记字符串的结束,编译运行程序,得到的是一个死循环,通过gdb调试查看其汇编代码,发现一些异常.
gdb ./tas
set disassembly-flavor intel
disassemble main
在数据初始化部分的代码片断如下:
0x0804848e < 10>: mov DWORD PTR [esp 0x2c],0x0
0x08048496 < 18>: mov DWORD PTR [esp 0x10],0x0
0x0804849e < 26>: mov DWORD PTR [esp 0x14],0x1
0x080484a6 < 34>: mov DWORD PTR [esp 0x18],0x2
0x080484ae < 42>: mov DWORD PTR [esp 0x1c],0x3
0x080484b6 < 50>: mov DWORD PTR [esp 0x20],0x4
0x080484be < 58>: jmp 0x8048522 <main 158>
0x080484c0 < 60>: mov eax,DWORD PTR [esp 0x2c]
0x080484c4 < 64>: mov ecx,DWORD PTR [esp eax*4 0x10]
0x080484c8 < 68>: mov edx,0x8048610
0x080484cd < 73>: mov ebx,DWORD PTR [esp 0x2c]
0x080484d1 < 77>: lea eax,[esp 0x27]
0x080484d5 < 81>: add eax,ebx
0x080484d7 < 83>: mov DWORD PTR [esp 0x8],ecx
0x080484db < 87>: mov DWORD PTR [esp 0x4],edx
0x080484df < 91>: mov DWORD PTR [esp],eax
0x080484e2 < 94>: call 0x8048364 <sprintf@plt>
从代码上基本可以发现在分配变量地址的问题
a[0] --> esp + 0x10
a --> esp + 0x14
a --> esp + 0x18
a --> esp + 0x1c
a --> esp + 0x20
str[0] --> esp + 0x27
.....
str --> esp + 0x2b
i ----> esp + 0x2c
在C语言书中提到字符串数组末尾都会默认添加一个'\0',这里似乎没看到,于是,通过gdb调试,打印地址,来验证假设:
p &i
$1 = (int *) 0xbffff82c
p &str
$2 = 0xbffff82b “\b\001”
p &str
$3 = 0xbffff82c “\001”
地址和i一样,末尾可能真的没有加零,如果将上面的注释替换掉的话,通过执行memset后,i的值已经变成0了.后来发现只有未初始化的字符串末尾均未加'\0',这个之前都没有注意过.