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:
parent
2372567a6e
commit
83aaf64318
5 changed files with 13 additions and 7 deletions
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in a new issue