使用自定义TCL解释器获取“free():无效指针”

时间:2010-12-28 18:22:57

标签: c++ malloc free tcl glibc

我有一个自定义TCL解释器。这是:

// file main.cpp
#include <tcl.h>
#include <string>

int    argc = 0;
char** argv = 0;

int
Tcl_AppInit( Tcl_Interp* interp ) 
{
    if ( Tcl_Init( interp ) == TCL_ERROR ) {
        return TCL_ERROR;  
    }
    for ( int i = 1; i < argc; ++i ) {             
        if ( Tcl_Eval( interp, ("source " + std::string( argv[i] )).c_str() ) == TCL_ERROR ) {
            return TCL_ERROR;
        }
    }
    return TCL_OK;
}

int
main( int argc, char** argv )
{
    ::argc = argc;
    ::argv = argv;
    Tcl_Main( 1, argv, &Tcl_AppInit );
    return 0;
}

我使用以下命令构建main.cpp

g++ -DNDEBUG -O3 -fpic -Wall -pedantic -fno-strict-aliasing \
    -Wl,-R/usr/local/lib -L/usr/local/lib -ltcl main.cpp -o myinterp

有时myinterp会崩溃并显示如下错误消息:

free(): invalid pointer: 0x00002b04078aa000 ***
======= Backtrace: =========
/lib64/libc.so.6[0x3723c722ef]
/lib64/libc.so.6(cfree+0x4b)[0x3723c7273b]
/lib64/libc.so.6(_IO_free_backup_area+0x18)[0x3723c6e1d8]
/lib64/libc.so.6(_IO_file_overflow+0x1d2)[0x3723c6c1d2]
/lib64/libc.so.6(_IO_file_xsputn+0xf2)[0x3723c6ce22]
/lib64/libc.so.6(_IO_vfprintf+0x1b0)[0x3723c428a0]
/lib64/libc.so.6(_IO_fprintf+0x88)[0x3723c4d358]

main.cpp出了什么问题?什么可能导致这次崩溃?

2 个答案:

答案 0 :(得分:2)

你可能最好写这样的代码:

int
Tcl_AppInit( Tcl_Interp* interp )
{
    if ( Tcl_Init( interp ) == TCL_ERROR ) {
        return TCL_ERROR;
    }
    for ( int i = 1; i < argc; ++i ) {
        std::string script("source ");

        script += argv[i];
        if ( Tcl_Eval( interp, script.c_str() ) == TCL_ERROR ) {
            return TCL_ERROR;
        }
    }
    return TCL_OK;
}

就像那样,std::string中缓冲区的生命周期是正确的,这就是我的直觉所表明的可能是你真正的问题。 (一旦内存损坏,崩溃几乎可以在任何地方出现。)但是,您还应该意识到,如果您在任何这些文件名中都有空格,这仍然会彻底错误。也许这对你来说没问题(例如,如果它是所有带有“漂亮”名称的本地文件名),但是否则使用Tcl的Tcl_EvalObjv来执行,就像这样(这有点长;它真的是C,而不是C ++):

int
Tcl_AppInit( Tcl_Interp* interp ) 
{
    Tcl_Obj *script[2];
    int code = TCL_OK;

    if ( Tcl_Init( interp ) == TCL_ERROR ) {
        return TCL_ERROR;
    }
    script[0] = Tcl_NewStringObj("source", -1);
    Tcl_IncrRefCount(script[0]);
    for ( int i = 1; i < argc && code == TCL_OK; ++i ) {
        script[1] = Tcl_NewStringObj(argv[i], -1);
        Tcl_IncrRefCount(script[1]);
        if (Tcl_EvalObjv(interp, 2, script, 0/*no special flags*/) != TCL_OK) {
            code = TCL_ERROR;
        }
        Tcl_DecrRefCount(script[1]);
    }
    Tcl_DecrRefCount(script[0]);
    return code;
}

答案 1 :(得分:0)

我相信Tcl_Main应该是这样的:

Tcl_Main(argc, argv, Tcl_AppInit);

没有&amp;运营商。有关示例,请参见此处here。我认为你正在向Tcl_Main讨论argv的大小以绕过参数的自动处理?

编辑:为了它的价值,我没有看到任何明显错误的代码,但鉴于我对操作员地址的精神失常,我的意见可能不值得。您可以将脚本源代码转换为标准的tclsh解释器而不会出现任何问题吗?他们是否加载任何其他扩展或库?