Компиляция Lua lib для Android - успех, но странные segfaults - программирование
Подтвердить что ты не робот

Компиляция Lua lib для Android - успех, но странные segfaults

Извините за длинный вопрос. Если вы хотите, пропустите часть о компиляции Lua (что почти нормально) и получите прямой ответ на последний вопрос.

Пусть компилирует Lua-библиотеку как статическую библиотеку для Android.

Загрузите последний источник и зайдите в doc/readme.html - Создайте Lua в разделе других систем для списка файлов для компиляции.

И, конечно же, посмотрите на make файлы - посмотрите, каким образом мы должны установить флаг платформы, например linux, bsd e.t.c. Но, конечно, нет платформы Android, поэтому у нас есть выбор для установки платформы на ANSI, Linux, Posix или Generic.

Первый вопрос: он строит нормально (с одним исключением из llex.c, о котором я расскажу ниже) даже без флага платформы, так что, возможно, это лишнее?

Я установил флаг ANSI.

Android.mk

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE    := lua
LOCAL_CFLAGS    := -DLUA_ANSI
LOCAL_SRC_FILES := lapi.c lcode.c lctype.c ldebug.c ldo.c ldump.c lfunc.c lgc.c llex.c lmem.c lobject.c lopcodes.c lparser.c lstate.c lstring.c ltable.c ltm.c lundump.c lvm.c lzio.c lauxlib.c lbaselib.c lbitlib.c lcorolib.c ldblib.c liolib.c lmathlib.c loslib.c lstrlib.c ltablib.c loadlib.c linit.c
include $(BUILD_STATIC_LIBRARY)

Application.mk

APP_MODULES := lua
APP_PLATFORM := android-8
APP_OPTIM   := release
APP_ABI := armeabi

И получили ошибки, конечно

Compile thumb  : lua <= llex.c
jni/llex.c: In function 'trydecpoint':
jni/llex.c:214:18: error: 'struct lconv' has no member named 'decimal_point'


#if !defined(getlocaledecpoint)
#define getlocaledecpoint() (localeconv()->decimal_point[0]) //Missing struct member
#endif

Фиксировать его самым дешевым способом

#if !defined(getlocaledecpoint)
#define getlocaledecpoint() ('.') //Code-monkey style
#endif

В Android NDK существуют некоторые ограничения на locale.h, поэтому эта ошибка не удивительна.

Также появились ошибки о size_t, UCHAR_MAX, INT_MAX - добавление llimits.h в llex.c, и теперь все ошибки исчезли.

В настоящее время существуют только предупреждения о "отсутствии разрыва в конце дела" и "нет возврата в функции, возвращающей не-void" в static int llex, но мы не связываемся с исходным кодом Lua не больше, потому что это не то, что жизненно важно.

Второй вопрос: Я собираюсь программировать ад для таких быстрых исправлений?

Захватите нашу свежую испеченную LuaLib в каталоге obj/armeabi и протестируйте ее. Конечно, для загрузки скриптов из файловой системы Android нам нужно написать некоторый загрузчик файлов с использованием класса AssetManager в Java, поэтому давайте сделаем это очень просто, нажав и прочитав глобальные вары lua.

