'Why does calling lua_newuserdata result in SIGSEGV Segmentation Fault?

I'm trying to identify why a call to lua_newuserdata result in SIGSEGV. The gdb backtrace is :

Thread 2 "main.o" received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7ffff7c1a700 (LWP 41635)]
0x0000555555573bbe in sweepstep.constprop ()
(gdb) backtrace
#0  0x0000555555573bbe in sweepstep.constprop ()
#1  0x000055555557531c in singlestep ()
#2  0x0000555555575d22 in luaC_step ()
#3  0x000055555556fbb7 in lua_newuserdatauv ()

To give some scope, this particular call works on numerous invocations -- it only yields this result when I have an io.popen call inside a lua script that runs a process that takes longer to complete than the lifecycle of the lua thread (coroutine) that spawns it. Any help is greatly appreciated. I wonder if stopping the GC with lua_gc(L, GCSTOP)/lua_gc(L, GCRESTART) around the creation of a new lua thread (coroutine) and it's associative offending lua_newuserdata call might help.

EDIT: (apologies for the long code) The repo SIGFAULTs on lua_pushlstring:

    #include <stdlib.h>
    #include <unistd.h>
    #include "lualib.h"
    #include "lauxlib.h"

    #define NT 18 //it works with a lower value

    struct stream_data {
    int fd;
    int len;
    int idx;
    char buf[128];
    };

    struct stream {
       lua_State *L;
       lua_State *T;
       struct stream_data *strm_d;
       int id;
       int status;
       char buf[128];
    };

    static lua_State *L;
    static int active = 0;
    static int fref;

    struct stream *new_strm(lua_State *L, int i) {
        struct stream *strm;
        lua_State *T;
        char str[64];
        int na;

        snprintf(str, 64, "thread id: %i", i);
        T = lua_newthread(L);

        lua_pushlightuserdata(L, T);
        strm = (struct stream *) lua_newuserdata(L, sizeof(struct stream));
        lua_rawset(L, LUA_REGISTRYINDEX);
        lua_pop(L, 1);

        lua_rawgeti(T, LUA_REGISTRYINDEX, fref);
        lua_pushstring(T, str);

        strm->id = i;
        strm->T = T;
        strm->L = L;

        strm->status = lua_resume(T, L, 1, &na);

        return strm;
    }

    static int register_fn(lua_State *L) {
        fref = luaL_ref(L, LUA_REGISTRYINDEX);
        return 0;
    }

    int lua_read(lua_State *L) {
        struct stream *strm;
        struct stream_data *strm_d;
        void *sd;
        FILE *f;

        lua_pushlightuserdata(L, L);
        lua_rawget(L, LUA_REGISTRYINDEX);
        strm = (struct stream*) lua_touserdata(L, -1);
        lua_pop(L, 1);

        sd = (void*) lua_touserdata(L, 1);
        f = *(FILE**) luaL_checkudata(L, 1, LUA_FILEHANDLE);

        lua_pushlightuserdata(L, (void*) sd);
        strm_d = lua_newuserdata(L, sizeof(struct stream_data));
        lua_rawset(L, LUA_REGISTRYINDEX);

        strm_d->len = lua_tointeger(L, 2);
        strm_d->idx = 0;
        strm_d->fd = fileno(f);
        strm->strm_d = strm_d;

        return lua_yield(L, 0);
    }

    int do_read(struct stream *strm) {
        struct stream_data *strm_d = strm->strm_d;
        int na, rv;

        if ((rv = read(strm_d->fd, &strm_d->buf, strm_d->len - strm_d->idx)) >= 0) {
            strm_d->idx += rv;
            if (strm_d->idx >= strm_d->len) {
                lua_pushlstring(strm->T, strm_d->buf, strm_d->len);
                strm->status = lua_resume(strm->T, strm->L, 1, &na);
            }
        }
        return 0;

    }

    static int luaopen_app(lua_State *L) {
        struct luaL_Reg functions[] = {
            { "register_fn",    register_fn},
            { "read",       lua_read },
        { NULL, NULL }
        };
        luaL_newlib(L, functions);
        return 1;
    }

lua_State* app_init() {
    L = luaL_newstate();

    luaL_openlibs(L);
    lua_getglobal(L, "package");
    lua_getfield(L, -1, "preload");
    lua_pushcfunction(L, luaopen_app);
    lua_setfield(L, -2, "app");
    lua_pop(L, 2);

    luaL_loadfile(L, "script.lua");
    lua_pcall(L, 0, 0, 0);

    return L;
}

int main() {
    L = app_init();

    struct stream *strm[NT];
    int i;

    for (i = 0; i < NT; i++) {
        strm[i] = new_strm(L, i);
    }

    while (1) {
        int done = 1;

        for (i = 0; i < NT; i++) {
            if (strm[i]->status == 1) {
                do_read(strm[i]);
                done = 0;
            } else {
                lua_gc(L, LUA_GCCOLLECT, 0);
                done = 1;
                continue;
            }
        }
          if (done == 1)
            break;
    }

    return 0;
}
script.lua
app = require 'app'

local function foo(txt)
    print(txt)

    local F = assert(io.popen('sh ./script.sh 2', 'r'))

    local g = app.read(F, 5)
    print(txt..' read: '..g)

    print('done')
end

app.register_fn(foo)
script.sh
#!/bin/sh
echo 1 $1
sleep 14
echo 2 $1
echo 3 $1
echo 4 $1
echo 5 $1


Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source