Repair buggy error-handling in makeclass/getclass

This commit is contained in:
2021-12-27 16:44:12 -05:00
parent 82381ada2e
commit 9517b3e004
5 changed files with 170 additions and 76 deletions

View File

@@ -188,66 +188,142 @@ lua_State *LuaStack::newthread(LuaSlot target) const {
return result;
}
void LuaStack::getclass(LuaSlot classtab, LuaSlot classname) const {
bool LuaStack::validclassname(const std::string &cname) {
if (cname.empty()) return false;
if (cname == "_G") return false;
return true;
}
bool LuaStack::validclassname(LuaSlot slot) const {
if (!isstring(slot)) return false;
return validclassname(ckstring(slot));
}
std::string LuaStack::classname(LuaSlot tab) const {
std::string result;
if (istable(tab)) {
lua_pushstring(L_, "__class");
lua_rawget(L_, tab);
if (lua_type(L_, -1) == LUA_TSTRING) {
lua_pushglobaltable(L_); // cname table
lua_pushvalue(L_, -2); // cname table cname
lua_rawget(L_, -2); // cname table ctab
if (lua_rawequal(L_, -1, tab)) {
size_t len;
const char *s = lua_tolstring(L_, -3, &len);
result = std::string(s, len);
if (!validclassname(result)) {
result = "";
}
}
lua_pop(L_, 3);
} else {
lua_pop(L_, 1);
}
}
return result;
}
std::string LuaStack::getclass(LuaSlot classtab, LuaSlot classname) const {
lua_checkstack(L_, 20);
LuaVar globtab, cname;
LuaStack LS(L_, globtab, cname);
if (!LS.isstring(classname)) {
luaL_error(L_, "Not a class name: %s", lua_tostring(L_, classname));
}
// Convert class name to a table.
if (LS.rawequal(classname, "_G")) {
luaL_error(L_, "_G is explicitly not allowed as a class name");
}
LS.getglobaltable(globtab);
LS.rawget(classtab, globtab, classname);
if (!LS.istable(classtab)) {
luaL_error(L_, "Not a class: %s", lua_tostring(L_, classname));
}
LS.rawget(cname, classtab, "__class");
if (!LS.rawequal(cname, classname)) {
luaL_error(L_, "Not a class: %s", lua_tostring(L_, classname));
}
// OK, we're done.
LS.result();
if (LS.isstring(classname)) {
if (!validclassname(LS.ckstring(classname))) {
std::string err = "Not allowed as a class name: " + LS.ckstring(classname);
LS.result();
return err;
}
LS.rawget(classtab, globtab, classname);
if (!LS.istable(classtab)) {
std::string err = "Not a class: " + LS.ckstring(classname);
LS.result();
return err;
}
LS.rawget(cname, classtab, "__class");
if (!LS.rawequal(cname, classname)) {
std::string err = "Not a valid class: " + LS.ckstring(classname);
LS.result();
return err;
}
LS.result();
return "";
} else if (LS.istable(classname)) {
LS.rawget(cname, classname, "__class");
if (!LS.isstring(cname)) {
std::string err = "Table is not a class.";
LS.result();
return err;
}
if (!validclassname(LS.ckstring(cname))) {
std::string err = "Not allowed as a class name: " + LS.ckstring(cname);
LS.result();
return err;
}
LS.rawget(classtab, globtab, cname);
if (!LS.rawequal(classtab, classname)) {
std::string err = "Not a valid class: " + LS.ckstring(cname);
LS.result();
return err;
}
LS.result();
return "";
} else {
std::string err = "getclass expects a string or a classtab";
LS.result();
return err;
}
}
std::string LuaStack::getclass(LuaSlot tab, const char *name) const {
push_any_value(name);
LuaSpecial classname(lua_gettop(L_));
std::string err = getclass(tab, classname);
lua_pop(L_, 1);
return err;
}
std::string LuaStack::getclass(LuaSlot tab, const std::string &name) const {
push_any_value(name);
LuaSpecial classname(lua_gettop(L_));
std::string err = getclass(tab, classname);
lua_pop(L_, 1);
return err;
}
void LuaStack::makeclass(LuaSlot classtab, LuaSlot classname) const {
lua_checkstack(L_, 20);
LuaVar globtab;
LuaStack LS(L_, globtab);
LuaVar globtab, cname;
LuaStack LS(L_, globtab, cname);
// Validate the class name.
if (!LS.isstring(classname)) {
luaL_error(L_, "Not a class name: %s", lua_tostring(L_, classname));
}
if (LS.rawequal(classname, "_G")) {
luaL_error(L_, "_G is explicitly not allowed as a class name");
}
assert(LS.validclassname(classname));
// Fetch the global environment from the registry.
LS.getglobaltable(globtab);
// Get the classtab from the global environment.
// Create it if it doesn't exist.
LS.rawget(classtab, globtab, classname);
if (LS.isnil(classtab)) {
// Make sure we're not reusing a table that isn't a class.
if (LS.istable(classtab)) {
LS.rawget(cname, classtab, "__class");
} else {
LS.set(cname, LuaNil);
}
// Make a new table if necessary.
if (!LS.rawequal(cname, classname)) {
LS.newtable(classtab);
LS.rawset(globtab, classname, classtab);
LS.rawset(classtab, "__class", classname);
}
// If the name isn't bound to a table, abort.
if (!LS.istable(classtab)) {
luaL_error(L_, "%s is not a class", ckstring(classname).c_str());
}
// Repair the special fields.
LS.settabletype(classtab, LUA_TT_CLASS);
LS.rawset(classtab, "__index", classtab);
LS.rawset(classtab, "__class", classname);
// Put the stack back.
LS.result();
@@ -267,27 +343,6 @@ void LuaStack::makeclass(LuaSlot tab, const std::string &name) const {
lua_pop(L_, 1);
}
std::string LuaStack::classname(LuaSlot tab) const {
std::string result;
if (istable(tab)) {
lua_pushstring(L_, "__class");
lua_rawget(L_, tab);
if (lua_type(L_, -1) == LUA_TSTRING) {
lua_pushglobaltable(L_); // cname table
lua_pushvalue(L_, -2); // cname table cname
lua_rawget(L_, -2); // cname table ctab
if (lua_rawequal(L_, -1, tab)) {
size_t len;
const char *s = lua_tolstring(L_, -3, &len);
result = std::string(s, len);
}
lua_pop(L_, 3);
} else {
lua_pop(L_, 1);
}
}
return result;
}
int64_t LuaStack::tanid(LuaSlot tab) const {
int64_t result = 0;