Tcl Source Code

View Ticket
Login
Ticket UUID: 2152286
Title: TCL_RETURN causes TclUpdateReturnInfo() to panic
Type: Bug Version: obsolete: 8.5.4
Submitter: fadib Created on: 2008-10-07 22:39:05
Subsystem: 45. Parsing and Eval Assigned To: dgp
Priority: 7 High Severity:
Status: Closed Last Modified: 2008-10-20 02:55:59
Resolution: Fixed Closed By: dgp
    Closed on: 2008-10-19 19:55:59
Description:
Please see the attached testcase (tcltest.tar.gz)

Problem Analysis:
----------------
The problem happens when a C function calls a TCL proc that calls a C function that returns TCL_RETURN, this causes returnLevel to be decremented all the way to 0 causing TclUpdateReturnInfo() to panic.

Testcase:
--------
 + (tcltest.c): main() calls CProcCmd() function which is a C function with a TCL wrapper.
 + CProcCmd() calls tclproc (tcltest.tcl) which calls CProcCmd() again.
 + CProcCmd() returns TCL_RETURN which makes TCL panic.

Workarounds:
-----------
There are two workarounds that I can use to make the testcase work (uncomment either line 25 or 28 in tcltest.c):

+ Workaround 1 (line 25): 
Explicitly increment returnLevel before returning TCL_RETURN.

+ Workaround 2 (line 28): 
Call a dummy tcl proc before returning TCL_RETURN. This works because it forces the returllevel to be incremented once and thus stops it from ever reaching 0.
User Comments: dgp added on 2008-10-20 02:55:59:
committed for 8.5.6 and 8.6b1

dgp added on 2008-10-20 02:50:55:
even simpler patch attached.
File Added: 2152286.patch

dgp added on 2008-10-20 02:50:54:

File Added - 297976: 2152286.patch

dgp added on 2008-10-20 02:31:47:
diff -u -r1.139.2.3 tclProc.c
--- generic/tclProc.c   11 Aug 2008 19:01:59 -0000      1.139.2.3
+++ generic/tclProc.c   19 Oct 2008 19:30:06 -0000
@@ -2245,6 +2245,10 @@
        if (code == TCL_ERROR) {
            iPtr->flags |= ERR_LEGACY_COPY;
        }
+       if (code != TCL_RETURN) {
+           iPtr->returnLevel = 1;
+           iPtr->returnCode = TCL_OK;
+       }
     }
     return code;
 }

dgp added on 2008-10-20 02:27:31:
Ok, none of my last comment
is wrong, exactly, but it
did miss the point.  Whether
or not C code calling Tcl
should do what the demo does, it's
now apparent that a small,
simple, safe change to Tcl
itself will permit it to
tolerate such code, and that's
good for all.

Testing that change now...

dgp added on 2008-10-20 01:52:36:
The error here is in the evaluation
of [cproc 1].  With a single argument
the branch is taken that evaluates
[tclproc].  If you examine the return
code from that Tcl_Eval(), you will
find that it is TCL_OK.  The command
[tclproc] has run successfully.

You then turn around and originate a
TCL_RETURN return code, without
dealing with the fact that an
intervening Tcl_Eval() has taken
the interp out of the reset state
it had when it entered CProcCmd.

There are a number of ways to
fix the code, depending on just
what it is this code is intended
to do.  That is not clear at all
from the example, which feels 
contrived to demo the conditions
for panic, more than directed
toward any rational purpose.  That's
fine; that's often true of bug
demos, but leaves me without any
context to choose what alternative
might make sense.

If you have a Tcl_ObjCmdProc that
will return TCL_RETURN, you should
either do that with the interp
still in its original reset state,
or do that after something you called
also returned TCL_RETURN (the "pass
along the exception" case), or take
care to call Tcl_SetReturnOptions()
to set the relevant options as needed
for your command (the "I'm originating
TCL_RETURN for my own purposes" case).

It seems to me the panic is serving
exactly the purpose intended, to call
attention to C code that's not robust
or safe so it can get corrected.

Note that your workarounds are just
tricky indirect ways to take my advice.
Explicit returnLevel increment is just
a sneaky "probe the internals" way to
accomplish what a proper Tcl_SetReturnOptions()
call would do.  The dummy proc call is just
a very indirect way to call the
Tcl_ResetResult() you need to get the
interp back to an initial state where
simple return of TCL_RETURN will cause
no trouble.

Hope that helps.  I'll keep this report
pending in case you want to comment
further or seek advice.

dgp added on 2008-10-17 04:51:25:
A quick attempt to patch up that
flaw does not resolve the issue, 
so I'll examine further.  In the meantime,
do not confuse the coding of 
procs, which push CallFrames, and
non-proc commands, which do not.

dgp added on 2008-10-17 04:48:03:
The flaw here is in the CProcCmd()
routine.  Several places in that routine
Tcl_Eval is called on some script, but
the return code is not checked.  If you
were to check it, you would find the
value to be TCL_RETURN, which is typically
an indication that you should not just
continue normally.  Your code continues
normally.

fadib added on 2008-10-08 05:50:00:

File Deleted - 296502: 

Please use the .zip file

msofer added on 2008-10-08 05:48:37:
That file seems to be corrupt:

mig@oli:/tmp$ tar -ztf /tmp/tcltest.tar.gz 
tar: This does not look like a tar archive
tar: Skipping to next header
tar: Error exit delayed from previous errors

fadib added on 2008-10-08 05:47:23:

File Added - 296503: tcltest.zip

File Added: tcltest.zip

fadib added on 2008-10-08 05:43:21:

File Deleted - 296501: 



File Added - 296502: tcltest.tar.gz

File Added: tcltest.tar.gz

fadib added on 2008-10-08 05:39:05:

File Added - 296501: tcltest.tar.gz

Attachments: