fix(lua): memory leaks, we should not use luaL_error because it does not unwind C++ stack

Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
This commit is contained in:
Leonardo de Moura 2013-11-11 21:44:10 -08:00
parent a30e02d862
commit d257156b88
11 changed files with 42 additions and 45 deletions

View file

@ -114,7 +114,7 @@ static int context_pred(lua_State * L) {
static int context_extend(lua_State * L) { static int context_extend(lua_State * L) {
int nargs = lua_gettop(L); int nargs = lua_gettop(L);
if (nargs != 3 && nargs != 4) if (nargs != 3 && nargs != 4)
luaL_error(L, "extend expect 3 or 4 arguments"); throw exception("extend expect 3 or 4 arguments");
return mk_context(L); return mk_context(L);
} }

View file

@ -173,7 +173,7 @@ int get_environment(lua_State * L) {
lua_pushlightuserdata(L, static_cast<void *>(&g_set_environment_key)); lua_pushlightuserdata(L, static_cast<void *>(&g_set_environment_key));
lua_gettable(L, LUA_REGISTRYINDEX); lua_gettable(L, LUA_REGISTRYINDEX);
if (!is_environment(L, -1)) if (!is_environment(L, -1))
luaL_error(L, "Lua registry does not contain a Lean environment"); throw exception("Lua registry does not contain a Lean environment");
return push_environment(L, to_environment(L, -1)); return push_environment(L, to_environment(L, -1));
} }

View file

@ -32,7 +32,7 @@ expr & to_expr(lua_State * L, int idx) {
expr & to_nonnull_expr(lua_State * L, int idx) { expr & to_nonnull_expr(lua_State * L, int idx) {
expr & r = to_expr(L, idx); expr & r = to_expr(L, idx);
if (!r) if (!r)
luaL_error(L, "non-null Lean expression expected"); throw exception("non-null Lean expression expected");
return r; return r;
} }
@ -83,7 +83,7 @@ static int expr_mk_var(lua_State * L) {
static int expr_mk_app(lua_State * L) { static int expr_mk_app(lua_State * L) {
int nargs = lua_gettop(L); int nargs = lua_gettop(L);
if (nargs < 2) if (nargs < 2)
luaL_error(L, "application must have at least two arguments"); throw exception("application must have at least two arguments");
buffer<expr> args; buffer<expr> args;
for (int i = 1; i <= nargs; i++) for (int i = 1; i <= nargs; i++)
args.push_back(to_nonnull_expr(L, i)); args.push_back(to_nonnull_expr(L, i));
@ -126,7 +126,7 @@ static std::pair<expr, expr> get_expr_pair_from_table(lua_State * L, int t, int
lua_pushinteger(L, i); lua_pushinteger(L, i);
lua_gettable(L, -2); // now table {ai, bi} is on the top lua_gettable(L, -2); // now table {ai, bi} is on the top
if (!lua_istable(L, -1) || objlen(L, -1) != 2) if (!lua_istable(L, -1) || objlen(L, -1) != 2)
luaL_error(L, "arg #1 must be of the form '{{expr, expr}, ...}'"); throw exception("arg #1 must be of the form '{{expr, expr}, ...}'");
expr ai = get_expr_from_table(L, -1, 1); expr ai = get_expr_from_table(L, -1, 1);
expr bi = get_expr_from_table(L, -1, 2); expr bi = get_expr_from_table(L, -1, 2);
lua_pop(L, 2); // pop table {ai, bi} and t from stack lua_pop(L, 2); // pop table {ai, bi} and t from stack
@ -137,16 +137,16 @@ typedef expr (*MkAbst1)(expr const & n, expr const & t, expr const & b);
typedef expr (*MkAbst2)(name const & n, expr const & t, expr const & b); typedef expr (*MkAbst2)(name const & n, expr const & t, expr const & b);
template<MkAbst1 F1, MkAbst2 F2> template<MkAbst1 F1, MkAbst2 F2>
int expr_abst(lua_State * L, char const * fname) { int expr_abst(lua_State * L) {
int nargs = lua_gettop(L); int nargs = lua_gettop(L);
if (nargs < 2) if (nargs < 2)
luaL_error(L, "Lean %s must have at least 2 arguments", fname); throw exception("function must have at least 2 arguments");
if (nargs == 2) { if (nargs == 2) {
if (!lua_istable(L, 1)) if (!lua_istable(L, 1))
luaL_error(L, "Lean %s expects arg #1 to be of the form '{{expr, expr}, ...}'", fname); throw exception("function expects arg #1 to be of the form '{{expr, expr}, ...}'");
int len = objlen(L, 1); int len = objlen(L, 1);
if (len == 0) if (len == 0)
luaL_error(L, "Lean %s expects arg #1 to be a non-empty table", fname); throw exception("function expects arg #1 to be a non-empty table");
expr r = to_nonnull_expr(L, 2); expr r = to_nonnull_expr(L, 2);
for (int i = len; i >= 1; i--) { for (int i = len; i >= 1; i--) {
auto p = get_expr_pair_from_table(L, 1, i); auto p = get_expr_pair_from_table(L, 1, i);
@ -155,7 +155,7 @@ int expr_abst(lua_State * L, char const * fname) {
return push_expr(L, r); return push_expr(L, r);
} else { } else {
if (nargs % 2 == 0) if (nargs % 2 == 0)
luaL_error(L, "Lean %s must have an odd number of arguments", fname); throw exception("function must have an odd number of arguments");
expr r = to_nonnull_expr(L, nargs); expr r = to_nonnull_expr(L, nargs);
for (int i = nargs - 1; i >= 1; i-=2) { for (int i = nargs - 1; i >= 1; i-=2) {
if (is_expr(L, i - 1)) if (is_expr(L, i - 1))
@ -167,9 +167,9 @@ int expr_abst(lua_State * L, char const * fname) {
} }
} }
static int expr_fun(lua_State * L) { return expr_abst<Fun, Fun>(L, "fun"); } static int expr_fun(lua_State * L) { return expr_abst<Fun, Fun>(L); }
static int expr_pi(lua_State * L) { return expr_abst<Pi, Pi>(L, "Pi"); } static int expr_pi(lua_State * L) { return expr_abst<Pi, Pi>(L); }
static int expr_let(lua_State * L) { return expr_abst<Let, Let>(L, "Let"); } static int expr_let(lua_State * L) { return expr_abst<Let, Let>(L); }
static int expr_type(lua_State * L) { static int expr_type(lua_State * L) {
int nargs = lua_gettop(L); int nargs = lua_gettop(L);

View file

@ -8,6 +8,7 @@ Author: Leonardo de Moura
#include <lua.hpp> #include <lua.hpp>
#include <cstring> #include <cstring>
#include "util/debug.h" #include "util/debug.h"
#include "util/sstream.h"
#include "util/sexpr/format.h" #include "util/sexpr/format.h"
#include "bindings/lua/util.h" #include "bindings/lua/util.h"
#include "bindings/lua/name.h" #include "bindings/lua/name.h"
@ -103,7 +104,7 @@ static int format_highlight(lua_State * L) {
} else if (strcmp(color_str, "grey") == 0) { } else if (strcmp(color_str, "grey") == 0) {
color = format::GREY; color = format::GREY;
} else { } else {
return luaL_error(L, "unknown color '%s'", color_str); throw exception(sstream() << "unknown color '" << color_str << "'");
} }
return push_format(L, highlight(to_format(L, 1), color)); return push_format(L, highlight(to_format(L, 1), color));
} }

View file

@ -159,7 +159,7 @@ static int print(lua_State * L) {
lua_call(L, 1, 1); lua_call(L, 1, 1);
s = lua_tolstring(L, -1, &l); s = lua_tolstring(L, -1, &l);
if (s == NULL) if (s == NULL)
return luaL_error(L, "'to_string' must return a string to 'print'"); throw exception("'to_string' must return a string to 'print'");
if (i > 1) { if (i > 1) {
std::cout << "\t"; std::cout << "\t";
} }

View file

@ -96,33 +96,33 @@ static int level_is_max(lua_State * L) {
static int level_name(lua_State * L) { static int level_name(lua_State * L) {
if (!is_uvar(to_level(L, 1))) if (!is_uvar(to_level(L, 1)))
luaL_error(L, "arg #1 must be a Lean level universal variable"); throw exception("arg #1 must be a Lean level universal variable");
return push_name(L, uvar_name(to_level(L, 1))); return push_name(L, uvar_name(to_level(L, 1)));
} }
static int level_lift_of(lua_State * L) { static int level_lift_of(lua_State * L) {
if (!is_lift(to_level(L, 1))) if (!is_lift(to_level(L, 1)))
luaL_error(L, "arg #1 must be a Lean level lift"); throw exception("arg #1 must be a Lean level lift");
return push_level(L, lift_of(to_level(L, 1))); return push_level(L, lift_of(to_level(L, 1)));
} }
static int level_lift_offset(lua_State * L) { static int level_lift_offset(lua_State * L) {
if (!is_lift(to_level(L, 1))) if (!is_lift(to_level(L, 1)))
luaL_error(L, "arg #1 must be a Lean level lift"); throw exception("arg #1 must be a Lean level lift");
lua_pushinteger(L, lift_offset(to_level(L, 1))); lua_pushinteger(L, lift_offset(to_level(L, 1)));
return 1; return 1;
} }
static int level_max_size(lua_State * L) { static int level_max_size(lua_State * L) {
if (!is_max(to_level(L, 1))) if (!is_max(to_level(L, 1)))
luaL_error(L, "arg #1 must be a Lean level max"); throw exception("arg #1 must be a Lean level max");
lua_pushinteger(L, max_size(to_level(L, 1))); lua_pushinteger(L, max_size(to_level(L, 1)));
return 1; return 1;
} }
static int level_max_level(lua_State * L) { static int level_max_level(lua_State * L) {
if (!is_max(to_level(L, 1))) if (!is_max(to_level(L, 1)))
luaL_error(L, "arg #1 must be a Lean level max"); throw exception("arg #1 must be a Lean level max");
return push_level(L, max_level(to_level(L, 1), luaL_checkinteger(L, 2))); return push_level(L, max_level(to_level(L, 1), luaL_checkinteger(L, 2)));
} }

View file

@ -71,7 +71,7 @@ static int local_entry_s(lua_State * L) {
static int local_entry_n(lua_State * L) { static int local_entry_n(lua_State * L) {
local_entry & e = to_local_entry(L, 1); local_entry & e = to_local_entry(L, 1);
if (!e.is_lift()) if (!e.is_lift())
luaL_error(L, "Lean lift local entry expected"); throw exception("Lean lift local entry expected");
lua_pushinteger(L, to_local_entry(L, 1).n()); lua_pushinteger(L, to_local_entry(L, 1).n());
return 1; return 1;
} }
@ -79,7 +79,7 @@ static int local_entry_n(lua_State * L) {
static int local_entry_v(lua_State * L) { static int local_entry_v(lua_State * L) {
local_entry & e = to_local_entry(L, 1); local_entry & e = to_local_entry(L, 1);
if (!e.is_inst()) if (!e.is_inst())
luaL_error(L, "Lean inst local entry expected"); throw exception("Lean inst local entry expected");
return push_expr(L, to_local_entry(L, 1).v()); return push_expr(L, to_local_entry(L, 1).v());
return 1; return 1;
} }

View file

@ -83,7 +83,7 @@ static int mpz_mul(lua_State * L) {
static int mpz_div(lua_State * L) { static int mpz_div(lua_State * L) {
mpz const & arg2 = to_mpz<2>(L); mpz const & arg2 = to_mpz<2>(L);
if (arg2 == 0) luaL_error(L, "division by zero"); if (arg2 == 0) throw exception("division by zero");
return push_mpz(L, to_mpz<1>(L) / arg2); return push_mpz(L, to_mpz<1>(L) / arg2);
} }
@ -93,7 +93,7 @@ static int mpz_umn(lua_State * L) {
static int mpz_power(lua_State * L) { static int mpz_power(lua_State * L) {
int k = luaL_checkinteger(L, 2); int k = luaL_checkinteger(L, 2);
if (k < 0) luaL_error(L, "argument #2 must be positive"); if (k < 0) throw exception("argument #2 must be positive");
return push_mpz(L, pow(to_mpz<1>(L), k)); return push_mpz(L, pow(to_mpz<1>(L), k));
} }
@ -200,7 +200,7 @@ static int mpq_mul(lua_State * L) {
static int mpq_div(lua_State * L) { static int mpq_div(lua_State * L) {
mpq const & arg2 = to_mpq<2>(L); mpq const & arg2 = to_mpq<2>(L);
if (arg2 == 0) luaL_error(L, "division by zero"); if (arg2 == 0) throw exception("division by zero");
return push_mpq(L, to_mpq<1>(L) / arg2); return push_mpq(L, to_mpq<1>(L) / arg2);
} }
@ -210,7 +210,7 @@ static int mpq_umn(lua_State * L) {
static int mpq_power(lua_State * L) { static int mpq_power(lua_State * L) {
int k = luaL_checkinteger(L, 2); int k = luaL_checkinteger(L, 2);
if (k < 0) luaL_error(L, "argument #2 must be positive"); if (k < 0) throw exception("argument #2 must be positive");
return push_mpq(L, pow(to_mpq<1>(L), k)); return push_mpq(L, pow(to_mpq<1>(L), k));
} }

View file

@ -8,6 +8,7 @@ Author: Leonardo de Moura
#include <lua.hpp> #include <lua.hpp>
#include "util/debug.h" #include "util/debug.h"
#include "util/name.h" #include "util/name.h"
#include "util/sstream.h"
#include "util/sexpr/options.h" #include "util/sexpr/options.h"
#include "util/sexpr/option_declarations.h" #include "util/sexpr/option_declarations.h"
#include "bindings/lua/util.h" #include "bindings/lua/util.h"
@ -133,7 +134,7 @@ static int options_get(lua_State * L) {
name k = to_key(L, 2); name k = to_key(L, 2);
auto it = get_option_declarations().find(k); auto it = get_option_declarations().find(k);
if (it == get_option_declarations().end()) { if (it == get_option_declarations().end()) {
return luaL_error(L, "unknown option '%s'", k.to_string().c_str()); throw exception(sstream() << "unknown option '" << k.to_string().c_str() << "'");
} else { } else {
option_declaration const & d = it->second; option_declaration const & d = it->second;
switch (d.kind()) { switch (d.kind()) {
@ -142,7 +143,7 @@ static int options_get(lua_State * L) {
case UnsignedOption: return options_get_unsigned(L); case UnsignedOption: return options_get_unsigned(L);
case DoubleOption: return options_get_double(L); case DoubleOption: return options_get_double(L);
case StringOption: return options_get_string(L); case StringOption: return options_get_string(L);
default: return luaL_error(L, "unsupported option kind for '%s'", k.to_string().c_str()); default: throw exception(sstream() << "unsupported option kind for '" << k.to_string().c_str() << "'");
} }
} }
} }
@ -151,7 +152,7 @@ static int options_update(lua_State * L) {
name k = to_key(L, 2); name k = to_key(L, 2);
auto it = get_option_declarations().find(k); auto it = get_option_declarations().find(k);
if (it == get_option_declarations().end()) { if (it == get_option_declarations().end()) {
return luaL_error(L, "unknown option '%s'", k.to_string().c_str()); throw exception(sstream() << "unknown option '" << k.to_string().c_str() << "'");
} else { } else {
option_declaration const & d = it->second; option_declaration const & d = it->second;
switch (d.kind()) { switch (d.kind()) {
@ -160,7 +161,7 @@ static int options_update(lua_State * L) {
case UnsignedOption: return options_update_unsigned(L); case UnsignedOption: return options_update_unsigned(L);
case DoubleOption: return options_update_double(L); case DoubleOption: return options_update_double(L);
case StringOption: return options_update_string(L); case StringOption: return options_update_string(L);
default: return luaL_error(L, "unsupported option kind for '%s'", k.to_string().c_str()); default: throw exception(sstream() << "unsupported option kind for '" << k.to_string().c_str() << "'");
} }
} }
} }

View file

@ -97,7 +97,7 @@ static int sexpr_is_mpq(lua_State * L) { lua_pushboolean(L, is_mpq(to_sexpr(L
static int sexpr_length(lua_State * L) { static int sexpr_length(lua_State * L) {
sexpr const & e = to_sexpr(L, 1); sexpr const & e = to_sexpr(L, 1);
if (!is_list(e)) if (!is_list(e))
return luaL_error(L, "s-expression is not a list"); throw exception("s-expression is not a list");
lua_pushinteger(L, length(e)); lua_pushinteger(L, length(e));
return 1; return 1;
} }
@ -105,21 +105,21 @@ static int sexpr_length(lua_State * L) {
static int sexpr_head(lua_State * L) { static int sexpr_head(lua_State * L) {
sexpr const & e = to_sexpr(L, 1); sexpr const & e = to_sexpr(L, 1);
if (!is_cons(e)) if (!is_cons(e))
return luaL_error(L, "s-expression is not a cons cell"); throw exception("s-expression is not a cons cell");
return push_sexpr(L, head(e)); return push_sexpr(L, head(e));
} }
static int sexpr_tail(lua_State * L) { static int sexpr_tail(lua_State * L) {
sexpr const & e = to_sexpr(L, 1); sexpr const & e = to_sexpr(L, 1);
if (!is_cons(e)) if (!is_cons(e))
return luaL_error(L, "s-expression is not a cons cell"); throw exception("s-expression is not a cons cell");
return push_sexpr(L, tail(e)); return push_sexpr(L, tail(e));
} }
static int sexpr_to_bool(lua_State * L) { static int sexpr_to_bool(lua_State * L) {
sexpr const & e = to_sexpr(L, 1); sexpr const & e = to_sexpr(L, 1);
if (!is_bool(e)) if (!is_bool(e))
return luaL_error(L, "s-expression is not a Boolean"); throw exception("s-expression is not a Boolean");
lua_pushboolean(L, to_bool(e)); lua_pushboolean(L, to_bool(e));
return 1; return 1;
} }
@ -127,7 +127,7 @@ static int sexpr_to_bool(lua_State * L) {
static int sexpr_to_string(lua_State * L) { static int sexpr_to_string(lua_State * L) {
sexpr const & e = to_sexpr(L, 1); sexpr const & e = to_sexpr(L, 1);
if (!is_string(e)) if (!is_string(e))
return luaL_error(L, "s-expression is not a string"); throw exception("s-expression is not a string");
lua_pushfstring(L, to_string(e).c_str()); lua_pushfstring(L, to_string(e).c_str());
return 1; return 1;
} }
@ -135,7 +135,7 @@ static int sexpr_to_string(lua_State * L) {
static int sexpr_to_int(lua_State * L) { static int sexpr_to_int(lua_State * L) {
sexpr const & e = to_sexpr(L, 1); sexpr const & e = to_sexpr(L, 1);
if (!is_int(e)) if (!is_int(e))
return luaL_error(L, "s-expression is not an integer"); throw exception("s-expression is not an integer");
lua_pushinteger(L, to_int(e)); lua_pushinteger(L, to_int(e));
return 1; return 1;
} }
@ -143,7 +143,7 @@ static int sexpr_to_int(lua_State * L) {
static int sexpr_to_double(lua_State * L) { static int sexpr_to_double(lua_State * L) {
sexpr const & e = to_sexpr(L, 1); sexpr const & e = to_sexpr(L, 1);
if (!is_double(e)) if (!is_double(e))
return luaL_error(L, "s-expression is not a double"); throw exception("s-expression is not a double");
lua_pushnumber(L, to_double(e)); lua_pushnumber(L, to_double(e));
return 1; return 1;
} }
@ -151,21 +151,21 @@ static int sexpr_to_double(lua_State * L) {
static int sexpr_to_name(lua_State * L) { static int sexpr_to_name(lua_State * L) {
sexpr const & e = to_sexpr(L, 1); sexpr const & e = to_sexpr(L, 1);
if (!is_name(e)) if (!is_name(e))
return luaL_error(L, "s-expression is not a name"); throw exception("s-expression is not a name");
return push_name(L, to_name(e)); return push_name(L, to_name(e));
} }
static int sexpr_to_mpz(lua_State * L) { static int sexpr_to_mpz(lua_State * L) {
sexpr const & e = to_sexpr(L, 1); sexpr const & e = to_sexpr(L, 1);
if (!is_mpz(e)) if (!is_mpz(e))
return luaL_error(L, "s-expression is not a multi-precision integer"); throw exception("s-expression is not a multi-precision integer");
return push_mpz(L, to_mpz(e)); return push_mpz(L, to_mpz(e));
} }
static int sexpr_to_mpq(lua_State * L) { static int sexpr_to_mpq(lua_State * L) {
sexpr const & e = to_sexpr(L, 1); sexpr const & e = to_sexpr(L, 1);
if (!is_mpq(e)) if (!is_mpq(e))
return luaL_error(L, "s-expression is not a multi-precision rational"); throw exception("s-expression is not a multi-precision rational");
return push_mpq(L, to_mpq(e)); return push_mpq(L, to_mpq(e));
} }

View file

@ -15,8 +15,3 @@ check_error(function() Pi({{"x"}}, Const("x")) end)
check_error(function() Pi(Const("x")) end) check_error(function() Pi(Const("x")) end)
check_error(function() Pi(Const("x"), Const("N"), Const("x"), Const("a")) end) check_error(function() Pi(Const("x"), Const("N"), Const("x"), Const("a")) end)
check_error(function() Pi({}, Const("x")) end) check_error(function() Pi({}, Const("x")) end)