summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsebres <sebres@users.sourceforge.net>2017-07-14 14:21:43 (GMT)
committersebres <sebres@users.sourceforge.net>2017-07-14 14:21:43 (GMT)
commit08bbcf33b65844d919ba4c58e0dcebd1fd330702 (patch)
treea1b684ccd31286c0a4ff273219bda27619f47cf9
parentba36e5644b01038e11624290850803281b18ece1 (diff)
downloadtcl-fix_8_5_578155d5a19b348d.zip
tcl-fix_8_5_578155d5a19b348d.tar.gz
tcl-fix_8_5_578155d5a19b348d.tar.bz2
stability fix: try to avoid segfault using released object, in error case of Tcl_ObjSetVar2, if newValuePtr self-released during set (lookup, by rewriting of interpreter state with error, by trace call, etc.), see ticket [578155d5a19b348d].fix_8_5_578155d5a19b348d
TODO: this is minimalist version of fix, so check this can be sane rewritten using something like flag TCL_OWN_OBJREF as suggested in ticket [578155d5a19b348d].
-rw-r--r--generic/tclVar.c16
1 files changed, 13 insertions, 3 deletions
diff --git a/generic/tclVar.c b/generic/tclVar.c
index e540c49..50df93e 100644
--- a/generic/tclVar.c
+++ b/generic/tclVar.c
@@ -1740,6 +1740,7 @@ Tcl_ObjSetVar2(
* TCL_LEAVE_ERR_MSG. */
{
Var *varPtr, *arrayPtr;
+ int newValRefCnt = newValuePtr->refCount; /* save original refCount */
/*
* Filter to pass through only the flags this interface supports.
@@ -1750,7 +1751,15 @@ Tcl_ObjSetVar2(
varPtr = TclObjLookupVarEx(interp, part1Ptr, part2Ptr, flags, "set",
/*createPart1*/ 1, /*createPart2*/ 1, &arrayPtr);
if (varPtr == NULL) {
- if (newValuePtr->refCount == 0) {
+ /*
+ * Free newValuePtr only if it had previously no references (otherwise
+ * the pointer newValRefCnt may be already released (during lookup,
+ * by rewriting of interpreter state with error, by trace call, etc.)
+ *
+ * TODO: check this can be sane rewritten using something like flag
+ * TCL_OWN_OBJREF as suggested in ticket [578155d5a19b348d].
+ */
+ if (newValRefCnt == 0) { /* not set and no other references */
Tcl_DecrRefCount(newValuePtr);
}
return NULL;
@@ -1807,6 +1816,7 @@ TclPtrSetVar(
Interp *iPtr = (Interp *) interp;
Tcl_Obj *oldValuePtr;
Tcl_Obj *resultPtr = NULL;
+ int newValRefCnt = newValuePtr->refCount; /* save original refCount */
int result;
/*
@@ -1921,7 +1931,7 @@ TclPtrSetVar(
Tcl_IncrRefCount(oldValuePtr); /* Since var is ref */
}
Tcl_AppendObjToObj(oldValuePtr, newValuePtr);
- if (newValuePtr->refCount == 0) {
+ if (newValRefCnt == 0) { /* not set and no other references */
Tcl_DecrRefCount(newValuePtr);
}
}
@@ -1981,7 +1991,7 @@ TclPtrSetVar(
return resultPtr;
earlyError:
- if (newValuePtr->refCount == 0) {
+ if (newValRefCnt == 0) { /* not set and no other references */
Tcl_DecrRefCount(newValuePtr);
}
goto cleanup;