summaryrefslogtreecommitdiffstats
path: root/generic
diff options
context:
space:
mode:
authorferrieux <ferrieux@users.sourceforge.net>2009-11-16 17:38:08 (GMT)
committerferrieux <ferrieux@users.sourceforge.net>2009-11-16 17:38:08 (GMT)
commit3ffda83a5b3d9b03fa4bad1e5384919a46adf47a (patch)
tree1b93d42b56b88ab1862f7389658528282be889d6 /generic
parentd264119bd45f0b0e694574efc0a627ac1a4232cb (diff)
downloadtcl-3ffda83a5b3d9b03fa4bad1e5384919a46adf47a.zip
tcl-3ffda83a5b3d9b03fa4bad1e5384919a46adf47a.tar.gz
tcl-3ffda83a5b3d9b03fa4bad1e5384919a46adf47a.tar.bz2
(forward port) Fix [Bug 2891556] and improve test to detect similar manifestations in the future. Add tcltest support for finalization.
Diffstat (limited to 'generic')
-rw-r--r--generic/tclBasic.c8
-rw-r--r--generic/tclCmdIL.c57
-rw-r--r--generic/tclEncoding.c28
-rw-r--r--generic/tclInt.h4
-rw-r--r--generic/tclNamesp.c36
-rw-r--r--generic/tclResult.c9
-rw-r--r--generic/tclTest.c47
7 files changed, 175 insertions, 14 deletions
diff --git a/generic/tclBasic.c b/generic/tclBasic.c
index cca8fba..c8ae5ae 100644
--- a/generic/tclBasic.c
+++ b/generic/tclBasic.c
@@ -16,7 +16,7 @@
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: @(#) $Id: tclBasic.c,v 1.407 2009/11/10 20:53:24 andreas_kupries Exp $
+ * RCS: @(#) $Id: tclBasic.c,v 1.408 2009/11/16 17:38:08 ferrieux Exp $
*/
#include "tclInt.h"
@@ -530,6 +530,9 @@ Tcl_CreateInterp(void)
iPtr->errorInfo = NULL;
TclNewLiteralStringObj(iPtr->eiVar, "::errorInfo");
Tcl_IncrRefCount(iPtr->eiVar);
+ iPtr->errorStack = Tcl_NewListObj(0, NULL);
+ Tcl_IncrRefCount(iPtr->errorStack);
+ iPtr->resetErrorStack = 1;
iPtr->errorCode = NULL;
TclNewLiteralStringObj(iPtr->ecVar, "::errorCode");
Tcl_IncrRefCount(iPtr->ecVar);
@@ -1470,6 +1473,7 @@ DeleteInterpProc(
Tcl_DecrRefCount(iPtr->errorInfo);
iPtr->errorInfo = NULL;
}
+ Tcl_DecrRefCount(iPtr->errorStack);
if (iPtr->returnOpts) {
Tcl_DecrRefCount(iPtr->returnOpts);
}
@@ -8820,5 +8824,7 @@ TclInfoCoroutineCmd(
* mode: c
* c-basic-offset: 4
* fill-column: 78
+ * tab-width: 8
+ * indent-tabs-mode: nil
* End:
*/
diff --git a/generic/tclCmdIL.c b/generic/tclCmdIL.c
index 03f5593..9c89ae4 100644
--- a/generic/tclCmdIL.c
+++ b/generic/tclCmdIL.c
@@ -16,7 +16,7 @@
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: @(#) $Id: tclCmdIL.c,v 1.171 2009/08/20 10:56:55 dkf Exp $
+ * RCS: @(#) $Id: tclCmdIL.c,v 1.172 2009/11/16 17:38:08 ferrieux Exp $
*/
#include "tclInt.h"
@@ -118,6 +118,9 @@ static int InfoCompleteCmd(ClientData dummy, Tcl_Interp *interp,
int objc, Tcl_Obj *const objv[]);
static int InfoDefaultCmd(ClientData dummy, Tcl_Interp *interp,
int objc, Tcl_Obj *const objv[]);
+/* TIP #348 - New 'info' subcommand 'errorstack' */
+static int InfoErrorStackCmd(ClientData dummy, Tcl_Interp *interp,
+ int objc, Tcl_Obj *const objv[]);
/* TIP #280 - New 'info' subcommand 'frame' */
static int InfoFrameCmd(ClientData dummy, Tcl_Interp *interp,
int objc, Tcl_Obj *const objv[]);
@@ -164,6 +167,7 @@ static const EnsembleImplMap defaultInfoMap[] = {
{"complete", InfoCompleteCmd, NULL},
{"coroutine", TclInfoCoroutineCmd, NULL},
{"default", InfoDefaultCmd, NULL},
+ {"errorstack", InfoErrorStackCmd, NULL},
{"exists", TclInfoExistsCmd, TclCompileInfoExistsCmd},
{"frame", InfoFrameCmd, NULL},
{"functions", InfoFunctionsCmd, NULL},
@@ -1017,6 +1021,55 @@ InfoDefaultCmd(
/*
*----------------------------------------------------------------------
*
+ * InfoErrorStackCmd --
+ *
+ * Called to implement the "info errorstack" command that returns information
+ * about the last error's call stack. Handles the following syntax:
+ *
+ * info errorstack ?interp?
+ *
+ * Results:
+ * Returns TCL_OK if successful and TCL_ERROR if there is an error.
+ *
+ * Side effects:
+ * Returns a result in the interpreter's result object. If there is an
+ * error, the result is an error message.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static int
+InfoErrorStackCmd(
+ ClientData dummy, /* Not used. */
+ Tcl_Interp *interp, /* Current interpreter. */
+ int objc, /* Number of arguments. */
+ Tcl_Obj *const objv[]) /* Argument objects. */
+{
+ Tcl_Interp *target;
+ Interp *iPtr;
+
+ if ((objc != 1) && (objc != 2)) {
+ Tcl_WrongNumArgs(interp, 1, objv, "?interp?");
+ return TCL_ERROR;
+ }
+
+ target = interp;
+ if (objc == 2) {
+ target = Tcl_GetSlave(interp, Tcl_GetString(objv[1]));
+ if (target == NULL) {
+ return TCL_ERROR;
+ }
+ }
+
+ iPtr = (Interp *) target;
+ Tcl_SetObjResult(interp, iPtr->errorStack);
+
+ return TCL_OK;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
* TclInfoExistsCmd --
*
* Called to implement the "info exists" command that determines whether
@@ -4388,5 +4441,7 @@ SelectObjFromSublist(
* mode: c
* c-basic-offset: 4
* fill-column: 78
+ * tab-width: 8
+ * indent-tabs-mode: nil
* End:
*/
diff --git a/generic/tclEncoding.c b/generic/tclEncoding.c
index 441e099..2188256 100644
--- a/generic/tclEncoding.c
+++ b/generic/tclEncoding.c
@@ -8,7 +8,7 @@
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: @(#) $Id: tclEncoding.c,v 1.66 2009/02/10 22:49:55 nijtmans Exp $
+ * RCS: @(#) $Id: tclEncoding.c,v 1.67 2009/11/16 17:38:08 ferrieux Exp $
*/
#include "tclInt.h"
@@ -844,6 +844,9 @@ FreeEncoding(
if (encodingPtr == NULL) {
return;
}
+ if (encodingPtr->refCount<=0) {
+ Tcl_Panic("FreeEncoding: refcount problem !!!");
+ }
encodingPtr->refCount--;
if (encodingPtr->refCount == 0) {
if (encodingPtr->freeProc != NULL) {
@@ -3385,11 +3388,24 @@ EscapeFreeProc(
if (dataPtr == NULL) {
return;
}
- subTablePtr = dataPtr->subTables;
- for (i = 0; i < dataPtr->numSubTables; i++) {
- FreeEncoding((Tcl_Encoding) subTablePtr->encodingPtr);
- subTablePtr++;
- }
+ /*
+ * The subTables should be freed recursively in normal operation but not
+ * during TclFinalizeEncodingSubsystem because they are also present as a
+ * weak reference in the toplevel encodingTable (ie they don't have a +1
+ * refcount for this), and unpredictable nuking order could remove them
+ * from under the following loop's feet [Bug 2891556].
+ *
+ * The encodingsInitialized flag, being reset on entry to TFES, can serve
+ * as a "not in finalization" test.
+ */
+ if (encodingsInitialized)
+ {
+ subTablePtr = dataPtr->subTables;
+ for (i = 0; i < dataPtr->numSubTables; i++) {
+ FreeEncoding((Tcl_Encoding) subTablePtr->encodingPtr);
+ subTablePtr++;
+ }
+ }
ckfree((char *) dataPtr);
}
diff --git a/generic/tclInt.h b/generic/tclInt.h
index 0f6654b..be536a9 100644
--- a/generic/tclInt.h
+++ b/generic/tclInt.h
@@ -15,7 +15,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.445 2009/09/30 03:11:26 dgp Exp $
+ * RCS: @(#) $Id: tclInt.h,v 1.446 2009/11/16 17:38:08 ferrieux Exp $
*/
#ifndef _TCLINT
@@ -1895,6 +1895,8 @@ typedef struct Interp {
Tcl_Obj *eiVar; /* cached ref to ::errorInfo variable. */
Tcl_Obj *errorCode; /* errorCode value (now as a Tcl_Obj). */
Tcl_Obj *ecVar; /* cached ref to ::errorInfo variable. */
+ Tcl_Obj *errorStack; /* [info errorstack] value (as a Tcl_Obj). */
+ int resetErrorStack; /* controls cleaning up of ::errorStack */
int returnLevel; /* [return -level] parameter. */
/*
diff --git a/generic/tclNamesp.c b/generic/tclNamesp.c
index 94ade8f..2b9b508 100644
--- a/generic/tclNamesp.c
+++ b/generic/tclNamesp.c
@@ -23,7 +23,7 @@
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: @(#) $Id: tclNamesp.c,v 1.193 2009/09/30 03:11:26 dgp Exp $
+ * RCS: @(#) $Id: tclNamesp.c,v 1.194 2009/11/16 17:38:09 ferrieux Exp $
*/
#include "tclInt.h"
@@ -7574,7 +7574,7 @@ Tcl_LogCommandInfo(
{
register const char *p;
Interp *iPtr = (Interp *) interp;
- int overflow, limit = 150;
+ int overflow, limit = 150, len;
Var *varPtr, *arrayPtr;
if (iPtr->flags & ERR_ALREADY_LOGGED) {
@@ -7633,6 +7633,36 @@ Tcl_LogCommandInfo(
TCL_GLOBAL_ONLY);
}
}
+
+ /*
+ * TIP #348
+ */
+
+ if (Tcl_IsShared(iPtr->errorStack)) {
+ Tcl_Obj *newObj;
+
+ newObj = Tcl_DuplicateObj(iPtr->errorStack);
+ Tcl_DecrRefCount(iPtr->errorStack);
+ Tcl_IncrRefCount(newObj);
+ iPtr->errorStack = newObj;
+ }
+ Tcl_ListObjLength(interp, iPtr->errorStack, &len);
+ if (iPtr->resetErrorStack) {
+ iPtr->resetErrorStack = 0;
+ /* reset while keeping the list intrep as much as possible */
+ Tcl_ListObjReplace(interp, iPtr->errorStack, 0, len, 0, NULL);
+ len=0;
+ }
+ if (iPtr->varFramePtr != iPtr->rootFramePtr) {
+ Tcl_Obj *listPtr;
+ int result;
+ listPtr=Tcl_NewListObj(iPtr->varFramePtr->objc,
+ iPtr->varFramePtr->objv);
+ result = Tcl_ListObjReplace(interp, iPtr->errorStack, len, 0, 1, &listPtr);
+ if (result != TCL_OK) {
+ Tcl_DecrRefCount(listPtr);
+ }
+ }
}
/*
@@ -7640,5 +7670,7 @@ Tcl_LogCommandInfo(
* mode: c
* c-basic-offset: 4
* fill-column: 78
+ * tab-width: 8
+ * indent-tabs-mode: nil
* End:
*/
diff --git a/generic/tclResult.c b/generic/tclResult.c
index 921a867..3d6284e 100644
--- a/generic/tclResult.c
+++ b/generic/tclResult.c
@@ -8,7 +8,7 @@
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: @(#) $Id: tclResult.c,v 1.54 2008/12/17 16:47:38 nijtmans Exp $
+ * RCS: @(#) $Id: tclResult.c,v 1.55 2009/11/16 17:38:09 ferrieux Exp $
*/
#include "tclInt.h"
@@ -19,7 +19,7 @@
enum returnKeys {
KEY_CODE, KEY_ERRORCODE, KEY_ERRORINFO, KEY_ERRORLINE,
- KEY_LEVEL, KEY_OPTIONS, KEY_LAST
+ KEY_LEVEL, KEY_OPTIONS, KEY_ERRORSTACK, KEY_LAST
};
/*
@@ -922,6 +922,7 @@ Tcl_ResetResult(
Tcl_DecrRefCount(iPtr->errorInfo);
iPtr->errorInfo = NULL;
}
+ iPtr->resetErrorStack = 1;
iPtr->returnLevel = 1;
iPtr->returnCode = TCL_OK;
if (iPtr->returnOpts) {
@@ -1158,6 +1159,7 @@ GetKeys(void)
TclNewLiteralStringObj(keys[KEY_ERRORCODE], "-errorcode");
TclNewLiteralStringObj(keys[KEY_ERRORINFO], "-errorinfo");
TclNewLiteralStringObj(keys[KEY_ERRORLINE], "-errorline");
+ TclNewLiteralStringObj(keys[KEY_ERRORSTACK],"-errorstack");
TclNewLiteralStringObj(keys[KEY_LEVEL], "-level");
TclNewLiteralStringObj(keys[KEY_OPTIONS], "-options");
@@ -1503,6 +1505,7 @@ Tcl_GetReturnOptions(
Tcl_DictObjPut(NULL, options, keys[KEY_ERRORLINE],
Tcl_NewIntObj(iPtr->errorLine));
}
+ Tcl_DictObjPut(NULL, options, keys[KEY_ERRORSTACK], iPtr->errorStack);
return options;
}
@@ -1624,5 +1627,7 @@ Tcl_TransferResult(
* mode: c
* c-basic-offset: 4
* fill-column: 78
+ * tab-width: 8
+ * indent-tabs-mode: nil
* End:
*/
diff --git a/generic/tclTest.c b/generic/tclTest.c
index da00e84..cdaa440 100644
--- a/generic/tclTest.c
+++ b/generic/tclTest.c
@@ -14,7 +14,7 @@
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: @(#) $Id: tclTest.c,v 1.136 2009/02/10 23:09:08 nijtmans Exp $
+ * RCS: @(#) $Id: tclTest.c,v 1.137 2009/11/16 17:38:09 ferrieux Exp $
*/
#define TCL_TEST
@@ -290,6 +290,9 @@ static int TestexitmainloopCmd(ClientData dummy,
Tcl_Interp *interp, int argc, const char **argv);
static int TestpanicCmd(ClientData dummy,
Tcl_Interp *interp, int argc, const char **argv);
+static int TestfinexitObjCmd(ClientData dummy,
+ Tcl_Interp *interp, int objc,
+ Tcl_Obj *const objv[]);
static int TestparserObjCmd(ClientData dummy,
Tcl_Interp *interp, int objc,
Tcl_Obj *const objv[]);
@@ -619,6 +622,7 @@ Tcltest_Init(
Tcl_CreateObjCommand(interp, "testlocale", TestlocaleCmd, (ClientData) 0,
NULL);
Tcl_CreateCommand(interp, "testpanic", TestpanicCmd, (ClientData) 0, NULL);
+ Tcl_CreateCommand(interp, "testfinexit", TestfinexitObjCmd, (ClientData) 0, NULL);
Tcl_CreateObjCommand(interp, "testparser", TestparserObjCmd,
(ClientData) 0, NULL);
Tcl_CreateObjCommand(interp, "testparsevar", TestparsevarObjCmd,
@@ -4358,6 +4362,47 @@ TestpanicCmd(
return TCL_OK;
}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TestfinexitObjCmd --
+ *
+ * Calls a variant of [exit] including the full finalization path.
+ *
+ * Results:
+ * Error, or doesn't return.
+ *
+ * Side effects:
+ * Exits application.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static int
+TestfinexitObjCmd(
+ ClientData dummy, /* Not used. */
+ Tcl_Interp *interp, /* Current interpreter. */
+ int objc, /* Number of arguments. */
+ Tcl_Obj *const objv[]) /* Argument objects. */
+{
+ int value;
+
+ if ((objc != 1) && (objc != 2)) {
+ Tcl_WrongNumArgs(interp, 1, objv, "?returnCode?");
+ return TCL_ERROR;
+ }
+
+ if (objc == 1) {
+ value = 0;
+ } else if (Tcl_GetIntFromObj(interp, objv[1], &value) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ Tcl_Finalize();
+ TclpExit(value);
+ /*NOTREACHED*/
+ return TCL_ERROR; /* Better not ever reach this! */
+}
static int
TestfileCmd(