summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordgp <dgp@users.sourceforge.net>2014-02-06 22:48:34 (GMT)
committerdgp <dgp@users.sourceforge.net>2014-02-06 22:48:34 (GMT)
commit5c88f32139644538542058b07833e3731af7be18 (patch)
treeaeb499092f019306364aa6075eab104c484306f5
parent1d139334be18bced5b3d4d6b1117e47696032f07 (diff)
parent32a6fce0618ed21d85cf47b4b842ea9ee2c0c2e6 (diff)
downloadtcl-5c88f32139644538542058b07833e3731af7be18.zip
tcl-5c88f32139644538542058b07833e3731af7be18.tar.gz
tcl-5c88f32139644538542058b07833e3731af7be18.tar.bz2
[a4494e28ed] Use flag bit instead of NULL pointer to suppress
teardown list of imported commands when the original command gets re-created. This prevents the panic otherwise possible when the invalid state represented by the NULL pointer is encountered during a command delete trace.
-rw-r--r--generic/tclBasic.c39
-rw-r--r--generic/tclInt.h1
-rw-r--r--tests/namespace.test9
3 files changed, 39 insertions, 10 deletions
diff --git a/generic/tclBasic.c b/generic/tclBasic.c
index 46b532b..2a334c4 100644
--- a/generic/tclBasic.c
+++ b/generic/tclBasic.c
@@ -2085,10 +2085,19 @@ Tcl_CreateCommand(
*/
cmdPtr = Tcl_GetHashValue(hPtr);
- oldRefPtr = cmdPtr->importRefPtr;
- cmdPtr->importRefPtr = NULL;
+ cmdPtr->refCount++;
+ if (cmdPtr->importRefPtr) {
+ cmdPtr->flags |= CMD_REDEF_IN_PROGRESS;
+ }
Tcl_DeleteCommandFromToken(interp, (Tcl_Command) cmdPtr);
+
+ if (cmdPtr->flags & CMD_REDEF_IN_PROGRESS) {
+ oldRefPtr = cmdPtr->importRefPtr;
+ cmdPtr->importRefPtr = NULL;
+ }
+ TclCleanupCommandMacro(cmdPtr);
+
hPtr = Tcl_CreateHashEntry(&nsPtr->cmdTable, tail, &isNew);
if (!isNew) {
/*
@@ -2272,10 +2281,19 @@ Tcl_CreateObjCommand(
* intact.
*/
- oldRefPtr = cmdPtr->importRefPtr;
- cmdPtr->importRefPtr = NULL;
+ cmdPtr->refCount++;
+ if (cmdPtr->importRefPtr) {
+ cmdPtr->flags |= CMD_REDEF_IN_PROGRESS;
+ }
Tcl_DeleteCommandFromToken(interp, (Tcl_Command) cmdPtr);
+
+ if (cmdPtr->flags & CMD_REDEF_IN_PROGRESS) {
+ oldRefPtr = cmdPtr->importRefPtr;
+ cmdPtr->importRefPtr = NULL;
+ }
+ TclCleanupCommandMacro(cmdPtr);
+
hPtr = Tcl_CreateHashEntry(&nsPtr->cmdTable, tail, &isNew);
if (!isNew) {
/*
@@ -3117,12 +3135,13 @@ Tcl_DeleteCommandFromToken(
* commands were created that refer back to this command. Delete these
* imported commands now.
*/
-
- for (refPtr = cmdPtr->importRefPtr; refPtr != NULL;
- refPtr = nextRefPtr) {
- nextRefPtr = refPtr->nextPtr;
- importCmd = (Tcl_Command) refPtr->importedCmdPtr;
- Tcl_DeleteCommandFromToken(interp, importCmd);
+ if (!(cmdPtr->flags & CMD_REDEF_IN_PROGRESS)) {
+ for (refPtr = cmdPtr->importRefPtr; refPtr != NULL;
+ refPtr = nextRefPtr) {
+ nextRefPtr = refPtr->nextPtr;
+ importCmd = (Tcl_Command) refPtr->importedCmdPtr;
+ Tcl_DeleteCommandFromToken(interp, importCmd);
+ }
}
/*
diff --git a/generic/tclInt.h b/generic/tclInt.h
index 7da0b7f..2aa1725 100644
--- a/generic/tclInt.h
+++ b/generic/tclInt.h
@@ -1686,6 +1686,7 @@ typedef struct Command {
#define CMD_TRACE_ACTIVE 0x2
#define CMD_HAS_EXEC_TRACES 0x4
#define CMD_COMPILES_EXPANDED 0x8
+#define CMD_REDEF_IN_PROGRESS 0x10
/*
*----------------------------------------------------------------
diff --git a/tests/namespace.test b/tests/namespace.test
index f6688f1..8c4b81c 100644
--- a/tests/namespace.test
+++ b/tests/namespace.test
@@ -558,6 +558,15 @@ test namespace-13.1 {DeleteImportedCmd, deletes imported cmds} {
lappend l [info commands ::test_ns_import::*]
}
} {::test_ns_import::cmd1 {}}
+test namespace-13.2 {DeleteImportedCmd, Bug a4494e28ed} {
+ # Will panic if still buggy
+ namespace eval src {namespace export foo; proc foo {} {}}
+ namespace eval dst {namespace import [namespace parent]::src::foo}
+ trace add command src::foo delete \
+ "[list namespace delete [namespace current]::dst] ;#"
+ proc src::foo {} {}
+ namespace delete src
+} {}
test namespace-14.1 {TclGetNamespaceForQualName, absolute names} {
catch {namespace delete {*}[namespace children :: test_ns_*]}