【问题标题】:strndup call is currupting stack framesstrndup 调用正在破坏堆栈帧
【发布时间】:2011-01-06 16:20:54
【问题描述】:

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

有人经历过这种行为吗?

如果是,请告诉我。

根据我的观察,必须有来自操作系统的补丁修复了这个问题。但如果有的话,我无法得到那个补丁。请点亮。

感谢和问候, 大拇指

【问题讨论】:

    标签: c aix


    【解决方案1】:

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

    因此,编译启用警告的代码总是有用的。

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

    编辑:看起来在 AIX 上可能存在带有 strndup()problem:问题似乎在于 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:看到您的输出后,&gt;01234567890123456789012345678&lt;,并且没有 strndup is broken,我认为您的 AIX 版本没有 strndup 错误。

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

    【讨论】:

      【解决方案2】:

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

      #include <string.h>
      ...
      

      编译:

      gcc -D_GNU_SOURCE a.c
      

      【讨论】:

        【解决方案3】:

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

        结果如下:

        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 的用法修改为源字符串的实际大小即可解决所有这些问题。

        感谢和问候, 大拇指

        【讨论】:

        • 请不要在“答案”部分发布问题,而是通过“编辑”来更新您的原始问题。我已经更新了我的答案,请参阅以获取更多信息。
        • 可能是您的源字符串格式不正确,因此strndup 试图访问它不应该访问的内存?虽然,要做到这一点,您必须在源中有一个格式错误的字符串,并且在长度参数中有很大的长度。
        【解决方案4】:

        老话题,但我也遇到过这个问题。 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) 会导致缓冲区溢出

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

        【讨论】:

        • +1:我没有任何 AIX SDK 来确认这一点,但这是一个很好的挖掘工作,似乎可以很好地诊断问题。您没有提供任何解决方案或链接,但在 C/C++ 级别,足以解决“我的代码”中的大多数问题(旁注:但不会修复任何可能已经使用 strndup 的“库”)。无论如何,一个值得几分的观察! :)
        猜你喜欢
        • 2012-05-11
        • 2018-05-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-04-06
        • 2011-04-21
        • 2011-11-01
        • 1970-01-01
        相关资源
        最近更新 更多