c++ - 用 GCC 4.5 编译的程序崩溃,而 GCC 4.4 没问题

标签 c++ gcc tcl simulator

最近尝试编译安装ns-2 , 基于 C++ 和 Tcl 的网络模拟器。

使用对源代码的一些轻微修改(别担心,它不会导致崩溃),我可以使用最新的 gcc 4.5 版本编译它。

但是当我执行二进制文件时,它给出了以下错误。:

$bin/ns
*** buffer overflow detected ***: bin/ns terminated

相同的代码如果编译 使用较早的 gcc , 运行良好 .所以我相信这是由于一些 enhanced features gcc 4.5 .

我该如何解决这个问题?当然用 编译gcc 4.4 是一种选择,但我想知道出了什么问题:)

更新:

这是使用 gdb 进行的完整堆栈跟踪和回溯:
$ bin/ns
*** buffer overflow detected ***: bin/ns terminated
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(__fortify_fail+0x37)[0x7f01824ac1d7]
/lib/x86_64-linux-gnu/libc.so.6(+0xfd0f0)[0x7f01824ab0f0]
bin/ns[0x8d5b5a]
bin/ns[0x8d56de]
bin/ns[0x841077]
bin/ns[0x842b19]
bin/ns(Tcl_EvalEx+0x16)[0x843256]
bin/ns(Tcl_Eval+0x1d)[0x84327d]
bin/ns(Tcl_GlobalEval+0x2b)[0x84391b]
bin/ns(_ZN3Tcl4evalEPc+0x27)[0x83352b]
bin/ns(_ZN3Tcl5evalcEPKc+0xdd)[0x8334e9]
bin/ns(_ZN11EmbeddedTcl4loadEv+0x24)[0x834712]
bin/ns(Tcl_AppInit+0xb2)[0x8331a5]
bin/ns(Tcl_Main+0x1d0)[0x8ad6a0]
bin/ns(nslibmain+0x25)[0x8330c5]
bin/ns(main+0x20)[0x833254]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xff)[0x7f01823cceff]
bin/ns[0x5bc1a9]

使用 GDB 并打开符号:
(gdb) bt
#0  0x00007ffff6970d05 in raise () from /lib/x86_64-linux-gnu/libc.so.6
#1  0x00007ffff6974ab6 in abort () from /lib/x86_64-linux-gnu/libc.so.6
#2  0x00007ffff69a9d7b in ?? () from /lib/x86_64-linux-gnu/libc.so.6
#3  0x00007ffff6a3b1d7 in __fortify_fail () from /lib/x86_64-linux-gnu/libc.so.6
#4  0x00007ffff6a3a0f0 in __chk_fail () from /lib/x86_64-linux-gnu/libc.so.6
#5  0x00000000008d5b5a in strcpy (interp=0xd2dda0, optionIndex=<value optimized out>, objc=<value optimized out>, objv=0x7fffffffdad0)
    at /usr/include/bits/string3.h:105
#6  TraceVariableObjCmd (interp=0xd2dda0, optionIndex=<value optimized out>, objc=<value optimized out>, objv=0x7fffffffdad0)
    at /media/Linux/ns-allinone-2.35-RC7/tcl8.5.8/unix/../generic/tclTrace.c:912
#7  0x00000000008d56de in Tcl_TraceObjCmd (dummy=<value optimized out>, interp=0xd2dda0, objc=<value optimized out>, objv=0xd2ec00)
    at /media/Linux/ns-allinone-2.35-RC7/tcl8.5.8/unix/../generic/tclTrace.c:293
#8  0x0000000000841077 in TclEvalObjvInternal (interp=0xd2dda0, objc=5, objv=0xd2ec00,
    command=0x7ffff7f680fe "trace variable defaultRNG w { abort \"cannot update defaultRNG once assigned\"; }\n\n\nClass RandomVariable/TraceDriven -superclass RandomVariable\n\nRandomVariable/TraceDriven instproc init {} {\n$self instv"..., length=80, flags=0)
    at /media/Linux/ns-allinone-2.35-RC7/tcl8.5.8/unix/../generic/tclBasic.c:3689
#9  0x0000000000842b19 in TclEvalEx (interp=0xd2dda0,
    script=0x7ffff7f52010 "\n\n\n\n\n\nproc warn {msg} {\nglobal warned_\nif {![info exists warned_($msg)]} {\nputs stderr \"warning: $msg\"\nset warned_($msg) 1\n}\n}\n\nif {[info commands debug] == \"\"} {\nproc debug args {\nwarn {Script debugg"..., numBytes=422209, flags=<value optimized out>, line=4141,
    clNextOuter=<value optimized out>,
    outerScript=0x7ffff7f52010 "\n\n\n\n\n\nproc warn {msg} {\nglobal warned_\nif {![info exists warned_($msg)]} {\nputs stderr \"warning: $msg\"\nset warned_($msg) 1\n}\n}\n\nif {[info commands debug] == \"\"} {\nproc debug args {\nwarn {Script debugg"...)
    at /media/Linux/ns-allinone-2.35-RC7/tcl8.5.8/unix/../generic/tclBasic.c:4386
#10 0x0000000000843256 in Tcl_EvalEx (interp=<value optimized out>, script=<value optimized out>, numBytes=<value optimized out>,
    flags=<value optimized out>) at /media/Linux/ns-allinone-2.35-RC7/tcl8.5.8/unix/../generic/tclBasic.c:4043
#11 0x000000000084327d in Tcl_Eval (interp=0xd2dda0, script=<value optimized out>)
    at /media/Linux/ns-allinone-2.35-RC7/tcl8.5.8/unix/../generic/tclBasic.c:4955
#12 0x000000000084391b in Tcl_GlobalEval (interp=0xd2dda0, command=<value optimized out>)
    at /media/Linux/ns-allinone-2.35-RC7/tcl8.5.8/unix/../generic/tclBasic.c:6005
#13 0x000000000083352b in Tcl::eval(char*) ()
#14 0x00000000008334e9 in Tcl::evalc(char const*) ()
#15 0x0000000000834712 in EmbeddedTcl::load() ()
#16 0x00000000008331a5 in Tcl_AppInit ()
#17 0x00000000008ad6a0 in Tcl_Main (argc=<value optimized out>, argv=0x7fffffffe1d0, appInitProc=0x8330f3 <Tcl_AppInit>)
    at /media/Linux/ns-allinone-2.35-RC7/tcl8.5.8/unix/../generic/tclMain.c:418
#18 0x00000000008330c5 in nslibmain ()
#19 0x0000000000833254 in main ()    

最佳答案

著名的遗言:“别担心 - 我的改变没有破坏任何东西”。我们如何确定这一点?

但是,如果代码在 4.4 下运行并在 4.5 下崩溃,那么您有一定的机会是正确的。

GCC 采用了一些与代码相关的积极优化,试图检测整数溢出并将其删除。在这种情况下,您将不得不在 ns-2 中找到该代码并尝试修复它 - 由 ns-2 开发人员或您自己。

您可能应该尝试在调试器下运行该程序,以便您可以在检测到缓冲区溢出的位置进行控制,并查看代码所在的位置。如果您禁用了核心转储(使用 ulimit -c 0 或等效项),请考虑启用它们并查看在终止时是否获得核心转储。这应该给你一个起点。

进一步的想法:

  • 当您编译代码时,使用的警告标志有多严格?您可以在启用更多警告的情况下重新编译吗?

    如果您找不到其他方法来获得 C 或 C++ 编译器的特殊选项,那么一种通常有效(使用 AutoTools 配置的程序)的技术是:
    ./configure --prefix=/opt/ns CC="gcc -Wall -Wextra" CXX="g++ -Wall -Wextra"
    

    (我还使用这种技术来指定 32 位与 64 位版本,添加 -m32-m64 。)

    警告:如果代码不是为了在这些选项下编译干净而创建的,则使用这些选项进行第一次编译可能会造成创伤。然而,在所有警告中也有一个很好的机会是关于您的问题的根源。然而,同样无可争议的是,可能会有 50 个警告与任何一个(或更糟)无关,并且修复由此发现的所有警告仍然可能无法解决问题。如果代码编译时带有严格的警告,那么您将面临启用更多奇特警告。但是,如果您可以让编译器帮助诊断由它引起的问题,那么您当然应该这样做——这比独立查找问题要简单得多。
  • 此外,请确保您正在生成可调试的程序 - 即使您保持启用优化。
  • 另外,考虑在关闭优化的情况下编译,看看程序是否仍然崩溃。如果程序在没有优化的情况下没有崩溃并且在优化后崩溃了,那么您就有了一些有用的信息。它不会更容易找到原因,但您知道它(可能)与优化器有关。或者可能只是错误在未优化时移动并且不会致命地失败。


  • 扩展堆栈跟踪信息很好奇:
    #5  0x00000000008d5b5a in strcpy (interp=0xd2dda0, optionIndex=<value optimized out>,
                                      objc=<value optimized out>, objv=0x7fffffffdad0)
        at /usr/include/bits/string3.h:105
    #6  TraceVariableObjCmd (interp=0xd2dda0, optionIndex=<value optimized out>,
                             objc=<value optimized out>, objv=0x7fffffffdad0)
        at /media/Linux/ns-allinone-2.35-RC7/tcl8.5.8/unix/../generic/tclTrace.c:912
    

    这些不是 strcpy() 的普通参数.通常,您只有两个参数。我无法立即想到在指向 Tcl 解释器的主控制结构的指针上复制字符串是合适的情况。因此,为了更进一步,我会非常努力地查看 tclTrace.c 中的第 900-920 行左右。 ,特别是第 912 行。这可能只是优化器处理目标代码方式的人工制品,或者它可能是一个真正的问题。

    我发现 tcl8.5.8 源代码和 tclTrace.c 的第 912 行是 strcpy()在这段代码中:
        if ((enum traceOptions) optionIndex == TRACE_ADD) {
            CombinedTraceVarInfo *ctvarPtr;
    
            ctvarPtr = (CombinedTraceVarInfo *) ckalloc((unsigned)
                    (sizeof(CombinedTraceVarInfo) + length + 1
                    - sizeof(ctvarPtr->traceCmdInfo.command)));
            ctvarPtr->traceCmdInfo.flags = flags;
            if (objv[0] == NULL) {
                ctvarPtr->traceCmdInfo.flags |= TCL_TRACE_OLD_STYLE;
            }
            ctvarPtr->traceCmdInfo.length = length;
            flags |= TCL_TRACE_UNSETS | TCL_TRACE_RESULT_OBJECT;
            strcpy(ctvarPtr->traceCmdInfo.command, command);       // Line 912
            ctvarPtr->traceInfo.traceProc = TraceVarProc;
            ctvarPtr->traceInfo.clientData = (ClientData)
                    &ctvarPtr->traceCmdInfo;
            ctvarPtr->traceInfo.flags = flags;
            name = Tcl_GetString(objv[3]);
            if (TraceVarEx(interp,name,NULL,(VarTrace*)ctvarPtr) != TCL_OK) {
                ckfree((char *) ctvarPtr);
                return TCL_ERROR;
            }
        } else {
    

    因此,GDB 的输出和堆栈跟踪看起来有些误导;有两个变量传递给 strcpy()其中之一在堆上本地分配。

    我会考虑编译 tcl独立于嵌入 ns-2 的源代码看看你是否可以自己解决这个问题(抱歉,糟糕的双关语)。此代码与跟踪 tcl 有关变量 - trace add varname ... AFAICT。

    假设通过了,我会考虑获取 GCC 4.6 并查看编译时是否出现相同的问题 ns-2用它代替 GCC 4.5。

    瓦尔格林

    由于您在 Linux 上运行,因此您应该能够使用 Valgrind。它非常擅长发现内存滥用问题。为了获得最大利益,请使用 ns-2 的调试版本.

    关于c++ - 用 GCC 4.5 编译的程序崩溃,而 GCC 4.4 没问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6293890/

    相关文章:

    c++ - 视觉C++ : Exporting decorated function name in a def file

    c++ - 我可以在 Xcode 中使用 C++11 吗?

    c++ - 使用 -fno-elide-constructors 的临时对象

    list - 如何使用tcl获取列表中的所有子目录名称?

    tcl - 从 TCL 中的字符串中提取整数

    c++ - 如何使用for循环C++将不同的值输入到二维指针到指针数组中

    c++ - 固定 QGraphicsItem 位置,不改变场景中其他 QGraphicsItem 的行为

    c++ - C++ 作用域静态初始化的汇编代码

    tcl - 如何让proc更有效?

    c++ - 带有额外 ":"或 "-"c++ 的文件名