diff options
| -rw-r--r-- | ChangeLog | 8 | ||||
| -rw-r--r-- | generic/tclInt.h | 3 | ||||
| -rw-r--r-- | generic/tclObj.c | 6 | ||||
| -rw-r--r-- | generic/tclPkg.c | 82 | 
4 files changed, 76 insertions, 23 deletions
| @@ -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 diff --git a/generic/tclInt.h b/generic/tclInt.h index 209991d..5c9ffbc 100644 --- a/generic/tclInt.h +++ b/generic/tclInt.h @@ -12,7 +12,7 @@   * See the file "license.terms" for information on usage and redistribution   * of this file, and for a DISCLAIMER OF ALL WARRANTIES.   * - * RCS: @(#) $Id: tclInt.h,v 1.80 2002/02/15 14:28:49 dkf Exp $ + * RCS: @(#) $Id: tclInt.h,v 1.81 2002/02/22 22:36:09 dgp Exp $   */  #ifndef _TCLINT @@ -1629,6 +1629,7 @@ extern long		tclObjsShared[TCL_MAX_SHARED_OBJ_STATS];   */  extern char *		tclEmptyStringRep; +extern char		tclEmptyString;  /*   *---------------------------------------------------------------- diff --git a/generic/tclObj.c b/generic/tclObj.c index c5f7f12..a2eb282 100644 --- a/generic/tclObj.c +++ b/generic/tclObj.c @@ -11,7 +11,7 @@   * See the file "license.terms" for information on usage and redistribution   * of this file, and for a DISCLAIMER OF ALL WARRANTIES.   * - * RCS: @(#) $Id: tclObj.c,v 1.29 2002/02/15 14:28:49 dkf Exp $ + * RCS: @(#) $Id: tclObj.c,v 1.30 2002/02/22 22:36:09 dgp Exp $   */  #include "tclInt.h" @@ -47,8 +47,8 @@ Tcl_Mutex tclObjMutex;   * 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: diff --git a/generic/tclPkg.c b/generic/tclPkg.c index 919b1b9..43d859b 100644 --- a/generic/tclPkg.c +++ b/generic/tclPkg.c @@ -9,7 +9,7 @@   * See the file "license.terms" for information on usage and redistribution   * of this file, and for a DISCLAIMER OF ALL WARRANTIES.   * - * RCS: @(#) $Id: tclPkg.c,v 1.8 2002/01/17 04:37:33 dgp Exp $ + * RCS: @(#) $Id: tclPkg.c,v 1.9 2002/02/22 22:36:09 dgp Exp $   */  #include "tclInt.h" @@ -187,7 +187,7 @@ Tcl_PkgRequireEx(interp, name, version, exact, clientDataPtr)      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 @@ Tcl_PkgRequireEx(interp, name, version, exact, clientDataPtr)       * 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); @@ -387,22 +447,6 @@ Tcl_PkgPresentEx(interp, name, version, exact, clientDataPtr)      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) {  	pkgPtr = (Package *) Tcl_GetHashValue(hPtr); | 
