如何解决xcb_image_get引发的核心转储问题?
读取屏幕像素触发Segmentation Fault(Core Dump)问题
尝试通过XCB读取屏幕像素实现录屏功能时,触发了Segmentation Fault(core dump)错误。已确认XCB基础窗口创建功能正常,但调用xcb_image_get后访问返回的xcb_image_t结构体时崩溃,尝试过使用根窗口和自定义窗口作为参数,问题依旧。
编译命令
gcc -o test test.c -I"/usr/local/include/libdrm" -ldrm -lxcb -lxcb-image
注:libdrm为后续功能所需,此处列出供排查参考。
测试代码
// DRM // 参考DRM文档示例 #include <xf86drm.h> #include <xf86drmMode.h> // XCB #include <xcb/xcb.h> #include <xcb/xcb_image.h> // 通用头文件 #include <drm_fourcc.h> #include <fcntl.h> #include <inttypes.h> #include <stdbool.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/mman.h> #include <time.h> #include <unistd.h> #include <stdint.h> int main(void){ /* 连接X服务器 */ xcb_connection_t *c = xcb_connect (NULL, NULL); printf("%d", xcb_connection_has_error(c)); // 返回0,连接正常 /* 获取第一个屏幕 */ const xcb_setup_t *setup = xcb_get_setup (c); printf("%d", setup->status); // 返回1 xcb_screen_iterator_t iter = xcb_setup_roots_iterator (setup); xcb_screen_t *screen = iter.data; printf("%d", screen->root == NULL); // 返回0,屏幕对象有效 /* 创建测试窗口 */ xcb_window_t window = xcb_generate_id (c); xcb_void_cookie_t create_cookie = xcb_create_window (c, /* 连接句柄 */ XCB_COPY_FROM_PARENT, /* 深度(与根窗口一致)*/ window, /* 窗口ID */ screen->root, /* 父窗口 */ 0, 0, /* 坐标x, y */ 150, 150, /* 宽高 */ 10, /* 边框宽度 */ XCB_WINDOW_CLASS_INPUT_OUTPUT, /* 窗口类型 */ screen->root_visual, /* 视觉格式 */ 0, NULL ); /* 属性掩码,暂未使用 */ // 检查窗口创建错误 xcb_generic_error_t *error = xcb_request_check(c, create_cookie); if (error) { printf("窗口创建失败\n"); free(error); } /* 映射窗口到屏幕 */ xcb_map_window (c, window); /* 确保命令发送到服务器 */ xcb_flush (c); // 获取窗口几何信息 xcb_get_geometry_cookie_t geomCookie = xcb_get_geometry (c, window); xcb_get_geometry_reply_t *geom = xcb_get_geometry_reply (c, geomCookie, NULL); if (!geom) { printf("获取窗口几何信息失败\n"); xcb_disconnect(c); return 1; } int _x = geom->x; int _y = geom->y; int _width = geom->width; int _height = geom->height; printf("\n %d %d %d %d\n", _x, _y, _width, _height); // 返回0 0 150 150 // 创建测试Pixmap xcb_pixmap_t pix = xcb_generate_id (c); xcb_void_cookie_t pixcook = xcb_create_pixmap (c, geom->depth, /* 屏幕深度 */ pix, /* Pixmap ID */ window, _width, /* 宽度 */ _height ); /* 高度 */ // 获取屏幕图像 // 0xffffffff 表示所有位平面 xcb_image_t* ximg = xcb_image_get(c, screen->root, 0, 0, screen->width_in_pixels, screen->height_in_pixels, 0xffffffff, XCB_IMAGE_FORMAT_Z_PIXMAP); // 关键:先检查ximg是否为NULL if (!ximg) { printf("xcb_image_get 调用失败\n"); free(geom); xcb_disconnect(c); return 1; } printf("%d\n", ximg->width); uint32_t pixel = xcb_image_get_pixel(ximg, 0, 0); printf("像素值:%u\n", pixel); xcb_image_destroy(ximg); free(geom); pause (); /* 等待Ctrl-C退出 */ xcb_disconnect (c); return 0; }
补充信息
- 运行环境:最新版Ubuntu,Wayland显示服务器
- 混淆过
xcb_image_get和xcb_get_image,找不到xcb_image_get和xcb_image_get_pixel的详细文档 - 了解Cairo可能是更便捷的方案,但希望学习XCB原生用法
问题分析与修复建议
直接崩溃原因:未检查
xcb_image_get返回值xcb_image_get在调用失败时会返回NULL,直接访问ximg->width会触发段错误。必须先判断返回值是否为NULL,再进行后续操作。Wayland环境的兼容性问题
在Wayland下,XCB是通过XWayland兼容层运行的,无法直接捕获Wayland的全局屏幕内容。XWayland的根窗口仅对应X兼容应用的区域,而非整个屏幕。如果要捕获Wayland屏幕,建议使用Wayland原生API或工具库;如果坚持用XCB,需确保目标窗口是XWayland管理的窗口。代码中的其他问题修复
- 原代码中
xcb_request_check(c, cook)里的cook未定义,已修改为对应窗口创建的create_cookie - 添加了
xcb_get_geometry_reply的返回值NULL判断 - 补充了
xcb_get_geometry_reply的内存释放操作
- 原代码中
内容的提问来源于stack exchange,提问作者Loki
相关产品推荐
相关产品推荐

