我在code.c:33中跟踪coredump .
源代码如下:
if (t->options & TAR_GNU)
strncpy(t->th_buf.magic, "ustar ", 8); // here is the coredump
else
....
函数调用堆栈如下:
0x4064d73a in strncpy (__len=8, __src=0x40663b34 "ustar ", __dest=0x4104e5ed "") at /usr/include/i386-linux-gnu/bits/string3.h:121
0x4024e342 in __strncpy_chk () from /lib/i386-linux-gnu/libc.so.6
0x4024ee1a in __chk_fail () from /lib/i386-linux-gnu/libc.so.6
0x40250065 in __fortify_fail () from /lib/i386-linux-gnu/libc.so.6
0x401b739a in ?? () from /lib/i386-linux-gnu/libc.so.6
0x4017d825 in abort () from /lib/i386-linux-gnu/libc.so.6
0x4017a1df in raise () from /lib/i386-linux-gnu/libc.so.6
0x40064424 in __kernel_vsyscall ()
<signal handler called>
sig_coredump (sig=6) at mpm_common.c:1207
t -> th_buf。Magic是tar_header的struct,定义:
struct tar_header{
...;
char magic[6];
char version[2];
...;
}
我很确定strncpy可以这样使用。
在我的例子中,t->th_buf已经有malloc了。
在gdb:(gdb) p t->th_buf
$5 = {name = "/TARFILE.C", ' 00' <repeats 89 times>, mode = "100644 ",
uid = " 41", gid = " 41 ", size = " 207114 ", mtime = "12115070475 ",
chksum = " 00 00 00 00 00 00 00", typeflag = 48 '0', linkname = ' 00' <repeats 99 times>,
magic = " 00 00 00 00 00", version = " 00",
...
虽然您试图将8个字节复制到只有6个空间的缓冲区中,但这通常不会出现问题。
这通常不是问题的原因是,后面紧跟着一个两字节的字符数组,它完全能够接收缓冲区溢出:
struct tar_header{
...;
char magic[6];
char version[2]; // Can absorb extra two chars easily.
...;
}
strncpy
的真正问题是大多数人不了解它是如何工作的。
如果要复制的缓冲区大于指定的大小,它基本上停止在该大小并不再复制,包括字符串末尾的空终止符。
因此,strncpy
可以最终给你的东西是不是一个C字符串,如果你随后试图使用它作为一个C字符串(如传递给strlen
),所有地狱可能会破裂。
这就是为什么我更喜欢使用strlen
检查,然后strcpy
,假设两部分之间的数据不能改变。这样,就可以保证最终得到一个C字符串(或者你事先知道)。
然而,这也不是这里的具体问题。
在调用堆栈中,有一个对检查函数__strncpy_chk
的调用,它像这样:
char *
__strncpy_chk (s1, s2, n, s1len)
char *s1;
const char *s2;
size_t n;
size_t s1len;
{
char c;
char *s = s1;
if (__builtin_expect (s1len < n, 0))
__chk_fail ();
:
rest of function to copy the stuff.
}
因此,它会提前检查源字符串是否超过您指定的长度,并在尝试复制之前失败。这基本上是在做我之前提到的相同的步骤,但强制崩溃,而不是在你自己的代码中知道它。
这就是你的错误的来源,在运行时库中增加了一点额外的安全性。
请记住,这个额外的检查只在调试代码中,而不是在生产就绪的代码中。这样,您就可以确认您在开发过程中所做的事情是正确的,而不会减慢您在该领域的代码。
magic
只有6个字符,而你正在向它写入8个字符。
您正在尝试复制8个字节:
strncpy(t->th_buf.magic, "ustar ", 8);
将放入一个为6
分配空间的缓冲区中char magic[6];
不上班