Comment 3 for bug 104978

Revision history for this message
xtknight (xt-knight) wrote :

I have the same problem. It is because Xinerama+Xrandr don't work together. Xinerama causes Xrandr to malfunction. And when the 'xrandr' program tries to access the Xrandr X extension, it gets a wrong response that it exists but it doesn't.

(Feisty i386 / nvidia)
Pkg: xrandr 1:1.0.2-0ubuntu1
Pkg: libxrandr2 2:1.2.0-3ubuntu1
Pkg: libxext6 2:1.0.3-1build1

I have traced the bug's path. I hope this helps the bug-squatters.

$ ltrace xrandr
__libc_start_main(0x8048d01, 1, 0xbf9c2284, 0x8049df9, 0x8049df4 <unfinished ...>
XOpenDisplay(NULL) = 0x804c008
XRRGetScreenInfo(0x804c008, 421, 0xb7f67ff4, 0xb7f2ce7c, 4 <unfinished ...>

It is crashing within XRRGetScreenInfo(). There is a null pointer causing a segmentation fault.

++Excerpt <main()> from <xrandr-1.0.2/xrandr.c>++
Line 207: sc = XRRGetScreenInfo (dpy, root);
//crashes within XRRGetScreenInfo()

++Excerpt <XRRGetScreenInfo()> from <libxrandr-1.2.0/src/XrrConfig.c>++
-----------------------
Line 345: XRRScreenConfiguration *XRRGetScreenInfo (Display *dpy, Window window)
{
    XRRScreenConfiguration *config;
    XExtDisplayInfo *info = XRRFindDisplay(dpy); // Xinerama+XRANDR crash: XRRFindDisplay() DOES NOT RETURN COMPLETE STRUCTURE (info->codes missing)
    XRRFindDisplay(dpy);
    LockDisplay (dpy);
    /*SEGFAULT WITHIN>>>>>>>>>>*/ config = _XRRGetScreenInfo(dpy, info /*sending incomplete structure*/, window);
    UnlockDisplay (dpy);
    SyncHandle ();
    return config;
}
-----------------------
++Excerpt <XRRFindDisplay()> from <libxrandr-1.2.0/src/Xrandr.c>++
-----------------------
Line 213: XExtDisplayInfo *
XRRFindDisplay (Display *dpy)
{
    XExtDisplayInfo *dpyinfo;
    XRandRInfo *xrri;
    int i, numscreens;
    dpyinfo = XextFindDisplay (&XRRExtensionInfo, dpy);

    if (!dpyinfo) {
 dpyinfo = XextAddDisplay (&XRRExtensionInfo, dpy,
      XRRExtensionName,
      &rr_extension_hooks,
      RRNumberEvents, 0);
       // dpyinfo->codes = NULL received from XextAddDisplay() <------- problem
       ....
       return dpyinfo; // structure with missing 'codes' member returned to caller <XRRGetScreenInfo()>
-----------------------
++Excerpt <XextAddDisplay()> from <libxext-1.0.3/src/extutil.c>++
-----------------------
Line 94: XExtDisplayInfo *XextAddDisplay (
    XExtensionInfo *extinfo,
    Display *dpy,
    char *ext_name,
    XExtensionHooks *hooks,
    int nevents,
    XPointer data)
{
    XExtDisplayInfo *dpyinfo;
    dpyinfo = (XExtDisplayInfo *) Xmalloc (sizeof (XExtDisplayInfo));
    ....
    dpyinfo->codes = XInitExtension (dpy, ext_name); // in this case, initialize XRandr extension for dpy (display)

    if (dpyinfo->codes) {
    ....
    } else if (hooks->close_display) {
        /*....*/
        XExtCodes *codes = XAddExtension(dpy);
 if (!codes) {
     XFree(dpyinfo);
     return NULL;
 }

        // INFO: but <<< codes >>> is not NULL
        // so it falls through to here
        // dpyinfo is later returned with a blank 'codes' member/pointer.

        XESetCloseDisplay (dpy, codes->extension, hooks->close_display);
    }

    ....
    return dpyinfo; // it is returned here. it then returns to the calling function <XRRFindDisplay()> which receives a valid pointer to the dpyinfo with a missing 'codes' value. should perhaps return NULL since the extension could not actually be found. this would need to be handled properly by the calling functions too, though. Merely doing this won't prevent the segfault as a NULL pointer will still be passed on.
    ....

This structure with a null 'codes' member gets sent to
-----------------------
++Excerpt <_XRRGetScreenInfo()> from <libxrandr-1.2.0/src/XrrConfig.c> (called from <main()> of <xrandr-1.0.2/xrandr.c>)++
-----------------------
static XRRScreenConfiguration *_XRRGetScreenInfo (Display *dpy,
        XExtDisplayInfo *info,
        Window window)
{
....
if (xrri->major_version == -1)
    {
     ....
     vreq->reqType = info->codes->major_opcode; // SEGFAULT HERE. codes is null. attempting to access member of null pointer (NULL->major_opcode).