mirror of
https://github.com/libretro/RetroArch.git
synced 2026-11-09 03:29:43 -10:00
dispserv_x11: survive an X server with RandR but no usable output
Every XRandR query in this file was treated as infallible. Under any server that advertises RandR without a configured output -- Xvfb is the easy one to reach, but a real display with everything disconnected gets there too -- x11_display_server_get_screen_orientation() segfaults during video_display_server_init(), before RetroArch has drawn anything: #0 x11_display_server_get_screen_orientation () #1 video_display_server_init () #2 rarch_main () XRRGetOutputInfo() returns NULL for an output the server cannot describe and info->connection was read straight off it. Same for XRRGetCrtcInfo() and crtc->width. XRRGetScreenResources() can fail. x11_display_server_open_display() can return NULL, and DefaultRootWindow() dereferences its argument. And XRRGetScreenInfo() can fail, while XRRFreeScreenConfigInfo() is not NULL-tolerant, so the cleanup path faults on the way out. Test all of them, in the four functions that query: get_screen_orientation, set_screen_orientation and both branches of set_resolution. Separately, both orientation walks iterate for (j = 0; j < info->ncrtc; j++) XRRGetCrtcInfo(dpy, screen, screen->crtcs[j]); ncrtc bounds info->crtcs, not screen->crtcs. Reading the screen's array with the output's count is out of bounds whenever an output has more crtcs than the screen has, and where it happens to stay in bounds it still describes the wrong crtc. The set path then compounded it by passing screen->crtcs[j] to XRRSetCrtcConfig() -- configuring one crtc from another's geometry. Both now use info->crtcs[j]. Call ordering in set_resolution is preserved: XRRAddOutputMode() and the orig_output copy still happen before XRRGetCrtcInfo(), with the NULL test moved to a separate block afterwards rather than folded into the condition. Verified by running: with these in place RetroArch reaches video init under Xvfb and renders the XMB menu on llvmpipe. Builds clean with the flags the unix Makefile emits and under -std=c89 -pedantic.
This commit is contained in:
1 parent
0f6ab5f6aa
commit
26b640f0ff
1 file changed
+66
-13
@@ -258,6 +258,9 @@ static bool x11_display_server_set_resolution(void *data,
|
||||
{
|
||||
XRROutputInfo *outputs = XRRGetOutputInfo(dpy, res, res->outputs[i]);
|
||||
|
||||
if (!outputs)
|
||||
continue;
|
||||
|
||||
if (outputs->connection == RR_Connected)
|
||||
{
|
||||
XRRCrtcInfo *crtc = NULL;
|
||||
@@ -266,7 +269,11 @@ static bool x11_display_server_set_resolution(void *data,
|
||||
XSync(dpy, False);
|
||||
strlcpy(dispserv->orig_output, outputs->name,
|
||||
sizeof(dispserv->orig_output));
|
||||
crtc = XRRGetCrtcInfo(dpy, resources, outputs->crtc);
|
||||
if (!(crtc = XRRGetCrtcInfo(dpy, resources, outputs->crtc)))
|
||||
{
|
||||
XRRFreeOutputInfo(outputs);
|
||||
continue;
|
||||
}
|
||||
crtc->mode = swmode->id;
|
||||
crtc->width = swmode->width;
|
||||
crtc->height = swmode->height;
|
||||
@@ -291,16 +298,19 @@ static bool x11_display_server_set_resolution(void *data,
|
||||
else
|
||||
{
|
||||
XRROutputInfo *outputs = XRRGetOutputInfo(dpy, res, res->outputs[monitor_index]);
|
||||
XRRCrtcInfo *crtc = NULL;
|
||||
|
||||
if (outputs->connection == RR_Connected)
|
||||
if (outputs && outputs->connection == RR_Connected)
|
||||
{
|
||||
XRRCrtcInfo *crtc = NULL;
|
||||
|
||||
XRRAddOutputMode(dpy, res->outputs[monitor_index], swmode->id);
|
||||
XSync(dpy, False);
|
||||
strlcpy(dispserv->orig_output, outputs->name,
|
||||
sizeof(dispserv->orig_output));
|
||||
crtc = XRRGetCrtcInfo(dpy, resources, outputs->crtc);
|
||||
}
|
||||
|
||||
if (crtc)
|
||||
{
|
||||
crtc->mode = swmode->id;
|
||||
crtc->width = swmode->width;
|
||||
crtc->height = swmode->height;
|
||||
@@ -316,7 +326,8 @@ static bool x11_display_server_set_resolution(void *data,
|
||||
|
||||
XRRFreeCrtcInfo(crtc);
|
||||
}
|
||||
XRRFreeOutputInfo(outputs);
|
||||
if (outputs)
|
||||
XRRFreeOutputInfo(outputs);
|
||||
}
|
||||
XRRFreeScreenResources(resources);
|
||||
XCloseDisplay(dpy);
|
||||
@@ -337,10 +348,23 @@ static void x11_display_server_set_screen_orientation(void *data,
|
||||
|
||||
screen = XRRGetScreenResources(dpy, DefaultRootWindow(dpy));
|
||||
|
||||
if (!screen)
|
||||
{
|
||||
XUngrabServer(dpy);
|
||||
if (config)
|
||||
XRRFreeScreenConfigInfo(config);
|
||||
XCloseDisplay(dpy);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < screen->noutput; i++)
|
||||
{
|
||||
XRROutputInfo *info = XRRGetOutputInfo(dpy, screen, screen->outputs[i]);
|
||||
|
||||
/* See x11_display_server_get_screen_orientation(). */
|
||||
if (!info)
|
||||
continue;
|
||||
|
||||
if (info->connection != RR_Connected)
|
||||
{
|
||||
XRRFreeOutputInfo(info);
|
||||
@@ -349,9 +373,12 @@ static void x11_display_server_set_screen_orientation(void *data,
|
||||
|
||||
for (j = 0; j < info->ncrtc; j++)
|
||||
{
|
||||
XRRCrtcInfo *crtc = XRRGetCrtcInfo(dpy, screen, screen->crtcs[j]);
|
||||
XRRCrtcInfo *crtc = XRRGetCrtcInfo(dpy, screen, info->crtcs[j]);
|
||||
Rotation new_rotation = RR_Rotate_0;
|
||||
|
||||
if (!crtc)
|
||||
continue;
|
||||
|
||||
if (crtc->width == 0 || crtc->height == 0)
|
||||
{
|
||||
XRRFreeCrtcInfo(crtc);
|
||||
@@ -399,7 +426,7 @@ static void x11_display_server_set_screen_orientation(void *data,
|
||||
|
||||
XRRSetScreenSize(dpy, DefaultRootWindow(dpy), crtc->width, crtc->height, (25.4 * crtc->width) / dpi, (25.4 * crtc->height) / dpi);
|
||||
|
||||
XRRSetCrtcConfig(dpy, screen, screen->crtcs[j], CurrentTime, crtc->x, crtc->y, crtc->mode, crtc->rotation, crtc->outputs, crtc->noutput);
|
||||
XRRSetCrtcConfig(dpy, screen, info->crtcs[j], CurrentTime, crtc->x, crtc->y, crtc->mode, crtc->rotation, crtc->outputs, crtc->noutput);
|
||||
|
||||
XRRFreeCrtcInfo(crtc);
|
||||
}
|
||||
@@ -411,7 +438,8 @@ static void x11_display_server_set_screen_orientation(void *data,
|
||||
|
||||
XUngrabServer(dpy);
|
||||
XSync(dpy, False);
|
||||
XRRFreeScreenConfigInfo(config);
|
||||
if (config)
|
||||
XRRFreeScreenConfigInfo(config);
|
||||
XCloseDisplay(dpy);
|
||||
}
|
||||
|
||||
@@ -422,24 +450,47 @@ static enum rotation x11_display_server_get_screen_orientation(void *data)
|
||||
enum rotation rotation = ORIENTATION_NORMAL;
|
||||
dispserv_x11_t *dispserv = (dispserv_x11_t*)data;
|
||||
Display *dpy = x11_display_server_open_display(dispserv);
|
||||
XRRScreenResources *screen = XRRGetScreenResources(dpy, DefaultRootWindow(dpy));
|
||||
if (!screen)
|
||||
return ORIENTATION_NORMAL;
|
||||
XRRScreenResources *screen = NULL;
|
||||
|
||||
/* x11_display_server_open_display() returns NULL when there is no
|
||||
* global display and XOpenDisplay() fails; DefaultRootWindow()
|
||||
* dereferences its argument. */
|
||||
if (!dpy)
|
||||
return ORIENTATION_NORMAL;
|
||||
|
||||
if (!(screen = XRRGetScreenResources(dpy, DefaultRootWindow(dpy))))
|
||||
{
|
||||
x11_display_server_close_display(dispserv, dpy);
|
||||
return ORIENTATION_NORMAL;
|
||||
}
|
||||
|
||||
config = XRRGetScreenInfo(dpy, DefaultRootWindow(dpy));
|
||||
|
||||
for (i = 0; i < screen->noutput; i++)
|
||||
{
|
||||
XRROutputInfo *info = XRRGetOutputInfo(dpy, screen, screen->outputs[i]);
|
||||
|
||||
/* XRRGetOutputInfo() returns NULL for an output the server
|
||||
* cannot describe, which is the normal case under Xvfb and any
|
||||
* other server with RandR present but no configured output. */
|
||||
if (!info)
|
||||
continue;
|
||||
|
||||
if (info->connection != RR_Connected)
|
||||
{
|
||||
XRRFreeOutputInfo(info);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* The crtcs to walk are this output's, not the screen's: ncrtc
|
||||
* bounds info->crtcs, and there is no guarantee the screen has
|
||||
* that many. */
|
||||
for (j = 0; j < info->ncrtc; j++)
|
||||
{
|
||||
XRRCrtcInfo *crtc = XRRGetCrtcInfo(dpy, screen, screen->crtcs[j]);
|
||||
XRRCrtcInfo *crtc = XRRGetCrtcInfo(dpy, screen, info->crtcs[j]);
|
||||
|
||||
if (!crtc)
|
||||
continue;
|
||||
|
||||
if (crtc->width == 0 || crtc->height == 0)
|
||||
{
|
||||
@@ -471,7 +522,9 @@ static enum rotation x11_display_server_get_screen_orientation(void *data)
|
||||
}
|
||||
|
||||
XRRFreeScreenResources(screen);
|
||||
XRRFreeScreenConfigInfo(config);
|
||||
/* XRRGetScreenInfo() can fail; the free is not NULL-tolerant. */
|
||||
if (config)
|
||||
XRRFreeScreenConfigInfo(config);
|
||||
|
||||
x11_display_server_close_display(dispserv, dpy);
|
||||
|
||||
|
||||
Reference in new issue
Block a user