简体   繁体   中英

Error when creating lua table from inside the c api

I have an A* algorithm in C, intended to be used from Lua. Now, the A* itself works fine but for some weird reason, when I call it from Lua, there's a weird error that pops out when any one of the argument functions (Neighbours) creates a table. Creating a table in C works fine. There are 2 versions of the library - 1st one called the script directly from C in the 'main' function, and creating tables from Lua worked smoothly. 2nd one is compiled to dll and loaded by the script which crashes when making tables. Why, I have no idea. I've already tried allocating all my memory inside C and passing lightuserdata but it made no difference. I have other .dlls compiled on the same machine which don't replicate this error.

C LIBRARY

int run(lua_State *L)
                      /*
                      1: string from, 
                      2: string to, 
                      3: string[] Neighbours(string of),
                      4: int Cost(string from, string to, string dest),
                      5: int Heuristic(string from, string to, string dest)
                      */
{
    char flag = 0;
    HE = HE ? HE : Heap_Alloc(200);
    Heap_Clear(HE);

    // create the HASHtable
    lua_createtable(L,1,300);
    // 6 - HASHtable (string -> {int cost,string Self,string parent})


    // get Heuristic(0,from,to)
    lua_pushvalue(L,5);
    lua_pushstring(L,0);
    lua_pushvalue(L,1);
    lua_pushvalue(L,2);
    lua_call(L,3,1); 

    {
        // 7 - Heuristic(0,from,to)
        Heap_val_t hp = {lua_tointeger(L,7), lua_tostring(L,1)};
        Z q;

        // HASH[from] = {cost=Heuristic, self=from, parent=nil}
        lua_pushvalue(L,1);
        lua_newuserdata(L,sizeof(struct g));
        q = lua_touserdata(L,-1);
        q->_cost = lua_tointeger(L,7);
        q->_self = lua_tostring(L,1);
        q->_parent = 0;
        lua_rawset(L,6);

        // pop Heuristic(0,from,to) (6)
        lua_pop(L,1);

        Heap_Push_macro(HE, hp);


        while (!Heap_Empty(HE))
        {
            int i=1;
            hp = Heap_Top(HE);
            Heap_Pop_macro(HE);

            // push Neighbours(Self) on the stack
            lua_pushvalue(L,3);
            lua_pushstring(L,hp._self);
            lua_call(L,1,1); // ALLOCATING TABLE INSIDE THIS GENERATES THE ERROR


            while(1)
            {
                // 7 - neighbours table[]

                // push neighbours[i]
                lua_rawgeti(L,-1,i);

                // check if we got to the end of neighbours
                if (!lua_isstring(L,-1))
                {
                    lua_pop(L,1);
                    break;
                }
                {
                    // 8 - neighbours[i]
                    int cost,heur;

                    // get HASH[hp.self].cost and pop from stack
                    lua_pushstring(L,hp._self);
                    lua_rawget(L,6);
                    q = lua_touserdata(L,-1);
                    cost = q->_cost;
                    lua_pop(L,1);

                    // call Cost(hp.self,*neighbours,to)
                    lua_pushvalue(L,4);
                    lua_pushstring(L,hp._self);
                    lua_pushvalue(L,8);
                    lua_pushvalue(L,2);
                    lua_call(L,3,1);
                    // add it to cost and remove from stack
                    cost += lua_tointeger(L,-1);
                    lua_pop(L,1);

                    // get Heuristic(hp._obj, *neighbours, to) and pop it
                    lua_pushvalue(L,5);
                    lua_pushstring(L,hp._self);
                    lua_pushvalue(L,8);
                    lua_pushvalue(L,2);
                    lua_call(L,3,1);
                    heur = lua_tointeger(L,-1);
                    lua_pop(L,1);

                    // get HASH[*neighbours]
                    lua_pushvalue(L,8);
                    lua_rawget(L,6);
                    q = lua_touserdata(L,-1);

                    if (!q  ||  q->_cost > cost+heur)
                    {
                        Heap_val_t  y = {cost+heur, lua_tostring(L,8)};
                        Heap_Push_macro(HE, y);
                        // HASH[*neighbours] = {cost=cost, self=*neighbours, parent=hp.self}
                        lua_pushvalue(L,8);
                        lua_newuserdata(L,sizeof(struct g));
                        q = lua_touserdata(L,-1);
                        q->_cost = cost;
                        q->_self = lua_tostring(L,8);
                        q->_parent = hp._self;
                        lua_rawset(L,6);
                    }
                    // remove 10
                    lua_pop(L,1);               
                    // 9

                }
                // remove neighbours[i]
                lua_pop(L,1);
                i++;
                // 8
            }


            // remove neighbours[]
            lua_pop(L,1);
            // 7

            lua_pushstring(L,hp._self);
            if (lua_equal(L,-1,2))
            {
                flag = 1;
                // pop the string
                lua_pop(L,1);
                break;
            }
            lua_pop(L,1);   
        }


        // 7 - return path table
        lua_createtable(L,1,1);
        if (flag)
        {
            int i=1,j;

            while(1)
            {
                Z g;
                lua_pushvalue(L,2);
                lua_rawget(L,6);
                g = lua_touserdata(L,-1);
                if (!g->_parent)
                {
                    lua_pop(L,1);
                    break;
                }

                lua_pushstring(L,g->_parent);
                lua_replace(L,2);
                lua_pushstring(L,g->_self);
                lua_rawseti(L,7,i++);
                lua_pop(L,1);
            }

            // reverse the table
            for (j=1, i--;  i-j > 0;  i--,j++)
            {
                lua_rawgeti(L,7,j);
                lua_rawgeti(L,7,i);
                lua_rawseti(L,7,j);
                lua_rawseti(L,7,i);
            }
        }
    }

    // replace HASH with return table
    lua_replace(L,6);
    return 1;
}

LUA SCRIPT

require 'astar'

function X(z)
    local a = z:find'[? ]'
    return tonumber(z:sub(1,a))
end
function Y(z)
    local a = z:find'[? ]'
    return tonumber(z:sub(a))
end


m,n = {-1,-1,-1,0,0,1,1,1},{-1,0,1,-1,1,-1,0,1}
function neighbours(of)
    print('neighbours',of)
    local x,y = X(of),Y(of)
    -- local r = {} -- creating a table from inside the C api crashes
    local r = 0

    for i=1,#m do
        local nx,ny = x+m[i],y+n[i]
        --table.insert(r,nx..' '..ny)
    end

    return r
end

function cost(from,to,dest)
    return 1
end
function heuristic(from,to,dest)
    local x1,y1,x2,y2 = X(to),Y(to),X(dest),Y(dest)
    return math.abs(x1-x2)+math.abs(y1-y2)
end


print{}     -- making tables before C api call..
r = astar.run('0 0','1 0', neighbours, cost, heuristic)
print{}     -- ..or after doesn't crash

print('r',r)
if r then
    print(#r)
    for i,j in pairs(r) do
        print(i,j)
    end
end

I finally figured it out: Lua doesn't like pendrives. When I offloaded the vc++ project and build it from my hard drive, everything went right. Kids, don't build Lua libraries on a pendrive.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM