获取“free():无效指针”配备定制 TCL 口译员

发布于 2024-10-09 11:10:47 字数 1368 浏览 6 评论 0原文

我有一个定制的 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 有问题吗?代码>?什么可能导致这次崩溃?

I have a custom TCL interpreter. Here it is:

// 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;
}

I build main.cpp with the following command:

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

Sometimes myinterp crushes with an error message like this:

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]

Is something wrong with main.cpp? What could cause this crash?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

与他有关 2024-10-16 11:10:47

您最好像这样编写代码:

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

You might be better off writing the code like this:

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

Like that, the lifetime of the buffer in the std::string will be correct, which is what my intuition indicates is probably your real problem. (Once there's corrupted memory about, the crash can crop up nearly anywhere.) However, you should also be aware that this will still go thoroughly wrong if you've got spaces in any of those filenames. Maybe that's OK for you (e.g., if it's all local filenames with “nice” names) but otherwise use Tcl's Tcl_EvalObjv to do the execution, like this (which is a bit longer; it's really C, not 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;
}
反目相谮 2024-10-16 11:10:47

我相信Tcl_Main应该是这样的:

Tcl_Main(argc, argv, Tcl_AppInit);

没有addressof &操作员。请参阅此处查看示例。我认为您在 argv 的大小问题上向 Tcl_Main 撒谎,以绕过参数的自动处理?

编辑:就其价值而言,我没有看到代码有任何明显的错误,但考虑到我对运算符地址的心理偏差,我的意见可能没有多大价值。您能否将脚本输入到标准 tclsh 解释器中而不会出现任何问题?他们是否加载任何其他扩展或库?

I believe that Tcl_Main should be like this:

Tcl_Main(argc, argv, Tcl_AppInit);

without the addressof & operator. See here here for an example. I take it you are fibbing to Tcl_Main about the size of argv in order to bypass the automatic processing of arguments?

Edit: For what its worth, I don't see anything obviously wrong with the code, but then given my mental aberration over the address of operator my opinion might not be worth much. Can you source the scripts into a standard tclsh interpreter without any problems? Do they load any other extensions or libraries?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文