Error when creating lua table from inside the c api - c
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.
Related
C: Bus Error between function returns and execution goes back to parent function
To simplify the problem as much as possible, I have two functions, a parent that calls the child. Everything executes okay till it gets to the return of the child function. After that I get a Bus Error. int main () { game(); // this doesn't get executed and program fails with bus error printf("Execute 2"); return 1; } int game () { game_t GameInfo = {.level = 1, .score = 0, .playerCh = 0, .playerX = 1, .playerY = 1}; gameLevel(&GameInfo); mvprintw(1,1, "Executed"); // code works up to here and get's executed properly return 1; }; void gameLevel (game_t *GameInfo) { // determine the size of the game field int cellCols = COLS / 3; int cellRows = (LINES / 3) - 2; GameInfo -> playerX = 1; GameInfo -> playerY = 1; generateMaze(0); int solved = 0; int level = GameInfo -> level; // default player position getPlayerDefault(GameInfo); pthread_t enemies_th; pthread_create(&enemies_th, NULL, enemies, (void *)GameInfo); // enemies(&level); while (solved == 0 && GameInfo -> collision != 1) { printGameInfo(GameInfo); noecho(); char move = getch(); echo(); if (GameInfo -> collision != 1) { if (checkMoveValidity(move, GameInfo) == 1) { solved = movePlayer(move, GameInfo); if (solved == 1) { break; } } } else { break; } } if (solved == 1) { pthread_cancel(enemies_th); GameInfo->level++; gameLevel(GameInfo); } else { // game over pthread_cancel(enemies_th); return; } } Now, the code is much more complicated than here, but I think that shouldn't have any influence on this (?) as it executes properly, until the return statement. There is also ncurses and multithreading, quite complex custom structures, but it all works, up until that point. Any ideas ? Tried putting print statements after each segment of code, everything worked up until this.
pthread_cancel() doesn't terminate the requested thread immediately. The only way to know that a cancelled thread has terminated is to call pthread_join(). If the thread is left running, it will interfere with use of the GameInfo variable in the next level of the game if the current level is solved, or may use the GameInfo variable beyond its lifetime if the current level was not solved and the main thread returns back to the main() function. To make sure the old enemies thread has terminated, add calls to pthread_join() to the gameLevel() function as shown below: if (solved == 1) { pthread_cancel(enemies_th); pthread_join(enemies_th); GameInfo->level++; gameLevel(GameInfo); } else { // game over pthread_cancel(enemies_th); pthread_join(enemies_th); return; } The use of tail recursion in gameLevel() seems unnecessary. I recommend returning the solved value and letting the game() function start the next level: In game(): while (gameLevel(&GameInfo)) { GameInfo.level++; } In gameLevel(): int gameLevel(game_t *GameInfo) { /* ... */ pthread_cancel(enemies_th); pthread_join(enemies_th); return solved; }
Updating array in a function causes pointer lose
I am trying to divide my code into functions, I have a sample code of "Game Of Life". However, when I try to initialize 2D grid array in a function, gnuplot gives no valid data points error. These are global variables declared before main: static char **currWorld=NULL, **nextWorld=NULL This is the original logic to init game grid, but this part is in main. if (game == 0){ // Use Random input for(i=1;i<nx-1;i++){ for(j=1;j<ny-1;j++) { currWorld[i][j] = (real_rand() < prob); population[w_plot] += currWorld[i][j]; } } } else if (game == 1){ // Block, still life printf("2x2 Block, still life\n"); int nx2 = nx/2; int ny2 = ny/2; currWorld[nx2+1][ny2+1] = currWorld[nx2][ny2+1] = currWorld[nx2+1][ny2] = currWorld[nx2][ny2] = 1; population[w_plot] = 4; } else if (game == 2){ // Glider (spaceship) printf("Glider (spaceship)\n"); // Your code codes here } else { printf("Unknown game %d\n",game); exit(-1); } This is my function: int init_game(int choice, int probability){ int i,j; if (choice == 0){ // Use Random input for(i=1;i<nx-1;i++){ for(j=1;j<ny-1;j++) { currWorld[i][j] = (real_rand() < probability); population[w_plot] += currWorld[i][j]; } } } else if (choice == 1){ // Block, still life printf("2x2 Block, still life\n"); int nx2 = nx/2; int ny2 = ny/2; currWorld[nx2+1][ny2+1] = currWorld[nx2][ny2+1] = currWorld[nx2+1][ny2] = currWorld[nx2][ny2] = 1; population[w_plot] = 4; } else if (choice == 2){ // Glider (spaceship) printf("Glider (spaceship)\n"); // Your code codes here } else { printf("Unknown game %d\n",choice); exit(-1); } } and my function call in main: init_game(game, prob); value of game is 0, prob is 0.2 and I tested memory allocations and other stuff, they work fine. Only difference is I moved the logic to a function. How can this happen? My arrays are global, I cannot understand how it cannot be initialized. This is the gnuplot error: Skipping data file with no valid points Since gnuplot and other functions are works fine, I did not add them but if you need any info, I can add. Here is the link of file itself: file
Having trouble figuring out this segmentation fault
I'm sure the mistake is obvious, but I sure am having trouble finding it. Basically I am trying to make a chessboard via 2D array. I am testing its functionality via 8 queens test... it is not functional. Somehow one of my integer values is getting out of whack, as gdb shows: .... (gdb) cont Continuing. Program received signal SIGSEGV, Segmentation fault. 0x080487f8 in diagnols (PARAMETER_ONE=0, PARAMETER_TWO=0) at eq1.c:77 77 if (key->board[abc][bcd] == 1) { (gdb) print abc 4424 // "SHOULD BE" ONE (gdb) print bcd 4424 // "SHOULD BE" ONE (gdb) backtrace #0 0x080487f8 in diagnols (PARAMETER_ONE=0, PARAMETER_TWO=0) at eq1.c:77 #1 0x08048873 in check (param1=0, param2=0) at eq1.c:91 #2 0x08048510 in recur (DEPTH=0, WIDTH=0) at eq1.c:99 #3 0x08048919 in main () at eq1.c:152 (gdb) Then here is diagnols(...), which is in: int recur(struct chessboard* key, int DEPTH, int WIDTH) { /* other functions above diagnols(...) */ diagnols(...): int diagnols(int PARAMETER_ONE, int PARAMETER_TWO) { // returns 0 if good int abc = 0; int bcd = 0; int counter = 0; // keeps track of conflicting piece occurrences // OTHER CHECKS FIRST... DELETED TO SAVE ROOM // checkign diagnol down and to the left abc = PARAMETER_ONE+1; bcd = PARAMETER_TWO-1; while ( (abc>=0)&&(bcd>=0) ) { if (key->board[abc][bcd] == 1) { counter++; } abc++; bcd--; } // ERROR IN THIS PART // checking diagnol down and to the right abc = PARAMETER_ONE+1; bcd = PARAMETER_TWO+1; while ( (abc>=0)&&(bcd>=0) ) { if (key->board[abc][bcd] == 1) { // ERROR counter++; } abc++; bcd++; } return counter; } And diagnols(...) is invoked in recur(...) in the below function: int check(int param1, int param2) { // if okay returns 2 // other functions d = diagnols(param1, param2); int total = 0; total = (h + v + d); // if okay, equals 2 return total; } For good measure here is my struct: struct chessboard { int board[7][7]; }; And main: int main() { struct chessboard* master = malloc(sizeof(struct chessboard)); /* i set the board to zero here. used calloc() before */ recur(master, 0, 0); // stuff } And yes, I realize diagnol isn't spelled diagonal ;)
while ( (abc>=0)&&(bcd>=0) ) { if (key->board[abc][bcd] == 1) { // ERROR counter++; } abc++; bcd++; } It seems that the condition is going to always be true since you are increasing both indexes. Did you mean < some limit instead?
problems with old c code with new ncurses version (ldat struct)
I have a problem with some code using curses after upgrading to a new server and thus also new software like libs, headers and such. The problem is the use of the ldat struct fields "firstchar", "lastchar" and "text" which in the the newer versions of curses.h is hidden in the curses.priv.h and therefore they are not resolved. I could really use some pointers as to how I might be able to resolve these issues. The code below indicates the use of the struct fields, but it just a part of the complete code as it several thousand lines... If there is need for additional code I can add this. I might also add that I have not made this program myself, I'm just responsible for making it work with our new server... int update_window(changed, dw, sw, win_shared) bool *changed; WINDOW *dw; /* Destination window */ window_t *sw; /* Source window */ bool win_shared; { int y, x; int yind, nx, first, last; chtype *pd, *ps; /* pd = pointer destination, ps = pointer source */ int nscrolls; /* Number of scrolls to make */ if(! sw->changed) { *changed = FALSE; return(0); } /**************************************** * Determine number of times window is * scrolled since last update ****************************************/ nscrolls = sw->scrollcount; if(nscrolls >= sw->ny) nscrolls = 0; sw->scrollcount = 0L; dw->_flags = _HASMOVED; dw->_cury = sw->cury; dw->_curx = sw->curx; if(nscrolls > 0) { /* Don't copy lines that is scolled away */ for(y = nscrolls; y < sw->ny; y++) { yind = GETYIND(y - nscrolls, sw->toprow, sw->ny); if(sw->lastch[yind] != _NOCHANGE) { first = dw->_line[y].firstchar = sw->firstch[yind]; last = dw->_line[y].lastchar = sw->lastch[yind]; ps = &sw->screen[yind][first]; pd = (chtype *)&dw->_line[y].text[first]; nx = last - first + 1; LOOPDN(x, nx) d++ = *ps++; if(! win_shared) { sw->firstch[yind] = sw->nx; sw->lastch[yind] = _NOCHANGE; } } } } else { LOOPUP(y, sw->ny) { yind = GETYIND(y, sw->toprow, sw->ny); if(sw->lastch[yind] != _NOCHANGE) { first = dw->_line[y].firstchar = sw->firstch[yind]; last = dw->_line[y].lastchar = sw->lastch[yind]; ps = &sw->screen[yind][first]; pd = (chtype *)&dw->_line[y].text[first]; nx = last - first + 1; LOOPDN(x, nx) *pd++ = *ps++; if(! win_shared) { sw->firstch[yind] = sw->nx; sw->lastch[yind] = _NOCHANGE; } } } if(! win_shared) sw->changed = FALSE; } *changed = TRUE; return(nscrolls); } I appreciate all the help I can get!
The members of struct ldat were made private in June 2001. Reading the function and its mention of scrolls hints that it is writing a portion of some window used to imitate scrolling (by writing a set of lines to the real window), and attempting to bypass the ncurses logic which checks for changed lines. For a function like that, the only solution is to determine what the developer was trying to do, and write a new function which does this — using the library functions provided.
ncurses program crashes on anything other than PuTTY
I have an older ncurses-based program that does some simple IO on a few files (i.e.: setup program). However, from a terminal different from PuTTY, it crashes with SIGBUS Program received signal SIGBUS, Bus error. 0x00000000004028b1 in fDisplay (ptr=Variable "ptr" is not available. ) at file_cpy.c:676 676 sprintf(p, " %-36s ", (*ptr)->datainfo.option); (gdb) where #0 0x00000000004028b1 in fDisplay (ptr=Variable "ptr" is not available. ) at file_cpy.c:676 #1 0x0000000000402cdb in fredraw (c=0x7fffffffe860) at file_cpy.c:696 #2 0x0000000000401996 in ls_dispatch (c=0x2020202020202020) at ds_cell.c:324 #3 0x0000000000403bf2 in main_dir (c=0x2020202020202020) at file_cpy.c:811 #4 0x0000000000403cb3 in main () at file_cpy.c:1345 (gdb) x/i $pc 0x4028b1 <fDisplay+17>: mov (%rax),%rdx (gdb) This happens on Linux and FreeBSD, regardless of ncurses version and 32/64bit architecture. I'm completely stumped. fDisplay() is called here: /* * File redraw routine. Draws current list on screen. */ int fredraw (CELL * c) { register int row = c->srow; dlistptr p = c->list_start; int i = 0; char buff[200]; if (c->ecol - c->scol) sprintf(buff, "%*s",c->ecol - c->scol + 1, " "); while (i <= c->erow - c->srow && p != NULL) { if (p == c->current) wattron(c->window,A_REVERSE); mvaddstr (row , c->scol, fDisplay(&p)); if (p == c->current) wattroff(c->window,A_REVERSE); row++; i++; p = p->nextlistptr; } if (row <= c -> erow) for (; row <= c -> erow ; row++) mvaddstr(row, c->scol, buff); wrefresh(c->window); c -> redraw = FALSE; return TRUE; } fredraw() is called here: int main_dir(CELL *c) { int i; getcwd(current_path, sizeof(current_path)); strcat(current_path, "/.config.h"); load_file(current_path); c->keytable = file_cpy_menu; c->func_table = file_cpy_table; c->ListEntryProc = File_Entry; c->UpdateStatusProc = status_update; c->redraw = TRUE; c->ListExitProc = List_Exit; c->ListPaintProc = fredraw; c->srow = 3; c->scol = 1; c->erow = c->window->_maxy - 5; c->ecol = c->window->_maxx - 1; c->max_rows = c->window->_maxy; c->max_cols = c->window->_maxx; c->filename = "[ Config ]"; c->menu_bar = 0; c->normcolor = 0x07; c->barcolor = 0x1f; init_dlist(c); for (i = 0; config_type[i].option; i++) insert_fdlist(c, &config_type[i]); /* * Go Do It */ do { c->redraw = TRUE; ls_dispatch(c); } while (c->termkey != ESC && c->termkey != ALT_X); return TRUE; } Finally, main() calls the above functions: int main() { CELL file_cpy = {0}; WINDOW *mainwin; mainwin = initscr(); start_color(); setup_colors(); cbreak(); noecho(); keypad(mainwin, TRUE); meta(mainwin, TRUE); raw(); leaveok(mainwin, TRUE); wbkgd(mainwin, COLOR_PAIR(COLOR_MAIN)); wattron(mainwin, COLOR_PAIR(COLOR_MAIN)); werase(mainwin); refresh(); file_cpy.window = mainwin; main_dir(&file_cpy); wbkgd(mainwin, A_NORMAL); werase(mainwin); echo(); nocbreak(); noraw(); refresh(); endwin(); return TRUE; }
Apparently you are calling main_dir and ls_dispatch with a pointer c initialized to 0x2020202020202020. While not completely impossible, I find it very unlikely, and it looks to me as if you're overwriting the pointer with spaces. valgrind would probably help, or some kind of memory or stack protection check. Why this depends on the terminal, I could not say; possibly there's some TERM-depending code (such as "allocate as many rows as there are on screen"). Anyway, that is not the bug: it's only the condition bringing the bug in the open. This kind of error is usually caused by a hard-wired constant which sometimes is exceeded by the real value (in the example above I could say "allocate 96 rows", assuming that 96 rows will always be enough for everyone; whereas a TERM with 100 rows would foil the assumption and lead to a buffer overrun). It might also be an artifact of the debugger, seeing as how c is allocated on the stack (but I don't think so: it should be c=0x7fffsomething - at least on the systems where I checked) . Anyway, I'd repeat the test like this, by making file_cpy heap dynamic: int main() { CELL *file_cpy = NULL; WINDOW *mainwin; file_cpy = malloc(sizeof(CELL)); ... file_cpy->window = mainwin; main_dir(file_cpy); ... free(file_cpy); // file_cpy = NULL; // we immediately return return TRUE; and then I'd try and tabulate the pointer's value throughout the main_dir function, in case it's overwritten.