You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用ncurses触发段错误,添加-fsanitize编译则正常求修复

ncurses调用wgetch时触发段错误的排查与修复建议

更新

调用ncurses函数时遇到段错误,gdb栈回溯信息如下:

程序收到信号SIGSEGV,段错误。
                                                                                                         
 0x00007ffff3a77f28 in wnoutrefresh () from /lib64/libncurses.so.6

(gdb) bt
#0  0x00007ffff3a77f28 in wnoutrefresh () from /lib64/libncurses.so.6
#1  0x00007ffff3a77feb in wrefresh () from /lib64/libncurses.so.6
#2  0x00007ffff3a7168a in _nc_wgetch () from /lib64/libncurses.so.6
#3  0x00007ffff3a7241b in wgetch () from /lib64/libncurses.so.6
#4  0x0000000000450e85 in process_user_security () at caomenu.pc:12948
#5  0x00000000004501e5 in display_user_security () at caomenu.pc:12780
#6  0x0000000000403932 in menu1 () at caomenu.pc:993
#7  0x00000000004018ca in main (ac=2, av=0x7fffffffe208) at caomenu.pc:562
(gdb)

段错误发生在process_user_security()函数的第12948行:

selection=wgetch(User_security_window);

怀疑是环境问题或未定义行为导致,以下是相关代码:

触发段错误的process_user_security函数

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include </usr/include/sys/stat.h>
#include <unistd.h>
#include <memory.h>
#include <ctype.h>
#include <curses.h>

WINDOW *User_security_window;

/*************************************************************************** */
/** 函数:process_user_security()                                  **/
/** 用途:处理用户菜单输入并显示相关内容             **/
/* ************************************************************************** */
void process_user_security(void) {
    int selection = 0;
    int i,z;
    int digitflag =FALSE;
    int number_in_group=0;
    int scrline_holder;
    int exitflag=FALSE;

    /* TDT,II - 2006年5月2日 - 添加一级调试 */
    if ( iDebug >= 1 )
            WriteTrace( "Running process_user_security" );

    digitcounter = 0;
    field_counter=0;
    for ( ; ; ) {
          selection=wgetch(User_security_window); // 触发段错误(行号12948)

        selection=toupper(selection);

        if ( selection== F8_KEY||selection==KEY_F(8) ) {
            EXEC SQL
            DELETE  CAO.SCRTY_USR_ASGN
            WHERE    USER_ID = :orUserSecurityInfo[usersecurityline].old_user_id;

            EXEC SQL
            COMMIT;

            load_user_data();

            disply_down_user_security(0);
            column_holder = 0;
            user_column = 1;
            memset(new_group_value,  0, sizeof(new_group_value));
            selection = 0;
            usersecurityline=scrline=0;
        };

        if ( (selection== F6_KEY||selection==KEY_F(6))&&(user_column == 50) ) {
            scrline_holder = scrline;

            display_group_id();
            clearok( User_security_window, TRUE );
            mvwaddstr(User_security_window,scrline_holder+9,50,"          ");
// 函数后续代码省略

初始化窗口的display_user_security函数

/****************************************************************************/
/** 函数:display_user_security()                       **/
/** 用途:显示用户安全访问下拉列表        **/
/****************************************************************************/
void display_user_security(void) {

    int iCount,i,j=0,k;
    int key_pressed,avl_elm,good_key;
    varchar cUser_id[30];
    varchar cUser_name[30];
    varchar cUpdate_user_id[30];
    varchar cUser_password[30];
    varchar cGroup_id[30];

    int selection=0;
    int selection2=0;
    int item_counter;
    int digitflag =FALSE;
    int z,m,n;
    char    A[30],B[30];

/* TDT,II - 2006年5月2日 - 添加一级调试 */
    if ( iDebug >= 1 )
        WriteTrace( "Running display_user_security" );

    noecho();

    User_security_window = newwin(0,0,0,0);
    keypad( User_security_window, TRUE );
    clearok( User_security_window, TRUE );

    sprintf(menustr,"CAO USER SECURITY ACCESS");
    mvwaddstr(User_security_window,1,28,menustr);

    sprintf(menustr,"F6-Select Group Id");
    mvwaddstr(User_security_window,3,5,menustr);

    sprintf(menustr,"F7-Add User");
    mvwaddstr(User_security_window,3,30,menustr);

    sprintf(menustr,"F8-Delete User");
    mvwaddstr(User_security_window,3,60,menustr);

    wmove(User_security_window,9,1);
    wrefresh(User_security_window);

    sprintf(menustr,"F2-First");
    mvwaddstr(User_security_window,23,5,menustr);
    sprintf(menustr,"F3-Last");
    mvwaddstr(User_security_window,23,16,menustr);

    sprintf(menustr,"F4-Prev");
    mvwaddstr(User_security_window,23,26,menustr);
    sprintf(menustr,"F5-Next");
    mvwaddstr(User_security_window,23,36,menustr);
    sprintf(menustr,"ESC-Back");
    mvwaddstr(User_security_window,23,46,menustr);

    sprintf(menustr," User     Adminstrator   User       User        Group");
    mvwaddstr(User_security_window,7,2,menustr);
    sprintf(menustr," Id       Id             Name       Password    Id");
    mvwaddstr(User_security_window,8,2,menustr); 

    clearok( User_security_window, TRUE );
    wrefresh(User_security_window);

    load_user_data();

    disply_down_user_security(0);
    column_holder = 0;
    user_column = 1;
    memset(new_group_value,  0, sizeof(new_group_value));
    selection = 0;
    usersecurityline=scrline=0;
    process_user_security(); // 调用process_user_security()函数
    delwin(User_security_window);
}

编译命令

gcc -g -o scrmenu caomenu.c superbox.c -L/opt/oracle/product/19c/dbhome_1/lib -L/usr/include/ -lclntsh -lncurses -lcurses

修复建议

  1. 检查窗口指针有效性:

    • newwin(0,0,0,0)虽会创建全屏窗口,但需检查返回值是否为NULL,避免空指针操作:
      User_security_window = newwin(0,0,0,0);
      if (User_security_window == NULL) {
          perror("newwin failed");
          exit(EXIT_FAILURE);
      }
      
    • 排查process_user_security()执行期间,是否有其他代码(如display_group_id())意外调用delwin(User_security_window)导致指针失效。
  2. 全局变量风险管控:

    • User_security_window为全局变量,需确保无其他线程或函数在process_user_security()运行时修改/释放该指针;多线程场景需加锁保护。
  3. ncurses环境初始化:

    • 确认程序入口已调用initscr()初始化ncurses,退出时调用endwin()清理环境,缺失初始化会触发未定义行为。
  4. 编译命令优化:

    • 移除重复的-lcurses(ncurses是curses的升级版本,系统默认兼容),同时删除无效的-L/usr/include/(头文件路径用-I,/usr/include为默认搜索路径):
      gcc -g -o scrmenu caomenu.c superbox.c -L/opt/oracle/product/19c/dbhome_1/lib -lclntsh -lncurses
      
  5. 未定义变量修复:

    • process_user_security()中使用的digitcounter、field_counter等变量未声明,需补充全局或局部声明,避免未定义行为。
  6. 调试验证指针状态:

    • 段错误触发后,在gdb中打印指针值确认是否失效:
      (gdb) p User_security_window
      
      若为NULL或无效地址,需追踪指针被修改的位置。

内容的提问来源于stack exchange,提问作者Mahesh Babu Tatineni

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 09:40:28