我有一个自定义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
出了什么问题?什么可能导致这次崩溃?
答案 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解释器而不会出现任何问题吗?他们是否加载任何其他扩展或库?