使用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
修复建议
检查窗口指针有效性:
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)导致指针失效。
全局变量风险管控:
User_security_window为全局变量,需确保无其他线程或函数在process_user_security()运行时修改/释放该指针;多线程场景需加锁保护。
ncurses环境初始化:
- 确认程序入口已调用
initscr()初始化ncurses,退出时调用endwin()清理环境,缺失初始化会触发未定义行为。
- 确认程序入口已调用
编译命令优化:
- 移除重复的
-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
- 移除重复的
未定义变量修复:
process_user_security()中使用的digitcounter、field_counter等变量未声明,需补充全局或局部声明,避免未定义行为。
调试验证指针状态:
- 段错误触发后,在gdb中打印指针值确认是否失效:
若为NULL或无效地址,需追踪指针被修改的位置。(gdb) p User_security_window
- 段错误触发后,在gdb中打印指针值确认是否失效:
内容的提问来源于stack exchange,提问作者Mahesh Babu Tatineni
相关产品推荐
相关产品推荐

