tclmagic.c: memleak Tcl ref counting over Eval memory leak

API docs indicate the original usage seems ok.
Calling Tcl_GetIndexFromObj() is allowed with a refcount == 0.
But in actual usage it leaks the Tcl_NewStringObj() memory across the
Tcl_EvalObjv() call like the object accounting system doesn't work on
that anymore (because the use of Tcl_EvalObjv() disrupted things).

Looking at the code nearby it increments refs (for all recently created
objs) and decrements around Tcl_EvalEx() for the actual data the 'eval'
needs pinned and is working on.

If we just repeat this same pattern but with 'objv0' the memory leak is
gone.  The decrement must wake it up / make it remember what to do.
So this required covering all the exit paths to decrement as well.
This commit is contained in:
Darryl L. Miles 2025-02-26 13:41:13 +00:00 committed by R. Timothy Edwards
parent 7029971c33
commit 142b7e5a78
1 changed files with 10 additions and 0 deletions

View File

@ -369,6 +369,7 @@ _tcl_dispatch(ClientData clientData,
if (!strncmp(argv0, "::", 2)) argv0 += 2;
objv0 = Tcl_NewStringObj(argv0, strlen(argv0));
Tcl_IncrRefCount(objv0); /* this seems needed to ensure it is freed across Tcl_EvalObjv() */
if (Tcl_GetIndexFromObj(interp, objv0, (const char **)conflicts,
"overloaded command", 0, &idx) == TCL_OK)
{
@ -396,7 +397,10 @@ _tcl_dispatch(ClientData clientData,
Tcl_Free((char *)objv);
if (result == TCL_OK)
{
Tcl_DecrRefCount(objv0);
return result;
}
/* The rule is to execute Magic commands for any Tcl command */
/* with the same name that returns an error. However, this */
@ -420,11 +424,17 @@ _tcl_dispatch(ClientData clientData,
slashptr++;
if ((dotptr = strrchr(slashptr, '.')) != NULL)
{
if (strcmp(dotptr + 1, "mag") && strcmp(dotptr + 1, "gz"))
{
Tcl_DecrRefCount(objv0);
return result;
}
}
}
}
}
Tcl_DecrRefCount(objv0);
Tcl_ResetResult(interp);
if (TxInputRedirect == TX_INPUT_REDIRECTED)