【问题标题】:C++ strncpy parameters "optimized out"; overwrites random memoryC++ strncpy 参数“优化”;覆盖随机内存
【发布时间】:2013-04-08 07:46:12
【问题描述】:

首先,我要为未能缩小问题范围以分享重现该错误的简短程序而道歉。

strncpy 的外部库 (FUSE) 调用“随机”覆盖了我的代码中的 shared_ptr<mutex>,当我尝试锁定该互斥体时会导致段错误。我用 valgrind 运行我的程序,它没有发现任何内存错误(下面的 valgrind 标志)。当我在 gdb 中运行我的代码并在 shared_ptr 上设置一个观察点时,它会在调用 strncpy 时中断。 gdb 说strncpy 的所有参数(dest、src 和 nbytes)都已“优化”,这让我认为它正在为该调用使用未初始化的内存。我是否正确解释了这一点?知道可能是什么原因吗?

这是指针被覆盖时来自 gdb 的堆栈跟踪:

#0  __strncpy_ssse3 () at ../sysdeps/x86_64/multiarch/strcpy-ssse3.S:2482
#1  0x0000003245809094 in strncpy (__len=<optimized out>, __src=<optimized out>, __dest=<optimized out>) at /usr/include/bits/string3.h:120
#2  add_name (buf=<optimized out>, bufsize=<optimized out>, s=<optimized out>, name=<optimized out>) at fuse.c:907
#3  0x000000324580997c in try_get_path (f=<optimized out>, nodeid=<optimized out>, name=<optimized out>, path=<optimized out>, wnodep=<optimized out>, need_lock=<optimized out>) at fuse.c:956
#4  0x000000324580a281 in get_path_common (f=<optimized out>, nodeid=<optimized out>, name=<optimized out>, path=<optimized out>, wnode=<optimized out>) at fuse.c:1152
#5  0x0000003245812432 in fuse_lib_unlink (req=<optimized out>, parent=<optimized out>, name=<optimized out>) at fuse.c:1198
#6  0x0000003245817057 in fuse_ll_process_buf (data=0x6f5650, buf=0x7fffffffd850, ch=<optimized out>) at fuse_lowlevel.c:2441
#7  0x000000324581388f in fuse_session_loop (se=0x6f8410) at fuse_loop.c:40
#8  0x000000324580b698 in fuse_loop (f=<optimized out>) at fuse.c:4309
#9  0x000000324581bb8f in fuse_main_common (argc=<optimized out>, argv=<optimized out>, op=<optimized out>, op_size=<optimized out>, user_data=<optimized out>, compat=<optimized out>) at helper.c:355
#10 0x000000000046f1b6 in main (argc=4, argv=0x7fffffffdec8) at ../src/fuse.cpp:100 

这是我运行 valgrind 的参数:

valgrind --tool=memcheck --leak-check=yes --show-reachable=yes --num-callers=20 --track-fds=yes

【问题讨论】:

  • 尝试不优化编译。
  • 什么版本的 FUSE?
  • @Drew:FUSE 2.6版,我觉得是最新的
  • @AShelly:优化已经关闭(-O0 标志)
  • @user1091954 FUSE 2.6 是从 2006 年开始的。我的网络搜索显示在旧版本中比最新版本(即 2.9.2)有几个类似的崩溃。让我知道升级是否有帮助,我会将其作为答案发布。

标签: c++ linux fuse


【解决方案1】:

gdb 说 strncpy 的所有参数(dest、src 和 nbytes)都已“优化”,这让我认为它正在为该调用使用未初始化的内存。我的解释正确吗?

没有。这只是意味着优化器已经删除了一些函数序言样板,这些样板将允许调试器可靠地打印函数的参数。这在任何合理优化级别的简单函数中都很常见。

这是一个简单的例子:

int
mystrcpy(char *p, const char *q)
{
    while (*p++ = *q++);
}

使用-g -O0 编译,您会看到它立即将其参数溢出到堆栈中:

mystrcpy:
.LFB0:
        .file 1 "t.c"
        .loc 1 5 0
        .cfi_startproc
        pushq   %rbp
        .cfi_def_cfa_offset 16
        movq    %rsp, %rbp
        .cfi_offset 6, -16
        .cfi_def_cfa_register 6
        movq    %rdi, -8(%rbp)      <<< here
        movq    %rsi, -16(%rbp)     <<< and here
        ...

然后编译器生成了关于它的调试信息:

    .section        .debug_info
    ...
    .uleb128 0x7
    .string "p"   <<< from char *p
    .byte   0x1
    .byte   0x4
    .long   0x65
    .byte   0x2
    .byte   0x91
    .sleb128 -24  <<< not 100% sure but this is probably related to frame offset
    .uleb128 0x7
    .string "q"
    .byte   0x1
    .byte   0x4
    .long   0x72
    .byte   0x2
    .byte   0x91
    .sleb128 -32   <<< note adjacent to p

当您启动-O2 -g 时,尽管-g 功能变得更小:

mystrcpy:
.LFB11:
        .file 1 "t.c"
        .loc 1 5 0
        .cfi_startproc
        (at this point we start copying, using the input regs directly)

现在调试信息中没有提到pq。正如你从这个例子中看到的,你可能可以在寄存器中找到你想要的信息,但你必须反汇编并理解解释它们的函数。如果你的函数调用了 other 函数,你可能需要找到你的寄存器溢出到堆栈的位置(对于被调用者保存的 regs 可能很远)。

【讨论】:

    【解决方案2】:

    这个错误是用new 创建shared_ptr,然后将其类型转换为weak_ptr 并删除它的结果。

    【讨论】:

    • 类型转换共享指针?编译器让你这样做?万维网。
    • 我正在使用一个 C 库,它只提供一个 uint64_t 来存储句柄。我向库传递了一个结构,该结构包含指向转换为 uint64_t 的弱指针的指针。该库调用我的函数并将包含指向弱指针的指针的结构传递给它们。我不小心将指针(转换为 uint64_t)设置为共享指针而不是弱指针的地址。
    猜你喜欢
    • 1970-01-01
    • 2018-09-08
    • 1970-01-01
    • 2020-07-17
    • 2018-02-08
    • 2013-11-05
    • 1970-01-01
    • 2017-04-30
    • 1970-01-01
    相关资源
    最近更新 更多