使用主动evals调用DeleteInterpProc

时间:2013-03-04 11:29:54

标签: c++ tcl

我正在编写一个执行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_PreserveTcl_Release后,结果相同。

2 个答案:

答案 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命令正常退出。