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_dirandls_dispatchwith a pointercinitialized to0x2020202020202020. While not completely impossible, I find it very unlikely, and it looks to me as if you’re overwriting the pointer with spaces.valgrindwould 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
cis allocated on the stack (but I don’t think so: it should bec=0x7fffsomething– at least on the systems where I checked) . Anyway, I’d repeat the test like this, by makingfile_cpyheap dynamic:and then I’d try and tabulate the pointer’s value throughout the
main_dirfunction, in case it’s overwritten.