fix(library/tactic): memory leaks

Proof/Cex builders and tactics implemented in Lua had a "strong reference" to script_state. If they are stored in the Lua state, then we get a cyclic reference.
That is, script_state points to these objects, and they point back to script_state.

To avoid this memory leak, this commit defines a weak reference for script_state objects. The Proof/Cex builders and tactics now store a weak reference to the Lua state.

Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
This commit is contained in:
Leonardo de Moura 2013-11-30 00:44:31 -08:00
parent 2372567a6e
commit 83aaf64318
5 changed files with 13 additions and 7 deletions

View file

@ -17,7 +17,7 @@ cex_builder & cex_builder::operator=(cex_builder && s) { LEAN_MOVE_REF(cex_build
DECL_UDATA(cex_builder)
static int mk_cex_builder(lua_State * L) {
script_state S = to_script_state(L);
script_state::weak_ref S = to_script_state(L).to_weak_ref();
luaL_checktype(L, 1, LUA_TFUNCTION); // user-fun
luaref ref(L, 1);
return push_cex_builder(L,

View file

@ -81,7 +81,7 @@ static const struct luaL_Reg assignment_m[] = {
DECL_UDATA(proof_builder);
static int mk_proof_builder(lua_State * L) {
script_state S = to_script_state(L);
script_state::weak_ref S = to_script_state(L).to_weak_ref();
luaL_checktype(L, 1, LUA_TFUNCTION); // user-fun
luaref ref(L, 1);
return push_proof_builder(L,

View file

@ -440,7 +440,7 @@ static int tactic_solve(lua_State * L) {
static int mk_lua_tactic01(lua_State * L) {
luaL_checktype(L, 1, LUA_TFUNCTION); // user-fun
script_state S = to_script_state(L);
script_state::weak_ref S = to_script_state(L).to_weak_ref();
luaref ref(L, 1);
return push_tactic(L,
mk_tactic01([=](environment const & env, io_state const & ios, proof_state const & s) -> optional<proof_state> {
@ -484,7 +484,7 @@ static int mk_lua_tactic01(lua_State * L) {
static int mk_lua_cond_tactic(lua_State * L, tactic t1, tactic t2) {
luaL_checktype(L, 1, LUA_TFUNCTION); // user-fun
script_state S = to_script_state(L);
script_state::weak_ref S = to_script_state(L).to_weak_ref();
luaref ref(L, 1);
return push_tactic(L,
mk_tactic([=](environment const & env, io_state const & ios, proof_state const & s) -> proof_state_seq {

View file

@ -111,8 +111,10 @@ script_state::script_state():
m_ptr->save_weak_ptr(m_ptr);
}
script_state::script_state(std::weak_ptr<imp> const & ptr):m_ptr(ptr.lock()) {
lean_assert(m_ptr);
script_state::script_state(weak_ref const & r) {
if (r.expired())
throw exception("weak reference to script_state object has expired (i.e., it has been deleted)");
m_ptr = r.lock();
}
script_state::~script_state() {

View file

@ -19,15 +19,19 @@ public:
struct imp;
private:
std::shared_ptr<imp> m_ptr;
script_state(std::weak_ptr<imp> const & ptr);
friend script_state to_script_state(lua_State * L);
std::mutex & get_mutex();
lua_State * get_state();
friend class data_channel;
public:
typedef std::weak_ptr<imp> weak_ref;
script_state();
script_state(weak_ref const & r);
~script_state();
weak_ref to_weak_ref() const { return weak_ref(m_ptr); }
/**
\brief Execute the file with the given name.
This method throws an exception if an error occurs.