Bug 7588

Summary: libXau is not thread safe
Product: xorg Reporter: Alan Coopersmith <alan.coopersmith>
Component: Lib/XauAssignee: Xorg Project Team <xorg-team>
Status: RESOLVED INVALID QA Contact: Xorg Project Team <xorg-team>
Severity: major    
Priority: high CC: jeremyhu
Version: gitKeywords: love
Hardware: All   
OS: All   
Whiteboard: 2011BRB_Reviewed
i915 platform: i915 features:

Description Alan Coopersmith 2006-07-21 09:47:02 UTC
Reported by SGI to old X.Org bug DB - the following is copied from X.Org Defect
8617 - unfortunately, in my copy, the end of the suggested fix got corrupted.

      VERSION:
 
 R6.3, public-patch-2
 
      CLIENT MACHINE and OPERATING SYSTEM:
 
 SGI Indigo2 / SGI Challenge L / Irix 6.5
 
      DISPLAY TYPE:
 
 SGI Indigo 2 XL
 
      WINDOW MANAGER:
 
 fvwm / 4Dwm
 
      COMPILER:
 
 native cc (7.2+)
 
      AREA:
 
 Xau
 
      SYNOPSIS:
 
 libXau is not thread safe.
 
      DESCRIPTION:
 
 Two variables (size,buf) in the function XauFileName are of storage class
 'static' these need to be protected against multiple threads accessing them at
 the same time.
 
      REPEAT BY:
 
 The following sample code creates 10 (NUM_THREADS) threads, each with its own
 display connection/application context/mainloop [Note that the default server
 source only allows for 5 connections to be 'listened' on at once, so you may
 need to lower this/rebuild server]. The shell script (run.sh) loops
 continuously until the test program core dumps. Multiple processors make this
 more likely
 
 
 8<------------------ run.sh -----------------------
 
 #! /bin/sh
 
 rm -f core
 while [ ! -f core ]
 do
     echo $1
     ./$1 -synchronous $2
 done
 ls -l core
 
 
 
 8<----------------------- threads.c ----------------------
 
 
 #include <Xm/XmAll.h>
 #include <X11/Xthreads.h>
 #include <unistd.h>
 #include <stdlib.h>
 #include <errno.h>
 
 /* #define      GADGETS */
 #define TIMEOUT         10000
 #define NUM_THREADS     10
 
 typedef struct _ThreadData {
         int             argc;
         char    **argv;
         pthread_t               id;
         int             thread_num;
         XtAppContext    app;
         Display *dsp;
         Widget  shell;
         XEvent  *event;
 } ThreadData;
 
 static char *fallbacks[] =
 {
     "*XmTextField.value: text field",
     "*XmText.value: text widget",
     "Shell.sgiMode: True",
     0
 };
 
 void
 errorHandler(Display *dsp)
 {
 
         abort();
 
 }
 
 void xtErrorHandler(char *msg)
 {
         abort();
 }
 
 void xtErrorMsgHandler(String name, String type, String class, String def,
 String *params, Cardinal *num)
 {
         abort();
 }
 
 static void
 nullTO(XtPointer client, XtIntervalId *id)
 {
 }
 
 static void
 timerCB(XtPointer client, XtIntervalId *id)
 {
         ThreadData *thread = (ThreadData *) client;
 
     XtAppSetExitFlag(thread->app);
 
 /* really bogus... We need to generate a fake event, to ensure that
  * XtAppNextEvent() unblocks. This wouldn't normally be a problem, since
  * XtAppSetExitFlag would be called from a Callback (probably from a pulldown
  * menu), the poping down of which would generate the event to unblock
  * XtAppNextEvent rmo */
         XSendEvent(XtDisplay(thread->shell), XtWindow(thread->shell),
                 False,
                 0,
                 thread->event);
 }
 
 static void
 mapCB(Widget w, XtPointer client, XEvent *xev, Boolean *cont)
 {
         ThreadData *thread = (ThreadData *) client;
     if (xev->type == MapNotify) {
                 thread->event = xev;
                 XtAppAddTimeOut(thread->app, TIMEOUT, timerCB, client);
         }
 }
 
 static void *
 createShell(void *ptr)
 {
         ThreadData *thread = (ThreadData *) ptr;
     Widget top, rc, w;
     unsigned int num;
     char buf[20];
     Arg args[10];
         Display *dsp;
 
         num = thread->thread_num;
 
 #ifdef APP_INIT
 
         thread->shell = XtVaAppInitialize(&thread->app, "Shell", 0, 0,
                        &thread->argc, thread->argv,
                        fallbacks,
                                            XtNwidth, 100,
                                            XtNheight, 100,
                                            NULL);
         thread->dsp = XtDisplay(thread->shell);
 
 #else
         thread->dsp = XtOpenDisplay(thread->app,NULL,
                         NULL, "Shell",
                         NULL, 0,
                         &thread->argc,
                         thread->argv);
 
         thread->shell = XtVaAppCreateShell(NULL,"Shell",
                         applicationShellWidgetClass,
                         thread->dsp,
                         XtNwidth, 100,
                         XtNheight, 100,
                         NULL);
 
 #endif /* APP_INIT */
 
 
 
         XtAddEventHandler(thread->shell,StructureNotifyMask, False, mapCB,
 thread);
         /*
                 XtAppAddTimeOut(thread->app, TIMEOUT, timerCB, thread);
         */
 
     XtRealizeWidget(thread->shell);
     XtAppMainLoop(thread->app);
 
         XtDestroyApplicationContext(thread->app);
     return NULL;
 }
 
 
 main(int argc, char **argv)
 {
     unsigned int numThreads = NUM_THREADS;
     Boolean status;
         int i;
 
     /* don't need Xlib threads */
     status = XInitThreads();
     if (status) {
         puts("Xlib threads supported");
     } else {
         puts("Xlib threads not supported");
         exit(1);
     }
 
     status = XtToolkitThreadInitialize();
     if (status) {
         puts("Xt threads supported");
     } else {
         puts("Xt threads not supported");
         exit(1);
     }
 
     XtToolkitInitialize();
 
         XSetIOErrorHandler( (XIOErrorHandler) errorHandler);
 
         XtSetErrorMsgHandler( (XtErrorMsgHandler) xtErrorMsgHandler );
 
     while(numThreads--) {
                 ThreadData *thread = (ThreadData *) calloc(1,
 sizeof(ThreadData) );
 
                 thread->argc = argc;
                 thread->argv = (char **) calloc(argc, sizeof(char *) );
                 thread->thread_num = numThreads;
 
 #ifndef APP_INIT
                 thread->app = XtCreateApplicationContext();
 #endif
 
                 for (i=0; i< argc; i++ )
                                 thread->argv[i] = XtNewString(argv[i]);
 
                 pthread_create(&thread->id, NULL, createShell, (void *)thread);
         }
 
     pthread_exit(NULL);
 }
 
      SAMPLE FIX:
 
 /* $XConsortium: AuFileName.c /main/8 1996/09/28 16:43:20 rws $ */
 
 [ piranha Jan04f ] p_rdiff -c AuFileName.c
 *** /usr/tmp/p_rdiff_16049/AuFileName.c Wed Feb  4 14:31:21 1998
 --- AuFileName.c        Wed Feb  4 14:31:12 1998
 ***************
 *** 30,40 ****
   #include <X11/Xauth.h>
   #include <X11/Xos.h>
 
   char *
   XauFileName ()
   {
       char *slashDotXauthority = "/.Xauthority";
 !     char    *name, *malloc (), *getenv ();
   #ifdef __sgi
        /*
         * PAGE USAGE TUNING: explicitly initialize to move these to data
 --- 30,53 ----
   #include <X11/Xauth.h>
   #include <X11/Xos.h>
 
 + #ifdef _SGIBUGFIX
 + /* Bugworks #568635: offer jan 98 */
 + #ifdef XTHREADS
 + #include <X11/Xlibint.h>
 + #endif /* XTHREADS */
 + #endif /* _SGIBUGFIX */
 +
   char *
   XauFileName ()
   {
       char *slashDotXauthority = "/.Xauthority";
 !     char    *name, *getenv ();
 ! #ifdef _SGIBUGFIX
 ! #ifndef XTHREADS
 !       char    *malloc();
 ! #endif /* XTHREADS */
 ! #endif /* _SGIBUGFIX */
 !
   #ifdef __sgi
        /*
         * PAGE USAGE TUNING: explicitly initialize to move these to data
 ***************
 *** 66,71 ****
 --- 79,89 ----
         return 0;
       }
       size = strlen (name) + strlen(&slashDotXauthority[1]) + 2;
 + #ifdef _SGIBUGFIX
 + #ifdef XTHREADS
 +       _XLockMutex(_Xglobal_lock);
 + #endif /* XTHREADS */
 + #endif /* _SGIBUGFIX */
       if (size > bsize) {
         if (buf)
             free (buf);
 ***************
 *** 76,80 ****
 --- 94,103 ----
       }
       strcpy (buf, name);
       strcat (buf, slashDotXauthority + (name[1] == '

[That's all I got - presumably _XUnlockMutex was added here.]
Comment 1 Alan Coopersmith 2006-07-21 09:48:31 UTC
The proposed fix looks fine (assuming the addition of unlock) for client side
code - but are _XLockMutex, etal. defined in the X server?
Comment 2 Daniel Stone 2006-12-16 09:47:29 UTC
nope, it's not.  we need to find a better solution to this, long-term.
Comment 3 Daniel Stone 2007-02-27 01:32:58 UTC
Sorry about the phenomenal bug spam, guys.  Adding xorg-team@ to the QA contact so bugs don't get lost in future.
Comment 4 Jeremy Huddleston Sequoia 2011-10-02 02:26:00 UTC
I just stumbled upon this.  Wow.  Is this still true, or has it been addressed 
and the bug just never got closed?
Comment 5 Adam Jackson 2018-06-12 19:10:46 UTC
Mass closure: This bug has been untouched for more than six years, and is not
obviously still valid. Please reopen this bug or file a new report if you continue to experience issues with current releases.

Use of freedesktop.org services, including Bugzilla, is subject to our Code of Conduct. How we collect and use information is described in our Privacy Policy.