/* gcc -Wall -o damage-crash damage-crash.c `pkg-config --libs xdamage xfixes x11` */ #include #include #include /* * Exercise the path of creating a Damage on a drawable, destroying the * drawable, and then modifying the Damage. The spec is unpleasantly * silent on this, but the deployed behaviour is that Damages are magically * destroyed when the drawable they're bound to is destroyed. * * Test this against both window and pixmap drawables, for all damage * report types. We should get BadDamage around the XDamageSubtracts and * nothing else, and obviously the server should not crash. */ static int damage_error_base, damage_event_base; static int (*old_handler)(Display *, XErrorEvent *); static int fail; static int bad_damage(Display *dpy, XErrorEvent *err) { if (err->error_code != (damage_error_base + BadDamage)) { printf("unexpected error %d\n", err->error_code); fail = 1; } return 0; } typedef int (*destroy_t)(Display *, Drawable); static void test_drawable(Display *dpy, Drawable d, int report, destroy_t destroy) { Damage damage; XserverRegion region; XRectangle rect; damage = XDamageCreate(dpy, d, report); /* stuff some damage into it first */ rect.x = 0; rect.y = 0; rect.width = 50; rect.height = 50; region = XFixesCreateRegion(dpy, &rect, 1); XDamageAdd(dpy, d, region); destroy(dpy, d); rect.x = 0; rect.y = 0; rect.width = 50; rect.height = 25; region = XFixesCreateRegion(dpy, &rect, 1); old_handler = XSetErrorHandler(bad_damage); XDamageSubtract(dpy, damage, region, None); XSync(dpy, 0); XSetErrorHandler(old_handler); } int main(void) { Display *dpy; Pixmap pixmap; Window window; int ret = 0; int report; dpy = XOpenDisplay(NULL); XDamageQueryExtension(dpy, &damage_event_base, &damage_error_base); for (report = 0; report <= XDamageReportNonEmpty; report++) { pixmap = XCreatePixmap(dpy, DefaultRootWindow(dpy), 50, 50, 1); test_drawable(dpy, pixmap, report, (destroy_t)XFreePixmap); if (fail) { printf("failed pixmap for report type %d\n", report); ret = 1; fail = 0; } window = XCreateSimpleWindow(dpy, DefaultRootWindow(dpy), 0, 0, 50, 50, 0, 0, 0); test_drawable(dpy, window, report, (destroy_t)XDestroyWindow); if (fail) { printf("failed window for report type %d\n", report); ret = 1; fail = 0; } } XCloseDisplay(dpy); return ret; }