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

发布于 2024-10-16 08:35:00 字数 5599 浏览 2 评论 0原文

我嵌入了 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)

如果我执行以下任一操作,我不会收到段错误:

  1. 删除 main 中对 luaL_openlibs 的调用
  2. 删除 。

不幸的是,我无法弄清楚除此之外的任何事情 此外,如果我在 event.subscribe 之后立即调用另一个函数,应用程序将挂起并且 GDB 报告:

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

Any ideas?

I've embedded Lua and written what's supposed to be a very simple event module in C. The problem is, when I try to exit my application, I receive a segmentation fault. GDB says:

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

Module:

#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;
    }
}

Main:

#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;
}

Test script:

function OnKeyDown()
    return
end

events.subscribe("OnKeyDown", OnKeyDown)

If I do either one of the following, I don't get the seg fault:

  1. Remove the call to luaL_openlibs in main
  2. Remove the call to add_callback in _events_subscribe

Unfortunately, I haven't been able to figure out anything beyond that. In addition, if I call another function immediately after event.subscribe, the application hangs and GDB reports:

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

Any ideas?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

楠木可依 2024-10-23 08:35:00

我知道这会是一件愚蠢的事情。我在 _events_subscribe 中错误地使用了 luaL_ref。应该是:

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

I knew it was going to be something silly. I was using luaL_ref incorrectly in _events_subscribe. It should be:

Callback* callback = add_callback(event, luaL_ref(L, LUA_REGISTRYINDEX));
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文