Index: ChangeLog
===================================================================
RCS file: /cvsroot/tcl/tcl/ChangeLog,v
retrieving revision 1.865
diff -u -u -r1.865 ChangeLog
--- ChangeLog	22 Feb 2002 21:54:39 -0000	1.865
+++ ChangeLog	22 Feb 2002 22:32:44 -0000
@@ -1,3 +1,11 @@
+2002-02-22  Don Porter <dgp@users.sourceforge.net>
+
+	* generic/tclInt.h:
+	* generic/tclObj.c: renamed global variable emptyString ->
+	tclEmptyString because it is no longer static.
+	* generic/tclPkg.c: Fix for panic when library is loaded on a
+	platform without backlinking without proper use of stubs. [Bug 476537]
+
 2002-02-22  Jeff Hobbs  <jeffh@ActiveState.com>
 
 	* tests/regexpComp.test: updated regexp-11.[1-4] to match changes
Index: generic/tclInt.h
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclInt.h,v
retrieving revision 1.80
diff -u -u -r1.80 tclInt.h
--- generic/tclInt.h	15 Feb 2002 14:28:49 -0000	1.80
+++ generic/tclInt.h	22 Feb 2002 22:32:45 -0000
@@ -1629,6 +1629,7 @@
  */
 
 extern char *		tclEmptyStringRep;
+extern char		tclEmptyString;
 
 /*
  *----------------------------------------------------------------
Index: generic/tclObj.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclObj.c,v
retrieving revision 1.29
diff -u -u -r1.29 tclObj.c
--- generic/tclObj.c	15 Feb 2002 14:28:49 -0000	1.29
+++ generic/tclObj.c	22 Feb 2002 22:32:46 -0000
@@ -47,8 +47,8 @@
  * is shared by all new objects allocated by Tcl_NewObj.
  */
 
-static char emptyString;
-char *tclEmptyStringRep = &emptyString;
+char tclEmptyString = '\0';
+char *tclEmptyStringRep = &tclEmptyString;
 
 /*
  * Prototypes for procedures defined later in this file:
Index: generic/tclPkg.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclPkg.c,v
retrieving revision 1.8
diff -u -u -r1.8 tclPkg.c
--- generic/tclPkg.c	17 Jan 2002 04:37:33 -0000	1.8
+++ generic/tclPkg.c	22 Feb 2002 22:32:46 -0000
@@ -187,7 +187,7 @@
     Tcl_DString command;
 
     /*
-     * If an attempt is being made to load this into a standalong executable
+     * If an attempt is being made to load this into a standalone executable
      * on a platform where backlinking is not supported then this must be
      * a shared version of Tcl (Otherwise the load would have failed).
      * Detect this situation by checking that this library has been correctly
@@ -195,7 +195,67 @@
      * work.
      */
     
-    if (!tclEmptyStringRep) {
+    if (tclEmptyStringRep == NULL) {
+
+	/*
+	 * OK, so what's going on here?
+	 *
+	 * First, what are we doing?  We are performing a check on behalf of
+	 * one particular caller, Tcl_InitStubs().  When a package is
+	 * stub-enabled, it is statically linked to libtclstub.a, which
+	 * contains a copy of Tcl_InitStubs().  When a stub-enabled package
+	 * is loaded, its *_Init() function is supposed to call
+	 * Tcl_InitStubs() before calling any other functions in the Tcl
+	 * library.  The first Tcl function called by Tcl_InitStubs() through
+	 * the stub table is Tcl_PkgRequireEx(), so this code right here is
+	 * the first code that is part of the original Tcl library in the
+	 * executable that gets executed on behalf of a newly loaded
+	 * stub-enabled package.
+	 *
+	 * One easy error for the developer/builder of a stub-enabled package
+	 * to make is to forget to define USE_TCL_STUBS when compiling the
+	 * package.  When that happens, the package will contain symbols
+	 * that are references to the Tcl library, rather than function
+	 * pointers referencing the stub table.  On platforms that lack
+	 * backlinking, those unresolved references may cause the loading
+	 * of the package to also load a second copy of the Tcl library,
+	 * leading to all kinds of trouble.  We would like to catch that
+	 * error and report a useful message back to the user.  That's
+	 * what we're doing.
+	 *
+	 * Second, how does this work?  If we reach this point, then the
+	 * global variable tclEmptyStringRep has the value NULL.  Compare
+	 * that with the definition of tclEmptyStringRep near the top of
+	 * the file generic/tclObj.c.  It clearly should not have the value
+	 * NULL; it should point to the char tclEmptyString.  If we see it
+	 * having the value NULL, then somehow we are seeing a Tcl library
+	 * that isn't completely initialized, and that's an indicator for the
+	 * error condition described above.  (Further explanation is welcome.)
+	 *
+	 * Third, so what do we do about it?  This situation indicates
+	 * the package we just loaded wasn't properly compiled to be
+	 * stub-enabled, yet it thinks it is stub-enabled (it called
+	 * Tcl_InitStubs()).  We want to report that the package just
+	 * loaded is broken, so we want to place an error message in
+	 * the interpreter result and return NULL to indicate failure
+	 * to Tcl_InitStubs() so that it will also fail.  (Further
+	 * explanation why we don't want to Tcl_Panic() is welcome.
+	 * After all, two Tcl libraries can't be a good thing!)
+	 *
+	 * Trouble is that's going to be tricky.  We're now using a Tcl
+	 * library that's not fully initialized.  In particular, it 
+	 * doesn't have a proper value for tclEmptyStringRep.  The
+	 * Tcl_Obj system heavily depends on the value of tclEmptyStringRep
+	 * and all of Tcl depends (increasingly) on the Tcl_Obj system, we
+	 * need to correct that flaw before making the calls to set the 
+	 * interpreter result to the error message.  That's the only flaw
+	 * corrected; other problems with initialization of the Tcl library
+	 * are not remedied, so be very careful about adding any other calls
+	 * here without checking how they behave when initialization is
+	 * incomplete.
+	 */
+
+	tclEmptyStringRep = &tclEmptyString;
         Tcl_AppendResult(interp, "Cannot load package \"", name, 
                 "\" in standalone executable: This package is not ",
                 "compiled with stub support", NULL);
@@ -386,22 +446,6 @@
     Tcl_HashEntry *hPtr;
     Package *pkgPtr;
     int satisfies, result;
-
-    /*
-     * If an attempt is being made to load this into a standalone executable
-     * on a platform where backlinking is not supported then this must be
-     * a shared version of Tcl (Otherwise the load would have failed).
-     * Detect this situation by checking that this library has been correctly
-     * initialised. If it has not been then return immediately as nothing will
-     * work.
-     */
-    
-    if (!tclEmptyStringRep) {
-        Tcl_AppendResult(interp, "Cannot load package \"", name, 
-                "\" in standalone executable: This package is not ",
-                "compiled with stub support", NULL);
-        return NULL;
-    }
 
     hPtr = Tcl_FindHashEntry(&iPtr->packageTable, name);
     if (hPtr) {
