我正在编写一个执行tcl脚本的程序。当脚本具有exit
命令时,程序崩溃并显示此错误
DeleteInterpProc called with active evals
Aborted
我正在调用Tcl_EvalFile(m_interpreter, script.c_str())
,其中脚本是文件名。
我也试过Tcl_Eval
带有参数解释器和“源文件名”。结果是一样的。其他tcl命令(例如,puts)解释器正常执行。如何解决这个问题?
#include <tcl.h>
#include <iostream>
int main() {
Tcl_Interp *interp = Tcl_CreateInterp();
//Tcl_Preserve(interp);
Tcl_Eval (interp, "exit");
//Tcl_Release(interp);
std::cout << "11111111111" << std::endl;
return 0;
}
这是一个简单的案例。 “11111111111”未打印。据我所知,在调用Tcl_Eval (interp, "exit");
时会退出整个程序。添加Tcl_Preserve
和Tcl_Release
后,结果相同。
答案 0 :(得分:3)
问题在于,解释器(Tcl代码的执行上下文)正在从其自身中删除;这让它很困惑!至少你得到一个干净的恐慌/中止,而不是一个令人厌恶的难以重现的崩溃。
最容易解决的问题可能是:
Tcl_Preserve(m_interpreter);
// Your code that calls Tcl_EvalFile(m_interpreter, script.c_str())
// and deals with the results.
Tcl_Release(m_interpreter);
请注意,在Tcl_Release
之后,Tcl_Interp
句柄可能会引用已删除的内存。
(是的,将Tcl_Preserve
/ Tcl_Release
包裹在RAII中是合理的。)
如果您希望在脚本执行exit
之后允许您的代码运行,则必须采取其他步骤。特别是,标准Tcl exit
命令不会导致返回到调用上下文:它将导致进程调用_exit(2)
系统调用。要更改它的行为,请将其替换为:
// A callback function that implements the replacement
static int
MyReplacementExit(ClientData unused, Tcl_Interp *interp, int argc, const char *argv[])
{
// We ought to check the argument count... but why bother?
Tcl_DeleteInterp(interp);
return TCL_OK;
}
int main() {
Tcl_Interp *interp = Tcl_CreateInterp();
// Install that function over the standard [exit]
Tcl_CreateCommand(interp, "exit", MyReplacementExit, NULL, NULL);
// Important; need to keep the *handle* live until we're finished
Tcl_Preserve(interp);
// Or run whatever code you want here...
Tcl_Eval(interp, "exit");
// Important piece of cleanup code
if (!Tcl_InterpDeleted(interp))
Tcl_DeleteInterp(interp);
Tcl_Release(interp);
// After this point, you *MUST NOT* use interp
std::cout << "11111111111" << std::endl;
return 0;
}
在the manual page for Tcl_CreateInterp
中列出了在这些场景中进行内存管理的规则。 (这是8.6手册页,但相关规则至少是自二十多年前的Tcl 7.0以来。)一旦解释器被删除,你就不能再指望执行任何命令或访问其中的任何变量; Tcl库为你处理状态展开。
答案 1 :(得分:1)
最好替换(隐藏)exit
命令并创建自己的exit
命令,以便优雅地退出程序。我对C和Tcl C Api不太好,但我希望这可以帮到你。
Eggdrop使用die
命令正常退出。