Segmentation Fault при завершении скрипта на lua

85
05 мая 2021, 07:50

Написал небольшой модуль для lua5.1 (в качестве эксперимента) на с++ (понятное дело функции экспортированы в C). Модуль предоставляет объект массив чисел с такими операциями как: получить размер, установить значение, получить значение по индексу. Все просто, все понятно. Вот код:

// main.cpp
#include <iostream>
#include <iterator>
#include <lauxlib.h>
#include <lua.h>
#define ARRAY_META "levkovitch.array"
#pragma pack(1)
class LuaArray final {
public:
  size_t size() const {
    return *reinterpret_cast<size_t *>(ptr_);
  }
  float &operator[](int i) {
    return (reinterpret_cast<float *>(ptr_) + sizeof(size_t))[i];
  }
  LuaArray(void *ptr)
      : ptr_{ptr} {
  }
  void setSize(size_t size) {
    *reinterpret_cast<size_t *>(ptr_) = size;
  }
private:
  void *ptr_;
};
extern "C" {
/**\brief create new array of floats with given size
 */
int lua_newarray(::lua_State *state) {
  int size = ::luaL_checknumber(state, 1);
  luaL_argcheck(state, size > 0, 1, "have to be number > 0");
  LuaArray data =
      ::lua_newuserdata(state, sizeof(LuaArray) + size * sizeof(float));
  data.setSize(size);
  luaL_getmetatable(state, ARRAY_META);
  ::lua_setmetatable(state, -2);
  return 1;
}
int lua_sizearray(::lua_State *state) {
  LuaArray arr = ::luaL_checkudata(state, 1, ARRAY_META);
  ::lua_pushnumber(state, arr.size());
  return 1;
}
int lua_setvalue(::lua_State *state) {
  LuaArray arr   = ::luaL_checkudata(state, 1, ARRAY_META);
  int      index = ::luaL_checknumber(state, 2);
  float    val   = ::luaL_checknumber(state, 3);
  luaL_argcheck(state, index > 0 && index <= (int)arr.size(), 2, "wrong index");
  arr[index] = val;
  return 0;
}
int lua_getvalue(::lua_State *state) {
  LuaArray arr   = ::lua_touserdata(state, 1);
  int      index = ::luaL_checknumber(state, 2);
  luaL_argcheck(state, index > 0 && index <= (int)arr.size(), 2, "wrong index");
  ::lua_pushnumber(state, arr[index]);
  return 1;
}
static const ::luaL_Reg arrayFuncs[] = {
    {"new", lua_newarray},
    {nullptr, nullptr},
};
static const ::luaL_Reg arrayMembers[] = {
    {"getval", lua_getvalue},
    {"setval", lua_setvalue},
    {"size", lua_sizearray},
    {nullptr, nullptr},
};
int luaopen_array(::lua_State *state) {
  ::luaL_newmetatable(state, ARRAY_META);
  ::lua_pushvalue(state, -1);
  ::lua_setfield(state, -2, "__index");
  ::luaL_openlib(state, nullptr, arrayMembers, 0);
  ::luaL_openlib(state, "array", arrayFuncs, 0);
  return 1;
}
}

lua

local array = require("array")
local function main()
  local arr = array.new(10)
  if not arr then
    print("invalid arr")
  end
  for i = 1, arr:size() do
    arr:setval(i, i * 2)
  end
  for i = 1, arr:size() do
    print(arr:getval(i))
  end
end
main()

Все работает как и ожидалось, но возникли проблемы, когда я переделал код для доступа к вышеперечисленным методам через __len, __index, __newindex поля метадаблицы:

// main.cpp
#include <iostream>
#include <iterator>
#include <lauxlib.h>
#include <lua.h>
#define ARRAY_META "levkovitch.array"
#pragma pack(1)
class LuaArray final {
public:
  size_t size() const {
    return *reinterpret_cast<size_t *>(ptr_);
  }
  float &operator[](int i) {
    return (reinterpret_cast<float *>(ptr_) + sizeof(size_t))[i];
  }
  LuaArray(void *ptr)
      : ptr_{ptr} {
  }
  void setSize(size_t size) {
    *reinterpret_cast<size_t *>(ptr_) = size;
  }
private:
  void *ptr_;
};
extern "C" {
/**\brief create new array of floats with given size
 */
int lua_newarray(::lua_State *state) {
  int size = ::luaL_checknumber(state, 1);
  luaL_argcheck(state, size > 0, 1, "have to be number > 0");
  LuaArray data =
      ::lua_newuserdata(state, sizeof(LuaArray) + size * sizeof(float));
  data.setSize(size);
  luaL_getmetatable(state, ARRAY_META);
  ::lua_setmetatable(state, -2);
  return 1;
}
int lua_sizearray(::lua_State *state) {
  LuaArray arr = ::luaL_checkudata(state, 1, ARRAY_META);
  ::lua_pushnumber(state, arr.size());
  return 1;
}
int lua_setvalue(::lua_State *state) {
  LuaArray arr   = ::luaL_checkudata(state, 1, ARRAY_META);
  int      index = ::luaL_checknumber(state, 2);
  float    val   = ::luaL_checknumber(state, 3);
  luaL_argcheck(state, index > 0 && index <= (int)arr.size(), 2, "wrong index");
  arr[index] = val;
  return 0;
}
int lua_getvalue(::lua_State *state) {
  LuaArray arr   = ::lua_touserdata(state, 1);
  int      index = ::luaL_checknumber(state, 2);
  luaL_argcheck(state, index > 0 && index <= (int)arr.size(), 2, "wrong index");
  ::lua_pushnumber(state, arr[index]);
  return 1;
}
static const ::luaL_Reg arrayFuncs[] = {
    {"new", lua_newarray},
    {nullptr, nullptr},
};
static const ::luaL_Reg arrayMembers[] = {
    {"__index", lua_getvalue},
    {"__newindex", lua_setvalue},
    {"__len", lua_sizearray},
    {nullptr, nullptr},
};
int luaopen_array(::lua_State *state) {
  ::luaL_newmetatable(state, ARRAY_META);
  ::luaL_openlib(state, nullptr, arrayMembers, 0);
  ::luaL_openlib(state, "array", arrayFuncs, 0);
  return 1;
}
}

lua

local array = require("array")
local function main()
  local arr = array.new(10)
  if not arr then
    print("invalid arr")
  end
  for i = 1, #arr do
    arr[i] = i * 2
  end
  for i = 1, #arr do
    print(arr[i])
  end
end
main()

Изменения минимальны и программа даже работает как ожидается до момента ее завершения, но падает при выходе. Почему? Предологаю, что дело в сборщике мусора, но что же все таки происходит?

PS когда ставлю collectgarbage() до цикла с присваиванием, скрипт завершается без ошибки,а если сразу после цикла с присваиванием, то на этом месте вылетает segmentation fault

READ ALSO
Запись в файл для всех файлов проекта

Запись в файл для всех файлов проекта

Друзья, помогите с задачейКак сделать так, чтобы запись в файл производилась из всех файлов проекта(например

85
Как сделать добавление товара в корзину!

Как сделать добавление товара в корзину!

Есть у меня кнопка на ней ссылка которая передаёт значения!

91
Как обрезать часть ссылки?

Как обрезать часть ссылки?

Есть например у меня ссылка!

197
Записать переменную полученную через callback [дубликат]

Записать переменную полученную через callback [дубликат]

Как получить данные из response в переменную res?

92