Skip to content

Commit 0ca087b

Browse files
committed
Merge bug-c1a376375e0e6488
2 parents d995661 + 008cd7d commit 0ca087b

File tree

9 files changed

+174
-48
lines changed

9 files changed

+174
-48
lines changed

generic/tclBasic.c

+11-9
Original file line numberDiff line numberDiff line change
@@ -2785,6 +2785,8 @@ TclCreateObjCommandInNs(
27852785
Command *refCmdPtr = oldRefPtr->importedCmdPtr;
27862786

27872787
dataPtr = (ImportedCmdData*)refCmdPtr->objClientData;
2788+
cmdPtr->refCount++;
2789+
TclCleanupCommandMacro(dataPtr->realCmdPtr);
27882790
dataPtr->realCmdPtr = cmdPtr;
27892791
oldRefPtr = oldRefPtr->nextPtr;
27902792
}
@@ -3374,7 +3376,7 @@ Tcl_GetCommandFullName(
33743376
* separator, and the command name.
33753377
*/
33763378

3377-
if (cmdPtr != NULL) {
3379+
if ((cmdPtr != NULL) && TclRoutineHasName(cmdPtr)) {
33783380
if (cmdPtr->nsPtr != NULL) {
33793381
Tcl_AppendToObj(objPtr, cmdPtr->nsPtr->fullName, -1);
33803382
if (cmdPtr->nsPtr != iPtr->globalNsPtr) {
@@ -3464,7 +3466,7 @@ Tcl_DeleteCommandFromToken(
34643466
* and skip nested deletes.
34653467
*/
34663468

3467-
if (cmdPtr->flags & CMD_IS_DELETED) {
3469+
if (cmdPtr->flags & CMD_DYING) {
34683470
/*
34693471
* Another deletion is already in progress. Remove the hash table
34703472
* entry now, but don't invoke a callback or free the command
@@ -3496,7 +3498,7 @@ Tcl_DeleteCommandFromToken(
34963498
* be ignored.
34973499
*/
34983500

3499-
cmdPtr->flags |= CMD_IS_DELETED;
3501+
cmdPtr->flags |= CMD_DYING;
35003502

35013503
/*
35023504
* Call trace functions for the command being deleted. Then delete its
@@ -3526,7 +3528,7 @@ Tcl_DeleteCommandFromToken(
35263528
}
35273529

35283530
/*
3529-
* The list of command exported from the namespace might have changed.
3531+
* The list of commands exported from the namespace might have changed.
35303532
* However, we do not need to recompute this just yet; next time we need
35313533
* the info will be soon enough.
35323534
*/
@@ -3661,7 +3663,7 @@ CallCommandTraces(
36613663
* While a rename trace is active, we will not process any more rename
36623664
* traces; while a delete trace is active we will never reach here -
36633665
* because Tcl_DeleteCommandFromToken checks for the condition
3664-
* (cmdPtr->flags & CMD_IS_DELETED) and returns immediately when a
3666+
* (cmdPtr->flags & CMD_DYING) and returns immediately when a
36653667
* command deletion is in progress. For all other traces, delete
36663668
* traces will not be invoked but a call to TraceCommandProc will
36673669
* ensure that tracePtr->clientData is freed whenever the command
@@ -5214,7 +5216,7 @@ TEOV_RunLeaveTraces(
52145216
int length;
52155217
const char *command = TclGetStringFromObj(commandPtr, &length);
52165218

5217-
if (!(cmdPtr->flags & CMD_IS_DELETED)) {
5219+
if (!(cmdPtr->flags & CMD_DYING)) {
52185220
if (cmdPtr->flags & CMD_HAS_EXEC_TRACES) {
52195221
traceCode = TclCheckExecutionTraces(interp, command, length,
52205222
cmdPtr, result, TCL_TRACE_LEAVE_EXEC, objc, objv);
@@ -6460,7 +6462,7 @@ TclNREvalObjEx(
64606462
/*
64616463
* Shimmer protection! Always pass an unshared obj. The caller could
64626464
* incr the refCount of objPtr AFTER calling us! To be completely safe
6463-
* we always make a copy. The callback takes care od the refCounts for
6465+
* we always make a copy. The callback takes care of the refCounts for
64646466
* both listPtr and objPtr.
64656467
*
64666468
* TODO: Create a test to demo this need, or eliminate it.
@@ -9513,7 +9515,7 @@ NRCoroutineCallerCallback(
95139515
SAVE_CONTEXT(corPtr->running);
95149516
RESTORE_CONTEXT(corPtr->caller);
95159517

9516-
if (cmdPtr->flags & CMD_IS_DELETED) {
9518+
if (cmdPtr->flags & CMD_DYING) {
95179519
/*
95189520
* The command was deleted while it was running: wind down the
95199521
* execEnv, this will do the complete cleanup. RewindCoroutine will
@@ -10282,7 +10284,7 @@ TclInfoCoroutineCmd(
1028210284
return TCL_ERROR;
1028310285
}
1028410286

10285-
if (corPtr && !(corPtr->cmdPtr->flags & CMD_IS_DELETED)) {
10287+
if (corPtr && !(corPtr->cmdPtr->flags & CMD_DYING)) {
1028610288
Tcl_Obj *namePtr;
1028710289

1028810290
TclNewObj(namePtr);

generic/tclCompile.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -1834,7 +1834,7 @@ CompileCmdLiteral(
18341834
bytes = TclGetStringFromObj(cmdObj, &numBytes);
18351835
cmdLitIdx = TclRegisterLiteral(envPtr, bytes, numBytes, extraLiteralFlags);
18361836

1837-
if (cmdPtr) {
1837+
if (cmdPtr && TclRoutineHasName(cmdPtr)) {
18381838
TclSetCmdNameObj(interp, TclFetchLiteral(envPtr, cmdLitIdx), cmdPtr);
18391839
}
18401840
TclEmitPush(cmdLitIdx, envPtr);

generic/tclEnsemble.c

+4-4
Original file line numberDiff line numberDiff line change
@@ -3161,7 +3161,7 @@ TclCompileEnsemble(
31613161
}
31623162

31633163
/*
3164-
* Now we've done the mapping process, can now actually try to compile.
3164+
* Now that the mapping process is done we actually try to compile.
31653165
* If there is a subcommand compiler and that successfully produces code,
31663166
* we'll use that. Otherwise, we fall back to generating opcodes to do the
31673167
* invoke at runtime.
@@ -3261,9 +3261,9 @@ TclAttemptCompileProc(
32613261

32623262
/*
32633263
* Advance parsePtr->tokenPtr so that it points at the last subcommand.
3264-
* This will be wrong, but it will not matter, and it will put the
3265-
* tokens for the arguments in the right place without the needed to
3266-
* allocate a synthetic Tcl_Parse struct, or copy tokens around.
3264+
* This will be wrong but it will not matter, and it will put the
3265+
* tokens for the arguments in the right place without the need to
3266+
* allocate a synthetic Tcl_Parse struct or copy tokens around.
32673267
*/
32683268

32693269
for (i = 0; i < depth - 1; i++) {

generic/tclExecute.c

+13-7
Original file line numberDiff line numberDiff line change
@@ -4464,7 +4464,7 @@ TEBCresume(
44644464
CoroutineData *corPtr = iPtr->execEnvPtr->corPtr;
44654465

44664466
TclNewObj(objResultPtr);
4467-
if (corPtr && !(corPtr->cmdPtr->flags & CMD_IS_DELETED)) {
4467+
if (corPtr && !(corPtr->cmdPtr->flags & CMD_DYING)) {
44684468
Tcl_GetCommandFullName(interp, (Tcl_Command) corPtr->cmdPtr,
44694469
objResultPtr);
44704470
}
@@ -4524,6 +4524,18 @@ TEBCresume(
45244524
TRACE(("\"%.30s\" => ", O2S(OBJ_AT_TOS)));
45254525
cmd = Tcl_GetCommandFromObj(interp, OBJ_AT_TOS);
45264526
if (cmd == NULL) {
4527+
goto instOriginError;
4528+
}
4529+
origCmd = TclGetOriginalCommand(cmd);
4530+
if (origCmd == NULL) {
4531+
origCmd = cmd;
4532+
}
4533+
4534+
TclNewObj(objResultPtr);
4535+
Tcl_GetCommandFullName(interp, origCmd, objResultPtr);
4536+
if (TclCheckEmptyString(objResultPtr) == TCL_EMPTYSTRING_YES ) {
4537+
Tcl_DecrRefCount(objResultPtr);
4538+
instOriginError:
45274539
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
45284540
"invalid command name \"%s\"", TclGetString(OBJ_AT_TOS)));
45294541
DECACHE_STACK_INFO();
@@ -4533,12 +4545,6 @@ TEBCresume(
45334545
TRACE_APPEND(("ERROR: not command\n"));
45344546
goto gotError;
45354547
}
4536-
origCmd = TclGetOriginalCommand(cmd);
4537-
if (origCmd == NULL) {
4538-
origCmd = cmd;
4539-
}
4540-
TclNewObj(objResultPtr);
4541-
Tcl_GetCommandFullName(interp, origCmd, objResultPtr);
45424548
TRACE_APPEND(("\"%.30s\"", O2S(OBJ_AT_TOS)));
45434549
NEXT_INST_F(1, 1, 1);
45444550
}

generic/tclInt.h

+29-9
Original file line numberDiff line numberDiff line change
@@ -1707,18 +1707,18 @@ typedef struct Command {
17071707
/*
17081708
* Flag bits for commands.
17091709
*
1710-
* CMD_IS_DELETED - Means that the command is in the process of
1710+
* CMD_DYING - If 1 the command is in the process of
17111711
* being deleted (its deleteProc is currently
17121712
* executing). Other attempts to delete the
17131713
* command should be ignored.
1714-
* CMD_TRACE_ACTIVE - 1 means that trace processing is currently
1714+
* CMD_TRACE_ACTIVE - If 1 the trace processing is currently
17151715
* underway for a rename/delete change. See the
17161716
* two flags below for which is currently being
17171717
* processed.
1718-
* CMD_HAS_EXEC_TRACES - 1 means that this command has at least one
1718+
* CMD_HAS_EXEC_TRACES - If 1 means that this command has at least one
17191719
* execution trace (as opposed to simple
17201720
* delete/rename traces) in its tracePtr list.
1721-
* CMD_COMPILES_EXPANDED - 1 means that this command has a compiler that
1721+
* CMD_COMPILES_EXPANDED - If 1 this command has a compiler that
17221722
* can handle expansion (provided it is not the
17231723
* first word).
17241724
* TCL_TRACE_RENAME - A rename trace is in progress. Further
@@ -1728,7 +1728,7 @@ typedef struct Command {
17281728
* (these last two flags are defined in tcl.h)
17291729
*/
17301730

1731-
#define CMD_IS_DELETED 0x01
1731+
#define CMD_DYING 0x01
17321732
#define CMD_TRACE_ACTIVE 0x02
17331733
#define CMD_HAS_EXEC_TRACES 0x04
17341734
#define CMD_COMPILES_EXPANDED 0x08
@@ -4960,10 +4960,30 @@ MODULE_SCOPE Tcl_PackageInitProc Procbodytest_SafeInit;
49604960
* the internal stubs, but the core can use the macro instead.
49614961
*/
49624962

4963-
#define TclCleanupCommandMacro(cmdPtr) \
4964-
if ((cmdPtr)->refCount-- <= 1) { \
4965-
ckfree(cmdPtr);\
4966-
}
4963+
#define TclCleanupCommandMacro(cmdPtr) \
4964+
do { \
4965+
if ((cmdPtr)->refCount-- <= 1) { \
4966+
ckfree(cmdPtr); \
4967+
} \
4968+
} while (0)
4969+
4970+
4971+
/*
4972+
* inside this routine crement refCount first incase cmdPtr is replacing itself
4973+
*/
4974+
#define TclRoutineAssign(location, cmdPtr) \
4975+
do { \
4976+
(cmdPtr)->refCount++; \
4977+
if ((location) != NULL \
4978+
&& (location--) <= 1) { \
4979+
ckfree(((location))); \
4980+
} \
4981+
(location) = (cmdPtr); \
4982+
} while (0)
4983+
4984+
4985+
#define TclRoutineHasName(cmdPtr) \
4986+
(cmdPtr)->hPtr != NULL
49674987

49684988
/*
49694989
*----------------------------------------------------------------

generic/tclNamesp.c

+18-16
Original file line numberDiff line numberDiff line change
@@ -1770,6 +1770,8 @@ DoImport(
17701770
TclInvokeImportedCmd, InvokeImportedNRCmd, dataPtr,
17711771
DeleteImportedCmd);
17721772
dataPtr->realCmdPtr = cmdPtr;
1773+
/* corresponding decrement is in DeleteImportedCmd */
1774+
cmdPtr->refCount++;
17731775
dataPtr->selfPtr = (Command *) importedCmd;
17741776
dataPtr->selfPtr->compileProc = cmdPtr->compileProc;
17751777
Tcl_DStringFree(&ds);
@@ -2077,6 +2079,7 @@ DeleteImportedCmd(
20772079
prevPtr->nextPtr = refPtr->nextPtr;
20782080
}
20792081
ckfree(refPtr);
2082+
TclCleanupCommandMacro(realCmdPtr);
20802083
ckfree(dataPtr);
20812084
return;
20822085
}
@@ -3888,38 +3891,37 @@ NamespaceOriginCmd(
38883891
int objc, /* Number of arguments. */
38893892
Tcl_Obj *const objv[]) /* Argument objects. */
38903893
{
3891-
Tcl_Command command, origCommand;
3894+
Tcl_Command cmd, origCmd;
38923895
Tcl_Obj *resultPtr;
38933896

38943897
if (objc != 2) {
38953898
Tcl_WrongNumArgs(interp, 1, objv, "name");
38963899
return TCL_ERROR;
38973900
}
38983901

3899-
command = Tcl_GetCommandFromObj(interp, objv[1]);
3900-
if (command == NULL) {
3902+
cmd = Tcl_GetCommandFromObj(interp, objv[1]);
3903+
if (cmd == NULL) {
3904+
goto namespaceOriginError;
3905+
}
3906+
origCmd = TclGetOriginalCommand(cmd);
3907+
if (origCmd == NULL) {
3908+
origCmd = cmd;
3909+
}
3910+
TclNewObj(resultPtr);
3911+
Tcl_GetCommandFullName(interp, origCmd, resultPtr);
3912+
if (TclCheckEmptyString(resultPtr) == TCL_EMPTYSTRING_YES ) {
3913+
Tcl_DecrRefCount(resultPtr);
3914+
namespaceOriginError:
39013915
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
39023916
"invalid command name \"%s\"", TclGetString(objv[1])));
39033917
Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "COMMAND",
39043918
TclGetString(objv[1]), NULL);
39053919
return TCL_ERROR;
39063920
}
3907-
origCommand = TclGetOriginalCommand(command);
3908-
TclNewObj(resultPtr);
3909-
if (origCommand == NULL) {
3910-
/*
3911-
* The specified command isn't an imported command. Return the
3912-
* command's name qualified by the full name of the namespace it was
3913-
* defined in.
3914-
*/
3915-
3916-
Tcl_GetCommandFullName(interp, command, resultPtr);
3917-
} else {
3918-
Tcl_GetCommandFullName(interp, origCommand, resultPtr);
3919-
}
39203921
Tcl_SetObjResult(interp, resultPtr);
39213922
return TCL_OK;
39223923
}
3924+
39233925

39243926
/*
39253927
*----------------------------------------------------------------------

generic/tclOO.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -1177,7 +1177,7 @@ ObjectNamespaceDeleted(
11771177
* freed memory.
11781178
*/
11791179

1180-
if (((Command *) oPtr->command)->flags && CMD_IS_DELETED) {
1180+
if (((Command *) oPtr->command)->flags && CMD_DYING) {
11811181
/*
11821182
* Something has already started the command deletion process. We can
11831183
* go ahead and clean up the the namespace,

generic/tclObj.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -4667,7 +4667,7 @@ SetCmdNameFromAny(
46674667
* report the failure to find the command as an error.
46684668
*/
46694669

4670-
if (cmdPtr == NULL) {
4670+
if (cmdPtr == NULL || !TclRoutineHasName(cmdPtr)) {
46714671
return TCL_ERROR;
46724672
}
46734673

0 commit comments

Comments
 (0)