TestLua - Android.mk

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)
LOCAL_MODULE    := lua
LOCAL_SRC_FILES := liblua.a
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/lua-inc //Where .h files from lua src stored
include $(PREBUILT_STATIC_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE    := LuaLibTest
LOCAL_STATIC_LIBRARIES:= lua
LOCAL_SRC_FILES := LuaLibTest.c
LOCAL_LDLIBS    := -llog
include $(BUILD_SHARED_LIBRARY)

LuaLibTest.c

#include "LuaLibTest.h"
#include "lua-inc/lua.h"
#include "lua-inc/lauxlib.h"
#include <android/log.h>

#define INFO_TAG "[INFO]"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, INFO_TAG, __VA_ARGS__)

 JNIEXPORT void JNICALL Java_com_lualib_test_NativeLib_testLua(JNIEnv* env, jclass _class)
{
 LOGI("HI FROM C");
 lua_State* L = luaL_newstate();
 luaL_openlibs(L);
 lua_pushstring(L, "Some string from Android C" );
 lua_setglobal(L, "TEST" );
 lua_getglobal(L, "TEST" );
 const char* res = lua_tostring(L, lua_gettop(L));
 LOGI("LUA TEST VAL: %s", res);
 lua_pop(L, 1);
 lua_close(L);
}

Result

Он также работает, если мы читаем файл script с AssetManager и помещаем его содержимое в строку, которая подается в lual_dostring(). Итак, да, мы создаем lua для Android (кроме функций lua i/o, которые не будут работать, потому что stdio, как printf, не работает в Android NDK).

Однако эта сборка имеет странные ошибки, например - fps script обновляет каждый кадр, но в любой момент может упасть с следующей ошибкой в ​​функции, которая обновляет fps с дельта-временем кадра

FPS.lua

FPS = {}

function initFPS()
FPS.fps = 0
FPS.last_fps = 0
FPS.frames_count = 0
FPS.frames_time = 0.0
local fps_msg = "FPS: " .. FPS.fps
c_set_fps(fps_msg);//Set some label in app - c function
end

function updateFPS(frameDeltaTime)
FPS.frames_count = FPS.frames_count + 1
FPS.frames_time = FPS.frames_time + frameDeltaTime
if FPS.frames_time >= 1000.0
then
    FPS.frames_time = 0.0;
    FPS.fps = FPS.frames_count;
    FPS.frames_count = 0;
    if FPS.last_fps ~= FPS.fps
    then
        local fps_msg = "FPS: " .. FPS.fps
        c_set_fps(fps_msg);
        FPS.last_fps = FPS.fps
    end
end
end

FPS.c

 void update_fps(const double* frame_delta_time) //SEGFAULT at this, at random time
 {
  lua_State* l = get_lua();
  lua_getglobal(l, "updateFPS");
  lua_pushnumber(l, *frame_delta_time);
  lua_call(l, 1, 0);
 }

И получите следующее сообщение об ошибке со сбоем всего приложения в случайное время (1 мин - 3 мин)
Error msg

Последний вопрос (yay, вы сделали это/пропустите скучную часть)
Почему я получаю segfaults, почему в случайное время? FPS script - это просто пример, у большинства моих lua script есть шанс свернуть все приложение (больше звонков == лучший шанс). Таким образом, некоторые игроки script, которые иногда меняют свой каталог при новом сбое pos.

Я думаю, это потому, что конфликт с мусором для Android/Java и уборщиком Lua, поэтому попробуйте освободить уже освобожденную память.

РЕДАКТИРОВАТЬ - ОТ ДВОЙНОГО ПУНКТА ПРИХОДИТЕ И ПОЧЕМУ:

 #define MS_1_SEC 1000.0

 typedef struct time_manager
 {
   double _time;
   double delta_time;
 }time_manager;

 static double get_ms(s_time* time)//get time in ms
 {
  return MS_1_SEC * time->tv_sec + (double) time->tv_nsec / NS_1_SEC;
 }

 double get_time_now()
 {
 s_time time_now;
 clock_gettime(CLOCK_REALTIME, &time_now);
 return get_ms(&time_now);
 }

 void init_time_manager(time_manager* tm)
 {
 tm->_time = get_time_now();
 tm->delta_time = 0.0;
}

void update_time_manager(time_manager* tm)
{
 double time_now = get_time_now();
 tm->delta_time = time_now - tm->_time;
 tm->_time = time_now;
}


static time_manager TM;//Global static var for whole render module

В функции onInit()

 init_time_manager(&TM);

В функции onDraw()

 double* frame_time = &TM.delta_time;//get pointer to delta time
 update_ui(frame_time);//Pass it every function
 update_sprites(frame_time);
 update_fps(frame_time);
 ...
 draw_fps();
 update_time_manager(&TM);

Почему я использую указатель для двойного, а не двойного? Ну, это экономит 4 байта копирования (каждый указатель имеет размер 4, double имеет размер 8) Параметр frame_delta_time для каждой функции, такой как update_ui(), я делаю то же самое для каждой структуры/типа больше 4 байтов, указатели константы вместо просто struct x для доступа только для чтения. Это плохо?

4b9b3361

Ответ 1

Ваши изменения выглядят нормально и подходят для вашей системы. Список рассылки lua предлагает внести изменения в luaconf.h, а не llex.c (http://lua-users.org/lists/lua-l/2012-08/msg00100.html), но это не имеет большого значения. (Короче говоря, вы не собираетесь в ад для этих изменений...).

Я предполагаю, что segfaults происходят, потому что некоторые из вашего моста C-lua делают что-то "плохое". Я предполагаю, что это будет какой-то стек lua ​​поверх/под потоком или доступ за пределами стека lua с использованием недопустимого индекса. Вы можете отслеживать это, если вы можете построить часть моста на linux/os x и использовать valgrind. (Аналогичные инструменты существуют и для окон, но я не уверен в том, что для него характерен для Android)

Ответ 2

Посмотрите на это: http://comments.gmane.org/gmane.comp.security.nmap.devel/14966

static void trydecpoint (LexState *ls, SemInfo *seminfo) {
  char old = ls->decpoint;
  ls->decpoint = '.';   //ls->decpoint = getlocaledecpoint();  // try to fix error: 'struct lconv' has no member named 'decimal_point'   -------- look at here
  buffreplace(ls, old, ls->decpoint);  /* try new decimal separator */
  if (!buff2d(ls->buff, &seminfo->r)) {
    /* format error with correct decimal point: no more options */
    buffreplace(ls, ls->decpoint, '.');  /* undo change (for error message) */
    lexerror(ls, "malformed number", TK_NUMBER);
  }
}

Ответ 3

Иногда это помогает скомпилировать lua с помощью -DLUA_USE_APICHECK. Он будет генерировать некоторые сообщения об ошибках вместо segfaults.