There's a problem with the current +mainBundle code in NSBundle.m. 
In attempting to find the executable used to start the process, it
invokes a function called objc_find_executable().  If the executable
path is relative, that function searches $PATH and the current working
directory.  If, as is often the case, the executable path is relative
and not in one of the directories in $PATH, it'll find the executable in
the current working directory.  But what if the process has changed the
cwd before calling +mainBundle?  Well, then it breaks.  The best
solution I can see is to find the executable path in NSBundle's
+initialize, i.e. before the program has a chance to change its cwd.
    On a related note, the method used by NSBundle has at least one
potential pitfall.  If a different version of the program exists in the
path before the one running, it could get the wrong main bundle.  Linux
provides a foolproof way to find the process' executable file:  look at
/proc/self/exe.  It's a symlink to the proper file.
    So, this patch updates three files:

        * base/configure.in: add a test to see whether a symlink
'/proc/self/exe' exists
        * base/Headers/gnustep/base/config.h.in: Add a definition for the test
result
        * base/Source/NSBundle.m: Move the discovery of the process' executable
file to +initialize; add code to discover it from /proc, if possible
Index: base/configure
===================================================================
RCS file: /gnustep/gnustep/core/base/configure,v
retrieving revision 1.37
diff -r1.37 configure
4224a4225,4238
> if test $sys_proc_fs = yes; then
>   echo $ac_n "checking link to executable in /proc""... $ac_c" 1>&6
> echo "configure:4228: checking link to executable in /proc" >&5
>   if test -L /proc/self/exe; then
>     cat >> confdefs.h <<\EOF
> #define HAVE_PROC_FS_EXE_LINK 1
> EOF
> 
>     echo "$ac_t""yes" 1>&6
>   else
>     echo "$ac_t""no" 1>&6
>   fi
> fi
> 
Index: base/configure.in
===================================================================
RCS file: /gnustep/gnustep/core/base/configure.in,v
retrieving revision 1.86
diff -r1.86 configure.in
654a655,667
> # Linux (and others?) /proc contains a symlink to the executable
> # file from which the process loaded its code.  This can be used
> # by NSBundle.m to locate the main bundle.
> if test $sys_proc_fs = yes; then
>   AC_MSG_CHECKING(link to executable in /proc)
>   if test -L /proc/self/exe; then
>     AC_DEFINE(HAVE_PROC_FS_EXE_LINK)
>     AC_MSG_RESULT(yes)
>   else
>     AC_MSG_RESULT(no)
>   fi
> fi
> 
Index: base/Headers/gnustep/base/config.h.in
===================================================================
RCS file: /gnustep/gnustep/core/base/Headers/gnustep/base/config.h.in,v
retrieving revision 1.23
diff -r1.23 config.h.in
31a32,34
> /* Define if your system has a /proc/self/exe symlink to the executable */
> #undef HAVE_PROC_FS_EXE_LINK
> 
Index: base/Source/NSBundle.m
===================================================================
RCS file: /gnustep/gnustep/core/base/Source/NSBundle.m,v
retrieving revision 1.63
diff -r1.63 NSBundle.m
75a76,78
> /* Keep the path to the executable file for finding the main bundle. */
> static NSString *_executable_path;
> 
254a258
>         char                  *output;
277a282,293
> #ifdef HAVE_PROC_FS_EXE_LINK
>         _executable_path = [[NSFileManager defaultManager]
>               contentsOfSymbolicLinkAtPath: @"/proc/self/exe"];
> #else
>         _executable_path =
>               [[[NSProcessInfo processInfo] arguments] objectAtIndex: 0];
>         output = objc_find_executable([_executable_path cString]);
>         NSAssert(output, NSInternalInconsistencyException);
>         _executable_path = [NSString stringWithCString: output];
>         OBJC_FREE(output);
> #endif
> 
312d327
<       char *output;
315,320d329
<       path = [[[NSProcessInfo processInfo] arguments] objectAtIndex: 0];
<       output = objc_find_executable([path cString]);
<       NSAssert(output, NSInternalInconsistencyException);
<       path = [NSString stringWithCString: output];
<       OBJC_FREE(output);
< 
322c331
<       path = [path stringByDeletingLastPathComponent];
---
>       path = [_executable_path stringByDeletingLastPathComponent];

Reply via email to