strndup调用正在破坏堆栈帧

时间:2010-01-19 06:05:24

标签: c aix

我在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

4 个答案:

答案 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。

最有可能是你在某处腐蚀内存(考虑到问题只出现在大型程序中,在某些条件下)。您是否可以制作一个展示堆栈损坏问题的小型,完整,可编译的示例?否则,您必须在程序中调试内存分配/释放。有很多程序可以帮助您实现这一目标,例如valgrindglibc mcheckdmallocelectricfence等。

答案 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时,我看到我的产品的行为:

  1. 在主要的“出口”,执行正在以“非法指示”取消
  2. 在执行过程中间歇性地“非法指令”(在strndup调用之后)。
  3. 损坏了某些已分配的内存,这与strndup无关。
  4. 所有这些问题都可以通过修改strndup与源字符串实际大小的使用来解决。

    谢谢&amp;问候, Thumbeti