Deleting a window's WM_CLASS emits set_class with class==NULL while the title is set; handle_xs_set_class passed the raw NULLs into wlr_foreign_toplevel_handle_v1_set_app_id / ext update_state, which strdup(NULL) -> SIGSEGV (exit 139; UBSan flags the nonnull argument first). The sibling set_title handler and every other mirror site use foreign_str(); apply the same guard here. Add tests/xclass.c (title set, WM_CLASS set-then-deleted probe) and a headless smoke test asserting the compositor survives the delete with no crash indicators (fails pre-fix: compositor dead).
53 lines
1.8 KiB
C
53 lines
1.8 KiB
C
/* xclass: WM_CLASS set-then-delete probe.
|
|
*
|
|
* Maps a titled X11 window with NO class, then sets WM_CLASS, then deletes
|
|
* it: the delete emits set_class with class==NULL while the title is set.
|
|
* The compositor must mirror "" (not raw NULL) onto the taskbar handles --
|
|
* passing NULL into the foreign-toplevel set_app_id/update_state calls
|
|
* segfaults inside wlroots' strdup (regression test for that crash).
|
|
*
|
|
* usage: xclass <hold-seconds> (total runtime ~= 4 + max(hold-4, 0))
|
|
*/
|
|
#define _POSIX_C_SOURCE 200809L
|
|
#include <X11/Xlib.h>
|
|
#include <X11/Xatom.h>
|
|
#include <X11/Xutil.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
|
|
int main(int argc, char **argv) {
|
|
int hold = argc > 1 ? atoi(argv[1]) : 6;
|
|
Display *d = XOpenDisplay(NULL);
|
|
if (!d) {
|
|
fprintf(stderr, "xclass: cannot open display\n");
|
|
return 1;
|
|
}
|
|
int scr = DefaultScreen(d);
|
|
Window w = XCreateSimpleWindow(d, RootWindow(d, scr), 0, 0, 400, 300, 0,
|
|
BlackPixel(d, scr), 0x804020UL);
|
|
XStoreName(d, w, "xclass-frame");
|
|
pid_t pid = getpid();
|
|
Atom apid = XInternAtom(d, "_NET_WM_PID", False);
|
|
XChangeProperty(d, w, apid, XA_CARDINAL, 32, PropModeReplace,
|
|
(unsigned char *)&pid, 1);
|
|
/* NOTE: no WM_CLASS yet (class == NULL server-side). */
|
|
XMapWindow(d, w);
|
|
XFlush(d);
|
|
fprintf(stderr, "[xclass] mapped, no class\n");
|
|
sleep(2);
|
|
XClassHint *ch = XAllocClassHint();
|
|
ch->res_name = "xclass-probe";
|
|
ch->res_class = "XClassProbe";
|
|
XSetClassHint(d, w, ch);
|
|
XFree(ch);
|
|
XFlush(d);
|
|
fprintf(stderr, "[xclass] class set\n");
|
|
sleep(2);
|
|
Atom wmclass = XInternAtom(d, "WM_CLASS", False);
|
|
XDeleteProperty(d, w, wmclass);
|
|
XFlush(d);
|
|
fprintf(stderr, "[xclass] class deleted (NULL)\n");
|
|
sleep(hold > 4 ? (unsigned)(hold - 4) : 0);
|
|
return 0;
|
|
}
|