退出应用程序时,luaF_newproto上的Lua 5.1分段错误

时间:2011-02-06 08:16:33

标签: c lua segmentation-fault

我已经嵌入了Lua并在C中编写了一个非常简单的事件模块。问题是,当我尝试退出应用程序时,我收到了一个分段错误。 GDB说:

Program received signal SIGSEGV, Segmentation fault.
0x003a72c3 in luaF_newproto () from C:\Windows\SysWOW64\lua5.1.dll

模块:

#include <stdlib.h>
#include <lua.h>
#include <lauxlib.h>
#include "ice.h"

typedef struct Callback_t {
    int ref;
    struct Callback_t* next;
} Callback;

typedef struct Event_t {
    char* name;
    Callback* chead;
    struct Event_t* next;
} Event;

static Event* ehead = NULL;

static Event* find_event(char* name) {
    Event* current = ehead;
    while (current) {
        if (strcmp(current->name, name) == 0)
            return current;
        current = current->next;
    }
    return NULL;
}

static Event* add_event(char* name) {
    Event* event = find_event(name);
    if (event == NULL) {
        event = (Event*)malloc(sizeof(Event));
        if (event == NULL)
            return NULL;

        event->name = name;
        event->chead = NULL;
        event->next = ehead;
        ehead = event;
    }

    return event;
}

static Callback* find_callback(Event* event, int ref) {
    Callback* current = event->chead;
    while (current) {
        if (current->ref == ref)
            return current;
        current = current->next;
    }
    return NULL;
}

static Callback* add_callback(Event* event, int ref) {
    Callback* callback = find_callback(event, ref);
    if (callback == NULL) {
        callback = (Callback*)malloc(sizeof(Callback));
        if (callback == NULL)
            return NULL;

        callback->ref = ref;
        callback->next = event->chead;
        event->chead = callback;
    }

    return callback;
}

static int _events_subscribe(lua_State* L) {
    const char* name = luaL_checkstring(L, 1);

    if (!lua_isfunction(L, 2))
        luaL_typerror(L, 2, lua_typename(L, LUA_TFUNCTION));

    Event* event = add_event((char*)name);
    if (event == NULL)
        luaL_error(L, "Failed to allocate memory for event.");

    Callback* callback = add_callback(event, luaL_ref(L, 2));
    if (callback == NULL)
        luaL_error(L, "Failed to allocate memory for event callback.");

    return 0;
}

static int _events_unsubscribe(lua_State* L) {
    // Not implemented yet
    return 0;
}

static const luaL_reg _events_methods[] = {
    { "subscribe", _events_subscribe },
    { "unsubscribe", _events_unsubscribe },
    { NULL, NULL }
};

int luaopen_events(lua_State* L) {
    luaL_openlib(L, "events", _events_methods, 0);
    lua_pop(L, 1);
    return 0;
}

void lua_closeevents(lua_State* L) {
    Event* event = ehead;

    while (event) {
        Callback* callback = event->chead;

        while (callback) {
            Callback* cnext = callback->next;
            free(callback);
            callback = cnext;
        }

        Event* enext = event->next;
        free(event);
        event = enext;
    }
}

主:

#include <stdlib.h>
#include <windows.h>
#include <SDL/SDL.h>
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
#include "ice.h"

lua_State* Lua;
SDL_Surface* screen;

void cleanup() {
    SDL_Quit();
    lua_closeevents(Lua);
    lua_close(Lua);
}

int main(int argc, char** argv) {
    Lua = lua_open();

    if (Lua == NULL)
        FATAL_ERROR("Failed to initialize Lua scripting engine.", NULL);

    luaL_openlibs(Lua);
    luaopen_events(Lua);

    if (SDL_Init(SDL_INIT_VIDEO) == -1)
        FATAL_ERROR("Failed to initialize SDL subsystems.", NULL);

    atexit(cleanup);

    screen = SDL_SetVideoMode(800, 600, 32, SDL_SWSURFACE);

    if (screen == NULL)
        FATAL_ERROR("Failed to set video mode.", NULL);

    if (argc > 1) {
        if (luaL_loadfile(Lua, argv[1]) != 0 || lua_pcall(Lua, 0, LUA_MULTRET, 0) != 0) {
            const char* msg = lua_tostring(Lua, -1);
            if (msg == NULL) msg = "No error message available.";
            FATAL_ERROR("%s", msg);
        }
    } else {
        FATAL_ERROR("No startup script specified.", NULL);
    }

    SDL_Event event;
    do {
        while (SDL_PollEvent(&event)) {
            switch (event.type) {
                case SDL_VIDEORESIZE:
                    DEBUG_WRITE("Resize", NULL);
                    screen = SDL_SetVideoMode(event.resize.w, event.resize.h,
                        screen->format->BitsPerPixel, screen->flags);
                    break;
                case SDL_USEREVENT:
                    switch (event.user.code) {
                        case SDL_USER_VIDEOFLAGS:
                            screen = SDL_SetVideoMode(screen->w, screen->h,
                                screen->format->BitsPerPixel,
                                *(int*)event.user.data1);
                            break;
                    }
                    break;
                default:
                    break;
            }
        }
    } while (event.type != SDL_QUIT);

    return EXIT_SUCCESS;
}

测试脚本:

function OnKeyDown()
    return
end

events.subscribe("OnKeyDown", OnKeyDown)

如果我执行以下任一操作,我就不会遇到seg错误:

  1. 移除luaL_openlibs
  2. 中对main的号召
  3. 移除add_callback
  4. 中对_events_subscribe的号召

    不幸的是,除了那之外,我还没有弄明白。此外,如果我在event.subscribe之后立即调用另一个函数,则应用程序将挂起并且GDB报告:

    Program received signal SIGSEGV, Segmentation fault.
    0x002c00a8 in luaS_newlstr () from C:\Windows\SysWOW64\lua5.1.dll
    

    有什么想法吗?

1 个答案:

答案 0 :(得分:1)

我知道这会有些愚蠢。我在luaL_ref中错误地使用了_events_subscribe。它应该是:

Callback* callback = add_callback(event, luaL_ref(L, LUA_REGISTRYINDEX));