2

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

有没有人经历过这种行为?

如果是,请告诉我。

根据我的观察,必须有一个来自操作系统的补丁来解决这个问题。但如果有的话,我无法得到那个补丁。请放一些光。

谢谢和问候,拇指

4

4 回答 4

5

您的代码中缺少 a #include <string.h>。请尝试一下——我很确定它会起作用。原因是没有, 范围内#include <string.h>就没有原型strndup(),因此编译器假定strndup()返回一个int,并采用未指定数量的参数。这显然是错误的。(我假设你在 POSIX 兼容模式下编译,所以strndup()你可以使用。)

出于这个原因,在启用警告的情况下编译代码总是有用的。

如果您的问题在更改后仍然存在,则可能存在错误。

编辑:看起来 AIX 上可能存在问题strndup():问题似乎出在 AIX 上的一个损坏的函数strnlen()中。如果,即使在#include <string.h>您看到问题之后,您也很可能看到了错误。谷歌搜索显示了一长串关于它的结果。

编辑 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 版本没有strndup错误。

很可能您在某处损坏了内存(鉴于问题仅在某些条件下出现在大型程序中)。你能做一个小的、完整的、可编译的例子来展示堆栈损坏问题吗?否则,您将不得不在程序中调试内存分配/释放。有许多程序可以帮助您做到这一点,例如valgrindglibc mcheckdmallocelectricfence等。

于 2010-01-19T06:09:16.957 回答
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 中的指令,它似乎分配了一个缓冲区,该缓冲区刚好足以处理 s 中的字符串加上一个 NULL 终止符。但是,它总是将 n 个字符复制到新缓冲区,必要时用零填充,如果 strlen(s) < n 会导致缓冲区溢出。

char* strndup(const char*s, size_t n)
{
    char* newbuf = (char*)malloc(strnlen(s, n) + 1);
    strncpy(newbuf, s, n-1);

    return newbuf;
}
于 2012-08-22T19:39:24.343 回答
1

阿洛克是对的。并且使用 glibc 下的 gcc 工具链,您需要定义 _GNU_SOURCE 来获取 strndup 的 decl,否则它不会被 decl'd,例如:

#include <string.h>
...

编译:

gcc -D_GNU_SOURCE a.c
于 2010-01-19T06:14:50.393 回答
0

非常感谢您的及时回复。我已经尝试了给定的程序。

结果如下:

bash-2.05b# ./mystrndup3
>01234567890123456789012345678<

在我包含的程序中,问题仍然存在。以下是 prepossessed 代码中的 strndup 声明。

extern char * strndup(const char *, size_t);

我想澄清一件事,使用小程序我不会受到堆栈损坏的影响。它一直出现在我的产品中,它有大量的函数调用。

以下列方式使用 strndup 解决了这个问题:

dst_str = strndup(src_str, srtlen(src_str));

请注意:使用 strlen 而不是 sizeof 因为我只需要有效的字符串。我试图了解它为什么会发生。

当我使用大尺寸的 strndup 时,我在产品上看到的行为:

  1. 在 main 的“退出”处,执行以“非法指令”为核心
  2. 在执行过程中间歇性地“非法指令”(在 strndup 调用之后)。
  3. 一些分配的内存损坏,这与 strndup 无关。

所有这些问题都可以通过修改 strndup 的用法和源字符串的实际大小来解决。

谢谢和问候,拇指

于 2010-01-19T09:07:26.980 回答