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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 11:40:37