Tcl Source Code

View Ticket
Login
Ticket UUID: 2662380
Title: Bug in append
Type: Bug Version: obsolete: 8.5.9
Submitter: a3a3el Created on: 2009-03-04 17:01:47
Subsystem: 46. Traces Assigned To: msofer
Priority: 9 Immediate Severity:
Status: Closed Last Modified: 2011-04-13 20:36:28
Resolution: Fixed Closed By: msofer
    Closed on: 2011-04-13 13:36:28
Description:
The following can crash 8.4, 8.5 and 8.6:

  array set a [list]

  trace variable a w unset_key

  proc unset_key { var key op } {

    puts stderr "$var, $key, $op"

    global a

    if { [info exists a($key)] } {
      puts stderr "Unsetting a($key)."
      unset a($key)
    } else {
      puts stderr "Cannot unset a($key)."
    }

  }

  append a(test) one two

Since 8.4, Tcl_AppendObjCmd has stopped calling Tcl_ObjSetVar2, and calls
TclPtrSetVar instead.  However, although TclPtrSetVar returns iPtr->emptyObj if
the variable has been unset by a trace, Tcl_AppendObjCmd is still checking for
NULL, and so attempts to append the next argument.  I've attached patches for
the 8.4 and 8.5 branches, and the trunk.

Az.
User Comments: msofer added on 2011-04-13 20:36:28:

allow_comments - 1

msofer added on 2011-04-13 20:36:26:
fixed in all 3 branches

msofer added on 2011-04-12 18:39:41:
The "gross change in write traces" covers 2 cases:

* trace undefined the var: in that case, TclPtrSetVar should just clear the var and return NULL

* trace converted the var to an array: so what do we do now? What should append/set/etc return? In 8.4:

% trace add variable x write foo
% proc foo {name args} {upvar 1 $name x; unset x; set x(1) 1}
% append x 2
% set x
can't read "x": variable is array
% parray x
x(1) = 1

msofer added on 2011-04-12 09:30:37:
Crashes HEAD but not core-8-5-branch as of today. Valgrind however still dislikes it in 8.5

dgp added on 2009-04-08 21:42:01:
I modified the test script so that the "Unsetting"
messages reports the value of the variable about
to be unset.  Then testing on Tcl releases 7.6p2
and 8.3.5, I see they agree on this output:

a, test, w
Unsetting a(test) = one.
a, test, w
Unsetting a(test) = two.

Without thinking too deeply about it, 
I admit, that output also makes sense
to me.  [append] can operate on
a name of a non-existent variable,
creating the variable by making the
appending write to it.  Write traces
come after the writing, so at that point
the variable exists, and the trace can
unset it.  We end up back where we
started with no existing variable.
Multiple arguments to append
just means we repeat the cycle.

Appears this report is exposing some
flaws in some of the varName resolution
caching machinery that's come in releases
8.4 and later.

Fixing that right may take some time
and thought (*), and since it appears the
claims of "crashes" are incorrect, I'll
leave this one to come back to.

The submitted patches may well be the
right answer, I'm not sure yet, but the
flaws exposed are broader and deeper,
so I'd prefer to be more certain about a
more complete fix.

(*) or at least some input from msofer. :)

dgp added on 2009-04-08 20:32:48:
Relevant tests:
append-7.1
appendComp-7.1
namespace-8.6
trace-16.8,9,10,13,14

dgp added on 2009-04-08 02:25:39:
I see no crash.

On 8.4 I see:

a, test, w
Unsetting a(test).
a, test, w
Cannot unset a(test).

On Tcl 8.5 and HEAD I see an uncaught errors,
but not always the same one (!).  Either :

a, test, w
Unsetting a(test).
can't set "a(test)": upvar refers to element in deleted array
    while executing
"append a(test) one two"
    (file "/home/dgp/2662380.tcl" line 20)

or this:

a, test, w
Unsetting a(test).
can't set "a(test)": upvar refers to variable in deleted namespace
    while executing
"append a(test) one two"
    (file "/home/dgp/2662380.tcl" line 20)

dkf added on 2009-04-05 00:34:36:

data_type - 110894

a3a3el added on 2009-03-05 00:02:24:

File Added - 316178: tclVar-trunk.diff

File Added: tclVar-trunk.diff

a3a3el added on 2009-03-05 00:02:08:

File Added - 316176: tclVar-8.5.diff

File Added: tclVar-8.5.diff

a3a3el added on 2009-03-05 00:01:47:

File Added - 316175: tclVar-8.4.diff

Attachments: