首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用GCC编写的4.5撞车程序,GCC 4.4没有问题

问用GCC编写的4.5撞车程序,GCC 4.4没有问题
EN

Stack Overflow用户
提问于 2011-06-09 13:54:30
回答 3查看 2.1K关注 0票数 3

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

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

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

代码语言:javascript
复制
$bin/ns
*** buffer overflow detected ***: bin/ns terminated

相同的代码,如果用较早的gcc编译,运行精细。所以,我相信这是由于一些增强特征在gcc 4.5。

我该如何处理这个问题?当然,用gcc 4.4编译是一种选择,但我想知道哪里出了问题:)

更新:

下面是gdb的完整堆栈跟踪和回跟踪:

代码语言:javascript
复制
$ 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并打开符号:

代码语言:javascript
复制
(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 ()    
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2011-06-09 14:03:47

著名的遗言:“别担心--我的零钱并没有破坏任何东西”。我们怎么能确定呢?

但是,如果代码在4.4下工作,而崩溃在4.5下,则有一定的可能是正确的。

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

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

进一步思考:

  • 在编译代码时,使用了多严格的警告标志?您能在启用更多警告的情况下重新编译吗? 如果您找不到其他方法来获得C或C++编译器的特殊选项,通常(使用AutoTools配置的程序)的一种技术是: ./配置--前缀=/opt/ns CC="gcc -Wall -Wextra“CXX="g++ -Wall -Wextra” (我还使用这种技术来指定32位对64位构建,添加-m32或-m64。) 警告:如果代码不是为了在这些选项下编译干净而创建的,那么使用这些选项进行第一次编译是很痛苦的。然而,也有一个不错的机会,在所有的警告是一个关于你的问题的根源。不过,无可争辩的是,可能会有50项警告与之无关,即(或更糟),而修正所有已发现的警告,仍可能不能解决问题。如果代码无论如何都会使用严格的警告进行编译,那么您将面临更多的异域警告。但是,如果您可以让编译器帮助诊断它所引起的问题,那么当然应该这样做--这比单独查找问题要简单得多。
  • 此外,确保您正在生成一个可调试的程序-即使您保持优化启用。
  • 此外,考虑编译与优化关闭,看看程序是否仍然崩溃。如果程序在没有优化的情况下不会崩溃,并且需要进行优化,那么您可以获得一些有用的信息。它不会使查找原因变得更容易,但您知道它(可能)与优化器有关。或者,错误可能只是在没有优化时移动,并且不会致命地失败。

扩展的堆栈跟踪信息很奇怪:

代码语言:javascript
复制
#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():

代码语言:javascript
复制
    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,看看是否可以自己去挠痒这个bug (对不起,糟糕的双关语)。此代码与跟踪tcl变量- trace add varname ... AFAICT有关。

假设这种情况过去了,我会考虑找到GCC 4.6,看看用它来编译ns-2时是否会出现同样的问题,而不是GCC 4.5。

瓦兰

因为您是在Linux上运行的,所以您应该能够使用Valgrind。它在发现记忆滥用问题方面非常出色。为了获得最大的好处,请使用ns-2的调试版本。

票数 6
EN

Stack Overflow用户

发布于 2011-06-09 14:00:05

“缓冲区溢出检测到”:您正在写入未分配的区域。gcc 4.4显然生成的代码没有引发问题(或者问题本身并没有显示为崩溃,但其结果却是错误的,现在还没有被检测到),gcc 4.5生成了检测到问题并警告您的代码。唯一的解决办法是找到问题的来源并修复代码。

票数 2
EN

Stack Overflow用户

发布于 2011-06-09 23:38:24

可能是各种各样的事。可能是GCC的窃听器。这可能是一个Tcl错误(我希望它不是,作为Tcl开发人员之一,但我不会排除它,因为Tcl经常假设结构上没有保护代码;Tcl绝对是C89代码)。它可能是ns2中的一个bug。据我所知,它甚至可能是其他地方的一个bug (因为ns2构建在Tcl上,它可以加载外部代码库;在那里很可能会出现问题)。

遗憾的是,我们无法从发布的信息中看出这些可能性中的哪一种。您知道程序崩溃时调用堆栈在哪个库中吗?虽然不能保证这是问题的实际位置,但它至少是一个开始bug搜索…的地方。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/6293890

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档