【问题标题】:Weird segmentation fault inside of XPutImage in XlibXlib 中的 XPutImage 内部出现奇怪的分段错误
【发布时间】:2026-01-24 07:35:01
【问题描述】:

我正在制作一个显示任务栏的程序,其中包含来自打开窗口的图标。我做了一个函数,它需要两个指针和一些额外的辅助数据。 icon_Data 和icon_Data_Ptr 这两个指针分别指向原子_NET_WM_ICON 返回的数据和我要使用的具体图标。下面是函数:

static Pixmap create_Pixmap_From_Icon_Data(Taskbar * taskbar, Taskbar_Item * taskbar_Item, uint32_t * icon_Data_Ptr, uint32_t * icon_Data) {
    Pixmap icon_Pixmap = XCreatePixmap(taskbar->display, taskbar->parent, (unsigned int) icon_Data_Ptr[0], (unsigned int) icon_Data_Ptr[1], 32);

    XImage * x_Image = XCreateImage(taskbar->display, taskbar->visual, 32, ZPixmap, 2, (char *) &icon_Data_Ptr, (unsigned int) icon_Data_Ptr[0], (unsigned int) icon_Data_Ptr[1], 32, 0);

    GC temp_GC = XCreateGC(taskbar->display, icon_Pixmap, 0, 0);

    XPutImage(taskbar->display, icon_Pixmap, temp_GC, x_Image, 0, 0, 0, 0, icon_Data_Ptr[0], icon_Data_Ptr[1]);
    x_Image->data = (char *) icon_Data;

    XDestroyImage(x_Image);
    XFreeGC(taskbar->display, temp_GC);

    return icon_Pixmap;
}

每当我尝试运行程序时,它大约有一半的时间会出现段错误。 Gdb 的堆栈跟踪如下:

#0 __memmove_sse2_unaligned_erms ()
    在 ../sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S:262
#1 0x00007ffff7c9f6b0 in memcpy (__len=,
    __src=0x7fffffffdd48, __dest=)
    在 /usr/include/x86_64-linux-gnu/bits/string_fortified.h:34
#2 SendZImage (dest_scanline_pad=,
    dest_bits_per_pixel=32,req_yoffset=0,
    req_xoffset=, image=0x459dd0,
    req=, dpy=0x4062a0)
    在 ../../src/PutImage.c:795
#3 PutImageRequest (gc=,
    dest_scanline_pad=, dest_bits_per_pixel=32,
    req_height=, req_width=,
    y=, x=, req_yoffset=0,
    req_xoffset=, image=0x459dd0,
    d=, dpy=0x4062a0) 在 ../../src/PutImage.c:861
#4 PutSubImage (dpy=0x4062a0, d=,
    gc=, image=0x459dd0,
    req_xoffset=, req_yoffset=,
    x=0, y=0, req_width=48, req_height=48,
    dest_bits_per_pixel=32, dest_scanline_pad=32)
    在 ../../src/PutImage.c:899
#5 0x00007ffff7c9faae 在 XPutImage (dpy=0x4062a0, d=23068677,
    gc=0x459e60,图像=0x459dd0,req_xoffset=0,req_yoffset=0,
    x=0, y=0, req_width=48, req_height=48)
    在../../src/PutImage.c:1018
#6 0x00000000004022bc 在 create_Pixmap_From_Icon_Data (
    任务栏=0x4088e0,任务栏_项目=0x413760,
    icon_Data_Ptr=0x4579b8, icon_Data=0x413890) 在 taskbar.c:206
#7 0x0000000000402032 在 find_And_Set_Pixmap_From_Property_Data
    (任务栏=0x4088e0,任务栏_项目=0x413760,
    icon_Data=0x413890, item_Count=72012) 在 taskbar.c:231
#8 0x0000000000401c48 在 set_Taskbar_Item_Icon_Pixmap (
    任务栏=0x4088e0,任务栏_项目=0x413760,实例=0x408860)
    在 taskbar.c:256
#9 0x000000000040196c 在 add_Instance_To_New_Taskbar_Item (
    任务栏=0x4088e0,实例=0x408860)在taskbar.c:315
#10 0x000000000040170e 在 add_Window_If_Necessary (
--键入  获取更多信息,q 退出,c 继续不分页--
    任务栏=0x4088e0,窗口=18876630)在taskbar.c:386
#11 0x0000000000402ae5 in iterate_Through_All_Windows (
    任务栏=0x4088e0,显示=0x4062a0,屏幕=0,
    iterator_Callback=0x401690 )
    在 taskbar_Test.c:31
#12 0x0000000000402997 在 setup_Taskbar (taskbar=0x7fffffffdfb8,
    显示=0x4062a0,屏幕=0,父=23068674,
    视觉= 0x408430,颜色图= 23068673)在taskbar_Test.c:42
#13 0x00000000004027bf in main () at taskbar_Test.c:72

在我调试它的其他时间,我已经检查以确保 icon_Data_Ptr 有足够的数据让 XCreatePixmap 运行,确实如此。然而,奇怪的是,我发现当 Gdb 进入 XCreatePixmap 时,指向函数内部数据的指针与函数外部的地址不同。此外,在使用 GDB 时,我发现当我在 XCreateImage 内部时,图像的数据指针不包含足够的数据以使函数工作。我还在 XCreateImage 的函数调用和 XCreateImage 的函数调用内部转储了指向图像数据的内存。我使用 Gimp 导入了这些数据。该图像在函数外部看起来像 chrome 浏览器图标,但在函数内部它看起来像是有序和随机颜色的混合,与 chrome 图标不同。

除了使用 Gdb 之外,我还尝试使用 Clang 代替 GCC 来查看这是否是编译器错误;它产生了同样的错误。

我不知道我做错了什么导致了这个分段错误,任何帮助都将不胜感激。

【问题讨论】:

  • 调用Xlib的函数后,应该检查返回值。如果这些返回值是指针,请检查它们是否不为空,然后继续。您似乎没有检查XCreateImageXCreatePixmapXCreateGC 的结果。
  • 此外,许多函数参数在 GDB 堆栈跟踪中显示为 optimized。你是在 Release 模式下编译吗?请在调试模式下使用-g3 编译器选项编译您的程序。这样,optimized 的实际值就会显示出来(我希望如此)。
  • 刚才,我使用 Gdb 运行我的程序,并打印了 XCreateImage、XCreatePixmap 和 XCreateGC 的输出;他们都给出了有效的值,但仍然崩溃。另外,我的程序没有优化并且设置了最大调试设置,只是优化了 libX11 和 libc。但是,我已经为这两个库安装了 dbgsym 包。
  • 由于问题在memcpy中显示,请检查您是否传递了任何与尺寸相关的参数以及该参数是否正确。尝试访问非法内存时似乎程序崩溃了,这通常发生在尝试越界访问内存时。

标签: c segmentation-fault gdb x11 xlib


【解决方案1】:

我使用 GDB 单步执行机器代码,并在函数调用 XCreateImage:lea -0x38(%rbp),%rdi 之前看到了这一点。这会将位于红色区域中的局部变量的地址加载到 rdi 寄存器中,该寄存器稍后会根据 Amd64 的 System V ABI (https://uclibc.org/docs/psABI-x86_64.pdf) 移动到 r9 寄存器中作为第 6 个参数。所以这意味着我没有传递icon_Data_Ptr 的指针值,而是传递了存储指针的地址:(char *) &icon_Data_Ptr。这会导致将错误的 XImage 结构传递给 XPutImage,从而导致分段错误。

【讨论】: