XCreateColormap调用触发段错误,请求故障排查与修复
问题描述
运行代码时触发段错误,调试显示错误发生在_XcmsAddCmapRec()函数(来自libX11.so.6)。已花费约3小时排查仍无进展,相关代码及调试信息如下:
关键代码片段
temp->wA.border_pixel = BlackPixel(temp->d, temp->sID); temp->wA.background_pixel = WhitePixel(temp->d, temp->sID); temp->wA.override_redirect = true; temp->wA.colormap = XCreateColormap(temp->d, RootWindow(temp->d, temp->sID), temp->vI->visual, AllocNone); temp->wA.event_mask = ExposureMask;
完整createWindow函数
window *createWindow(int height, int width, const char *name) { window *temp = (window *)malloc(sizeof(window)); temp->d = XOpenDisplay(NULL); temp->s = DefaultScreenOfDisplay(temp->d); temp->sID = DefaultScreen(temp->d); int tempattribs[] = { GLX_RGBA, GLX_DOUBLEBUFFER, GLX_DEPTH_SIZE, 24, GLX_STENCIL_SIZE, 8, GLX_RED_SIZE, 8, GLX_GREEN_SIZE, 8, GLX_BLUE_SIZE, 8, GLX_SAMPLE_BUFFERS, 0, GLX_SAMPLES, 0, None}; memcpy(temp->attribs, tempattribs, sizeof(tempattribs)); temp->vI = glXChooseVisual(temp->d, temp->sID, temp->attribs); if (temp->vI == NULL) { perror("ERROR: GLXCHOOSEVISUAL FAILED!\n"); return NULL; } temp->wA.border_pixel = BlackPixel(temp->d, temp->sID); temp->wA.background_pixel = WhitePixel(temp->d, temp->sID); temp->wA.override_redirect = true; temp->wA.colormap = XCreateColormap(temp->d, RootWindow(temp->d, temp->sID), temp->vI->visual, AllocNone); temp->wA.event_mask = ExposureMask; temp->w = XCreateWindow(temp->d, RootWindow(temp->d, temp->sID), 0, 0, height, width, 0, temp->vI->depth, InputOutput, temp->vI->visual, CWBackPixel | CWColormap | CWBorderPixel | CWEventMask, &temp->wA); temp->c = glXCreateContext(temp->d, temp->vI, NULL, 1); glXMakeCurrent(temp->d, temp->w, temp->c); return temp; }
window结构体定义
typedef struct window { Window w; Display *d; Screen *s; XEvent e; int sID; bool running; XVisualInfo *vI; GLXContext c; XSetWindowAttributes wA; int attribs[]; } window;
调试结果
Thread 1 "main" received signal SIGSEGV, Segmentation fault. 0x0000007ff7e10754 in _XcmsAddCmapRec () from /lib/aarch64-linux-gnu/libX11.so.6
错误原因分析
- 柔性数组未正确分配内存:
window结构体中的int attribs[]是柔性数组成员,使用malloc(sizeof(window))仅分配了结构体本身的内存,未为attribs数组预留空间。后续memcpy操作会写入未分配的内存区域,破坏堆结构,最终导致X11函数调用时触发段错误。 - 未检查
XOpenDisplay返回值:如果XOpenDisplay(NULL)失败返回NULL,后续所有访问temp->d的操作都会触发未定义行为,可能间接引发段错误。 - 窗口属性掩码不匹配:设置了
temp->wA.override_redirect = true,但XCreateWindow的属性掩码中未包含CWOverrideRedirect,会导致该属性被忽略,属于逻辑错误。
修复方案
针对上述问题,修改后的代码如下:
完整修正后的createWindow函数
window *createWindow(int height, int width, const char *name) { int tempattribs[] = { GLX_RGBA, GLX_DOUBLEBUFFER, GLX_DEPTH_SIZE, 24, GLX_STENCIL_SIZE, 8, GLX_RED_SIZE, 8, GLX_GREEN_SIZE, 8, GLX_BLUE_SIZE, 8, GLX_SAMPLE_BUFFERS, 0, GLX_SAMPLES, 0, None}; // 分配包含柔性数组的总内存:结构体大小 + 属性数组大小 size_t total_size = sizeof(window) + sizeof(tempattribs); window *temp = (window *)malloc(total_size); if (temp == NULL) { perror("malloc failed"); return NULL; } // 检查XOpenDisplay返回值 temp->d = XOpenDisplay(NULL); if (temp->d == NULL) { perror("XOpenDisplay failed"); free(temp); return NULL; } temp->s = DefaultScreenOfDisplay(temp->d); temp->sID = DefaultScreen(temp->d); memcpy(temp->attribs, tempattribs, sizeof(tempattribs)); temp->vI = glXChooseVisual(temp->d, temp->sID, temp->attribs); if (temp->vI == NULL) { perror("ERROR: GLXCHOOSEVISUAL FAILED!\n"); XCloseDisplay(temp->d); free(temp); return NULL; } temp->wA.border_pixel = BlackPixel(temp->d, temp->sID); temp->wA.background_pixel = WhitePixel(temp->d, temp->sID); temp->wA.override_redirect = true; temp->wA.colormap = XCreateColormap(temp->d, RootWindow(temp->d, temp->sID), temp->vI->visual, AllocNone); temp->wA.event_mask = ExposureMask; // 修正属性掩码,加入CWOverrideRedirect使override_redirect生效 temp->w = XCreateWindow(temp->d, RootWindow(temp->d, temp->sID), 0, 0, height, width, 0, temp->vI->depth, InputOutput, temp->vI->visual, CWBackPixel | CWColormap | CWBorderPixel | CWEventMask | CWOverrideRedirect, &temp->wA); temp->c = glXCreateContext(temp->d, temp->vI, NULL, 1); glXMakeCurrent(temp->d, temp->w, temp->c); return temp; }
内容的提问来源于stack exchange,提问作者Gu-Goomba
相关产品推荐
相关产品推荐

