I have an older ncurses-based program that does some simple IO on a few files (ie: 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.
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.