Lua engine: Enable checks for debug builds, kill sol::buffer. (#9419)

This commit is contained in:
Vas Crabb 2022-03-17 16:47:19 +11:00 committed by GitHub
parent 0074d3ad94
commit dd1e5b1d7a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 115 additions and 63 deletions

View File

@ -95,18 +95,6 @@ template <> struct is_container<image_interface_formats> : std::true_type { };
template <> struct is_container<plugin_options_plugins> : std::true_type { };
sol::buffer *sol_lua_get(sol::types<buffer *>, lua_State *L, int index, sol::stack::record &tracking)
{
return new sol::buffer(stack::get<int>(L, index), L);
}
int sol_lua_push(sol::types<buffer *>, lua_State *L, buffer *value)
{
delete value;
return 1;
}
template <typename T>
struct usertype_container<lua_engine::devenum<T> > : lua_engine::immutable_collection_helper<lua_engine::devenum<T>, T>
{
@ -834,7 +822,15 @@ void lua_engine::initialize()
}
new (&file) emu_file(path, flags);
}));
file_type.set("read", [](emu_file &file, sol::buffer *buff) { buff->set_len(file.read(buff->get_ptr(), buff->get_len())); return buff; });
file_type.set("read",
[] (emu_file &file, sol::this_state s, size_t len)
{
buffer_helper buf(s);
auto space = buf.prepare(len);
space.add(file.read(space.get(), len));
buf.push();
return sol::stack::pop<sol::object>(s);
});
file_type.set("write", [](emu_file &file, const std::string &data) { return file.write(data.data(), data.size()); });
file_type.set("puts", &emu_file::puts);
file_type.set("open", static_cast<std::error_condition (emu_file::*)(std::string_view)>(&emu_file::open));
@ -1001,16 +997,18 @@ void lua_engine::initialize()
}
return sol::make_object(sol(), ret);
});
item_type.set("read_block", [](save_item &item, int offset, sol::buffer *buff) {
if(!item.base || ((offset + buff->get_len()) > (item.size * item.count)))
item_type.set("read_block", [](save_item &item, sol::this_state s, int offset, size_t len) {
buffer_helper buf(s);
auto space = buf.prepare(len);
if(!item.base || ((offset + len) > (item.size * item.count)))
{
buff->set_len(0);
space.add(0);
}
else
{
const uint32_t blocksize = item.size * item.valcount;
uint32_t remaining = buff->get_len();
uint8_t *dest = reinterpret_cast<uint8_t *>(buff->get_ptr());
size_t remaining = len;
uint8_t *dest = reinterpret_cast<uint8_t *>(space.get());
while(remaining)
{
const uint32_t blockno = offset / blocksize;
@ -1022,8 +1020,10 @@ void lua_engine::initialize()
remaining -= chunk;
dest += chunk;
}
space.add(len);
}
return buff;
buf.push();
return sol::stack::pop<sol::object>(s);
});
item_type.set("write", [](save_item &item, int offset, uint64_t value) {
if(!item.base || (offset >= item.count))

View File

@ -21,7 +21,11 @@
#include <tuple>
#include <vector>
#ifdef MAME_DEBUG
#define SOL_ALL_SAFETIES_ON 1
#else
#define SOL_SAFE_USERTYPE 1
#endif
#include "sol/sol.hpp"
struct lua_State;
@ -30,6 +34,7 @@ class lua_engine
{
public:
// helper structures
class buffer_helper;
template <typename T> struct devenum;
template <typename T> struct simple_list_wrapper;
template <typename T> struct tag_object_ptr_map;

View File

@ -16,10 +16,100 @@
#include <lua.hpp>
#include <cassert>
#include <system_error>
class lua_engine::buffer_helper
{
private:
class proxy
{
private:
buffer_helper &m_host;
char *m_space;
size_t const m_size;
public:
proxy(proxy const &) = delete;
proxy &operator=(proxy const &) = delete;
proxy(proxy &&that) : m_host(that.m_host), m_space(that.m_space), m_size(that.m_size)
{
that.m_space = nullptr;
}
proxy(buffer_helper &host, size_t size) : m_host(host), m_space(luaL_prepbuffsize(&host.m_buffer, size)), m_size(size)
{
m_host.m_prepared = true;
}
~proxy()
{
if (m_space)
{
assert(m_host.m_prepared);
luaL_addsize(&m_host.m_buffer, 0U);
m_host.m_prepared = false;
}
}
char *get()
{
return m_space;
}
void add(size_t size)
{
assert(m_space);
assert(size <= m_size);
assert(m_host.m_prepared);
m_space = nullptr;
luaL_addsize(&m_host.m_buffer, size);
m_host.m_prepared = false;
}
};
luaL_Buffer m_buffer;
bool m_valid;
bool m_prepared;
public:
buffer_helper(buffer_helper const &) = delete;
buffer_helper &operator=(buffer_helper const &) = delete;
buffer_helper(lua_State *L)
{
luaL_buffinit(L, &m_buffer);
m_valid = true;
m_prepared = false;
}
~buffer_helper()
{
assert(!m_prepared);
if (m_valid)
luaL_pushresult(&m_buffer);
}
void push()
{
assert(m_valid);
assert(!m_prepared);
luaL_pushresult(&m_buffer);
m_valid = false;
}
proxy prepare(size_t size)
{
assert(m_valid);
assert(!m_prepared);
return proxy(*this, size);
}
};
template <typename T>
struct lua_engine::simple_list_wrapper
{
@ -40,52 +130,9 @@ struct lua_engine::tag_object_ptr_map
namespace sol {
class buffer
{
public:
// sol does lua_settop(0), save userdata buffer in registry if necessary
buffer(int size, lua_State *L)
{
ptr = luaL_buffinitsize(L, &buff, size);
len = size;
if(buff.b != buff.initb)
{
lua_pushvalue(L, -1);
lua_setfield(L, LUA_REGISTRYINDEX, "sol::buffer_temp");
}
}
~buffer()
{
lua_State *L = buff.L;
if(lua_getfield(L, LUA_REGISTRYINDEX, "sol::buffer_temp") != LUA_TNIL)
{
lua_pushnil(L);
lua_setfield(L, LUA_REGISTRYINDEX, "sol::buffer_temp");
}
else
lua_pop(L, -1);
luaL_pushresultsize(&buff, len);
}
void set_len(int size) { len = size; }
int get_len() { return len; }
char *get_ptr() { return ptr; }
private:
luaL_Buffer buff;
int len;
char *ptr;
};
// don't convert core_optons to a table directly
// don't convert core_options to a table directly
template <> struct is_container<core_options> : std::false_type { };
// buffer customisation
sol::buffer *sol_lua_get(sol::types<buffer *>, lua_State *L, int index, sol::stack::record &tracking);
int sol_lua_push(sol::types<buffer *>, lua_State *L, buffer *value);
// these things should be treated as containers
template <typename T> struct is_container<lua_engine::devenum<T> > : std::true_type { };