【问题标题】:ncurses program crashes on anything other than PuTTYncurses 程序在 PuTTY 以外的任何东西上崩溃
【发布时间】:2012-10-11 01:23:14
【问题描述】:

我有一个较旧的基于 ncurses 的程序,它对一些文件(即:安装程序)执行一些简单的 IO。但是,从不同于 PuTTY 的终端,它会因 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)

这发生在 Linux 和 FreeBSD 上,与 ncurses 版本和 32/64 位架构无关。我完全被难住了。

fDisplay() 在这里被调用:

/*
 * 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() 在这里被调用:

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;
}

最后main()调用了上面的函数:

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;
}

【问题讨论】:

  • PuTTY 将$TERM 设置为什么?如果在非 PuTTY 环境中将 $TERM 更改为该值会怎样?那么终端尺寸呢?
  • 很抱歉听到您的问题。我记得我曾经不得不使用 C 和 ncurses 编写一个游戏板程序,但他们明确告诉我们只能使用 Putty 作为我们的 shell,而不是任何其他类型的 shell 程序。
  • Kevin,$TERM 被 putty 和我的其他应用程序设置为 xterm。这可能是 ncurses 的问题吗?
  • 这似乎并不特定于我的客户模拟器以外的任何东西。 PuTTY 工作正常。
  • 如果您不粘贴更多代码,我怀疑我们是否真的能够帮助您。特别是ptr从哪里来?

标签: c ncurses


【解决方案1】:

显然,您正在调用 main_dirls_dispatch,并将指针 c 初始化为 0x2020202020202020。虽然并非完全不可能,但我认为这不太可能,而且在我看来,您好像在用空格覆盖指针。

valgrind 可能会有所帮助,或者某种内存或堆栈保护检查。

为什么这取决于终端,我不能说;可能有一些依赖于 TERM 的代码(例如“分配与屏幕上一样多的行”)。无论如何,这不是错误:它只是将错误公开的条件。这种错误通常是由硬连线常量引起的,有时实际值会超过该常量(在上面的示例中,我可以说“分配 96 行”,假设 96 行对每个人来说总是足够的 em>;而 100 行的 TERM 会破坏假设并导致缓冲区溢出)。

它也可能是调试器的产物,看看c 是如何在堆栈上分配的(但我不这么认为:它应该是c=0x7fffsomething - 至少在我检查过的系统上)。无论如何,我会重复这样的测试,通过使file_cpy 堆动态:

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;

然后我会尝试将指针的值列在整个main_dir 函数中,以防它被覆盖。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-04-24
    • 2010-10-10
    • 2020-12-08
    • 2017-02-22
    • 2021-02-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多