我在AIX 5.3和6.1上看到了“strndup”调用的奇怪行为。 如果我调用大小超过实际源字符串长度大小的strndup,那么在该调用之后会出现堆栈损坏。
int main ()
{
char *dst_str = NULL;
char src_str[1023] = "sample string";
dst_str = strndup(src_str, sizeof(src_str));
free(dst_str);
return 0;
}
有没有人遇到过这种行为?
如果是,请告诉我。
根据我的观察,必须有来自操作系统的补丁,此问题得到解决。但如果有任何补丁,我无法得到那个补丁。请稍微说清楚。
谢谢&问候, Thumbeti
答案 0 :(得分:5)
您的代码中缺少#include <string.h>
。请试试 - 我相信它会起作用。原因是没有#include <string.h>
,范围内没有strndup()
的原型,因此编译器假定strndup()
返回int
,并且采用未指定数量的参数。这显然是错误的。 (我假设您正在编译POSIX兼容模式,因此可以使用strndup()
。)
因此,在启用警告的情况下编译代码总是有用的。
如果您的问题在更改后仍然存在,则可能存在错误。
编辑:看起来AIX上可能有problem strndup()
:问题似乎是在AIX上的strnlen()
函数中出现问题。如果即使在#include <string.h>
之后您发现问题,也很可能是您看到了这个错误。 google search显示了一长串关于它的结果。
编辑2 :
您可以尝试以下程序并发布结果吗?
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
char *test1 = "abcdefghijabcdefghijabcdefghijk";
char *test2 = "012345678901234567890123456789";
char *control = "01234567890123456789012345678";
char *verify;
free(strndup(test1, 30));
verify = strndup(test2, 29); /* shorter then first strndup !!! */
fprintf(stderr,">%s<\n",verify);
if (strcmp(control, verify))
printf("strndup is broken\n");
}
(取自https://bugzilla.samba.org/show_bug.cgi?id=1097#c10。)
编辑3 :在看到您的输出(>01234567890123456789012345678<
且没有strndup is broken
)后,我认为您的AIX版本不具有{{1} } bug。
最有可能是你在某处腐蚀内存(考虑到问题只出现在大型程序中,在某些条件下)。您是否可以制作一个展示堆栈损坏问题的小型,完整,可编译的示例?否则,您必须在程序中调试内存分配/释放。有很多程序可以帮助您实现这一目标,例如valgrind,glibc mcheck,dmalloc,electricfence等。
答案 1 :(得分:2)
老话题,但我也遇到过这个问题。 AIX 6.1上的一个简单的测试程序与AIX的MALLOCDEBUG一起证实了这个问题。
#include <string.h>
int main(void)
{
char test[32] = "1234";
char *newbuf = NULL;
newbuf = strndup(test, sizeof(test)-1);
}
使用缓冲区溢出检测编译并运行程序:
~$ gcc -g test_strndup2.c
~$ MALLOCDEBUG=catch_overflow ./a.out
Segmentation fault (core dumped)
现在运行dbx来分析核心:
~$ dbx ./a.out /var/Corefiles/core.6225952.22190412
Type 'help' for help.
[using memory image in /var/Corefiles/core.6225952.22190412]
reading symbolic information ...
Segmentation fault in strncpy at 0xd0139efc
0xd0139efc (strncpy+0xdc) 9cc50001 stbu r6,0x1(r5)
(dbx) where
strncpy() at 0xd0139efc
strndup@AF5_3(??, ??) at 0xd03f3f34
main(), line 8 in "test_strndup2.c"
跟踪strndup中的指令,看起来它mallocs一个足够大的缓冲区来处理s中的字符串加上一个NULL终止符。但是,它总是将n个字符复制到新缓冲区,必要时用零填充,如果strlen(s)&lt; Ñ
char* strndup(const char*s, size_t n)
{
char* newbuf = (char*)malloc(strnlen(s, n) + 1);
strncpy(newbuf, s, n-1);
return newbuf;
}
答案 2 :(得分:1)
Alok是对的。并且使用glibc下的gcc工具链,您需要定义_GNU_SOURCE来获取strndup的decl,否则它不会被删除,例如:
#include <string.h>
...
compilo:
gcc -D_GNU_SOURCE a.c
答案 3 :(得分:0)
非常感谢您的及时回复。 我尝试过给定的程序。
结果如下:
bash-2.05b# ./mystrndup3
>01234567890123456789012345678<
在我已经包含的程序中,仍然存在问题。 以下是预先发现的代码中的strndup声明。
extern char * strndup(const char *, size_t);
我想澄清一件事,小程序我不会受到堆栈损坏的影响。它一直出现在我的产品中,它具有大量的函数调用。
以下列方式使用strndup解决了这个问题:
dst_str = strndup(src_str, srtlen(src_str));
请注意:使用strlen而不是sizeof,因为我只需要有效的字符串。 我试图理解它为什么会发生。
当我使用大尺寸的strndup时,我看到我的产品的行为:
所有这些问题都可以通过修改strndup与源字符串实际大小的使用来解决。
谢谢&amp;问候, Thumbeti