mirror of
https://github.com/X11Libre/xserver.git
synced 2026-01-26 05:57:53 +00:00
present: Call driver check_flip after we finish with our checks
We don't really gain anything by calling `check_flip` early,
but it turns out that doing so causes problems.
Thanks to @jipok for finding this issue:
```
// gcc crash_x11libre.c -o crash_x11libre -lX11 -lXext -lXpresent
// Code written by LLM!
// WARNING: THIS PROGRAM IS INTENDED TO CRASH THE X SERVER (via XPresent + Glamor bug)
void attempt_crash_via_present(Display* dpy, Window win, int width, int height, int depth) {
XShmSegmentInfo shminfo;
// 1. Calculate TIGHT stride (width * 4 bytes).
// Misalignment here + XPresent is the killer combination.
int stride = width * 4;
size_t size = stride * height;
// 2. Resize the window to match the buffer (simulating JTK resize behavior)
XResizeWindow(dpy, win, width, height);
// XSync(dpy, False); // Optional: let window manager catch up, but hammering triggers races better
// 3. Allocate Shared Memory
memset(&shminfo, 0, sizeof(shminfo));
shminfo.shmid = shmget(IPC_PRIVATE, size, IPC_CREAT | 0777);
if (shminfo.shmid < 0) { perror("shmget"); return; }
shminfo.shmaddr = (char*)shmat(shminfo.shmid, 0, 0);
shminfo.readOnly = False;
shmctl(shminfo.shmid, IPC_RMID, 0); // Auto-cleanup
if (!XShmAttach(dpy, &shminfo)) {
fprintf(stderr, "XShmAttach failed\n");
shmdt(shminfo.shmaddr);
return;
}
// 4. Create the Misaligned Pixmap
Pixmap pixmap = XShmCreatePixmap(dpy, win, shminfo.shmaddr, &shminfo, width, height, depth);
// 5. THE TRIGGER: XPresentPixmap
// This forces Glamor to treat the SHM segment as a presentable surface.
// If strided alignment logic inside miCopyRegion/glamor is broken, this dies.
XPresentPixmap(dpy, win, pixmap, 0, 0, 0, 0, 0, None, None, None, 0, 0, 0, 0, 0, 0);
// Flush to make sure the server received the command
XSync(dpy, False);
// Cleanup for next iteration
XFreePixmap(dpy, pixmap);
XShmDetach(dpy, &shminfo);
shmdt(shminfo.shmaddr);
}
int main() {
Display* dpy = XOpenDisplay(NULL);
if (!dpy) { fprintf(stderr, "No display\n"); return 1; }
// Check extensions
int major, minor, pixmaps;
if (!XShmQueryVersion(dpy, &major, &minor, &pixmaps) || !pixmaps) {
fprintf(stderr, "XShm not supported!\n"); return 1;
}
int present_opcode, event_base, error_base;
if (!XQueryExtension(dpy, "Present", &present_opcode, &event_base, &error_base)) {
fprintf(stderr, "XPresent extension not supported! (Can't repro bug)\n");
return 1;
}
int screen = DefaultScreen(dpy);
XVisualInfo vinfo;
if (!XMatchVisualInfo(dpy, screen, 32, TrueColor, &vinfo)) {
printf("32-bit visual not found, using default.\n");
vinfo.visual = DefaultVisual(dpy, screen);
vinfo.depth = DefaultDepth(dpy, screen);
}
XSetWindowAttributes attrs;
attrs.colormap = XCreateColormap(dpy, RootWindow(dpy, screen), vinfo.visual, AllocNone);
attrs.background_pixel = 0; // Black
attrs.border_pixel = 0;
Window win = XCreateWindow(dpy, RootWindow(dpy, screen),
0, 0, 100, 100, 0,
vinfo.depth, InputOutput, vinfo.visual,
CWColormap | CWBackPixel | CWBorderPixel, &attrs);
XMapWindow(dpy, win);
XSync(dpy, False);
printf("Starting XPresent Stress Test...\n");
sleep(1);
// Fixed height (enough to have data), varying width
int height = 500;
// Iterate widths. We expect crashes on non-standard alignments.
// XLibre often crashes at 1266 width (stride 5064).
for (int w = 1000; w < 2000; w++) {
int stride = w * 4;
printf("\rTesting Width: %4d | Stride: %5d (mod 64: %2d)", w, stride, stride % 64);
fflush(stdout);
attempt_crash_via_present(dpy, win, w, height, vinfo.depth);
// Small delay to let the server actually try to process the Present request
// before we trash the memory, though XSync should handle it.
usleep(1000);
}
printf("\nTest finished successfully (No crash).\n");
XDestroyWindow(dpy, win);
XCloseDisplay(dpy);
return 0;
}
```
Fixes: https://github.com/X11Libre/xserver/issues/1754
Fixes: 9108a2bf55
Signed-off-by: stefan11111 <stefan11111@shitposting.expert>
This commit is contained in:
parent
0d93b942ad
commit
8ed09861dc
@ -58,6 +58,29 @@ present_flip_pending_pixmap(ScreenPtr screen)
|
||||
return screen_priv->flip_pending->pixmap;
|
||||
}
|
||||
|
||||
static inline Bool
|
||||
present_check_driver_flip(RRCrtcPtr crtc,
|
||||
WindowPtr window,
|
||||
PixmapPtr pixmap,
|
||||
Bool sync_flip,
|
||||
present_screen_priv_ptr screen_priv,
|
||||
PresentFlipReason *reason)
|
||||
{
|
||||
if (screen_priv->info->version >= 1 && screen_priv->info->check_flip2) {
|
||||
if (!(*screen_priv->info->check_flip2) (crtc, window, pixmap, sync_flip, reason)) {
|
||||
DebugPresent(("\td %08" PRIx32 " -> %08" PRIx32 "\n", window->drawable.id, pixmap ? pixmap->drawable.id : 0));
|
||||
return FALSE;
|
||||
}
|
||||
} else if (screen_priv->info->check_flip) {
|
||||
if (!(*screen_priv->info->check_flip) (crtc, window, pixmap, sync_flip)) {
|
||||
DebugPresent(("\td %08" PRIx32 " -> %08" PRIx32 "\n", window->drawable.id, pixmap ? pixmap->drawable.id : 0));
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static Bool
|
||||
present_check_flip(RRCrtcPtr crtc,
|
||||
WindowPtr window,
|
||||
@ -72,7 +95,6 @@ present_check_flip(RRCrtcPtr crtc,
|
||||
PixmapPtr window_pixmap;
|
||||
WindowPtr root = screen->root;
|
||||
present_screen_priv_ptr screen_priv = present_screen_priv(screen);
|
||||
PresentFlipReason tmp_reason = PRESENT_FLIP_REASON_UNKNOWN;
|
||||
|
||||
if (crtc) {
|
||||
screen_priv = present_screen_priv(crtc->pScreen);
|
||||
@ -93,27 +115,6 @@ present_check_flip(RRCrtcPtr crtc,
|
||||
if (!screen_priv->info->flip)
|
||||
return FALSE;
|
||||
|
||||
/* Ask the driver for permission. Do this now to see if there's TearFree. */
|
||||
if (screen_priv->info->version >= 1 && screen_priv->info->check_flip2) {
|
||||
if (!(*screen_priv->info->check_flip2) (crtc, window, pixmap, sync_flip, &tmp_reason)) {
|
||||
DebugPresent(("\td %08" PRIx32 " -> %08" PRIx32 "\n", window->drawable.id, pixmap ? pixmap->drawable.id : 0));
|
||||
/* It's fine to return now unless the page flip failure reason is
|
||||
* PRESENT_FLIP_REASON_BUFFER_FORMAT; we must only output that
|
||||
* reason if all the other checks pass.
|
||||
*/
|
||||
if (!reason || tmp_reason != PRESENT_FLIP_REASON_BUFFER_FORMAT) {
|
||||
if (reason)
|
||||
*reason = tmp_reason;
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
} else if (screen_priv->info->check_flip) {
|
||||
if (!(*screen_priv->info->check_flip) (crtc, window, pixmap, sync_flip)) {
|
||||
DebugPresent(("\td %08" PRIx32 " -> %08" PRIx32 "\n", window->drawable.id, pixmap ? pixmap->drawable.id : 0));
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Make sure the window hasn't been redirected with Composite */
|
||||
window_pixmap = screen->GetWindowPixmap(window);
|
||||
if (window_pixmap != screen->GetScreenPixmap(screen) &&
|
||||
@ -144,9 +145,13 @@ present_check_flip(RRCrtcPtr crtc,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (tmp_reason == PRESENT_FLIP_REASON_BUFFER_FORMAT) {
|
||||
if (reason)
|
||||
*reason = tmp_reason;
|
||||
/**
|
||||
* Ask the driver for permission
|
||||
*
|
||||
* We need to call the driver check flip after the full-screen window check.
|
||||
* See: https://github.com/X11Libre/xserver/issues/1754
|
||||
*/
|
||||
if (!present_check_driver_flip(crtc, window, pixmap, sync_flip, screen_priv, reason)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user