Tcl Source Code

View Ticket
Login
Ticket UUID: 615043
Title: various execution trace issues
Type: Bug Version: obsolete: 8.4.1
Submitter: vincentdarley Created on: 2002-09-26 16:29:25
Subsystem: 18. Commands M-Z Assigned To: dgp
Priority: 5 Medium Severity:
Status: Closed Last Modified: 2003-01-17 18:26:58
Resolution: Fixed Closed By: vincentdarley
    Closed on: 2003-01-17 11:26:58
Description:
Under some circumstances, when idle events are 
pending, execution traces with 'enterstep' 
and 'leavestep' do not trace these events.

The attached script shows the problem.  It runs two 
different scenarios of tracing 'foo':

proc foo {} {
    msg "hi"
    set a 1
}

foo

after idle {puts idle} ; foo

The first of these works correctly, but the second 
one skips three commands that should be traced --
 these three events never occur:

    {msg hi} 0 {} leavestep
    {set a 1} enterstep
    {set a 1} 0 1 leavestep

This is on Windows, but the code is entirely generic.

---
# script starts here

proc msg {txt} {
    set a [::msgcat::mc $txt]
    update idletasks
}

proc foo {} {
    msg "hi"
    set a 1
}

proc log {args} {
    puts [string range $args 0 40]
}

trace add execution foo {enter leave enterstep 
leavestep} log

puts stderr "tracing without any idletasks"
puts stderr "notice how there is a line '{msg hi} 0 {} 
leavestep'"
update
foo

puts stderr "tracing with idletask"
after idle {puts idle} ; foo

puts stderr "Notice how in the second run, the 
following lines"
puts stderr "are missing {
    {msg hi} 0 {} leavestep
    {set a 1} enterstep
    {set a 1} 0 1 leavestep
}"
User Comments: vincentdarley added on 2003-01-17 18:26:58:
Logged In: YES 
user_id=32170

I've done the necessary cleanup, I believe, and will commit
asap.

vincentdarley added on 2002-10-15 23:17:11:
Logged In: YES 
user_id=32170

I've committed Hemang's patch, but left this report 
open with a different title, since Hemang indicates 
below that there are further issues which ought to be 
cleaned up in the future.

hemanglavana added on 2002-10-15 00:31:10:
Logged In: YES 
user_id=81875

I created a patch [ 623143 ], but I see that Vince has
already attached the patch file here. So [ 623143 ] may be
closed.

hemanglavana added on 2002-10-15 00:22:28:
Logged In: YES 
user_id=81875

I looked into the code section questioned by  DGP.
TclTraceExecutionObjCmd() calls Tcl_TraceCommand  and passes
on execution flags to it as well as TraceCommandProc as its
trace handler. The Tcl_TraceCommand function has been
modified to register the execution flags. However, this is
not correct since such changes were not mentioned in tip62.
 Also, the current trace handler is completely ignored --
correct trace handler should have been TraceExecutionProc
whose call is hard-coded in TclCheckExecutionTraces.

I will create a patch soon for fixing the above problems:
the changes made to Tcl_TraceCommand, Tcl_UntraceCommand and
Tcl_CommandTraceInfo for execution traces should be moved
into new internal functions. Moreover a new tip will be
required to expose the functionality of execution traces as
C APIs: Tcl_TraceExecution, Tcl_UntraceExecution, and
Tcl_ExecutionTraceInfo.

Next, I have created a patch for the original problem
submitted here. It includes fixes to tclCmdMZ.c file and a
shorter script to reproduce the problem as a testcase in
trace.test. I am including the patch here since the upload
button doesn't show up in my browser:

Index: generic/tclCmdMZ.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclCmdMZ.c,v
retrieving revision 1.76
diff -r1.76 tclCmdMZ.c
49c49,54
<     int startLevel;             /* Used for bookkeeping
with execution traces */
---
>     int startLevel;             /* Used for bookkeeping
with step execution
>                                  * traces, store the level
at which the step
>                                  * trace was invoked */
>     char *startCmd;             /* Used for bookkeeping
with step execution
>                                  * traces, store the
command name which invoked
>                                  * step trace */
3189a3195
>               tcmdPtr->startCmd = NULL;
3238a3245,3247
>                             if (tcmdPtr->startCmd != NULL) {
>                               ckfree((char
*)tcmdPtr->startCmd);
>                           }
3390a3400
>               tcmdPtr->startCmd = NULL;
3965a3976,3978
>             if (tcmdPtr->startCmd != NULL) {
>               ckfree((char *)tcmdPtr->startCmd);
>           }
4292c4305,4306
<        * created an interpreter trace, we remove it
---
>        * created an interpreter trace for enterstep and/or
leavestep
>          * execution traces, we remove it here.
4295c4309,4310
<           if ((tcmdPtr->stepTrace != NULL) && (level ==
tcmdPtr->startLevel)) {
---
>           if ((tcmdPtr->stepTrace != NULL) && (level ==
tcmdPtr->startLevel)
>                 && (strcmp(command, tcmdPtr->startCmd) ==
0)) {
4297a4313,4315
>                 if (tcmdPtr->startCmd != NULL) {
>                   ckfree((char *)tcmdPtr->startCmd);
>               }
4299d4316
<           
4384,4385c4401,4406
<        * Third, create an interpreter trace, if we need
one for
<        * subsequent internal execution traces.
---
>        * Third, if there are any step execution traces for
this proc,
>          * we register an interpreter trace to invoke
enterstep and/or
>        * leavestep traces.
>        * We also need to save the current stack level and
the proc
>          * string in startLevel and startCmd so that we
can delete this
>          * interpreter trace when it reaches the end of
this proc.
4389a4411,4413
>               tcmdPtr->startCmd = 
>                   (char *) ckalloc((unsigned)
(strlen(command) + 1));
>               strcpy(tcmdPtr->startCmd, command);
4398a4423,4425
>             if (tcmdPtr->startCmd != NULL) {
>               ckfree((char *)tcmdPtr->startCmd);
>           }
Index: tests/trace.test
===================================================================
RCS file: /cvsroot/tcl/tcl/tests/trace.test,v
retrieving revision 1.22
diff -r1.22 trace.test
1840a1841,1870
> test trace-28.1 {enterstep and leavestep traces with
update idletasks (615043)} {
>     catch {rename foo {}}
>     proc foo {} {
>         set a 1
>         update idletasks
>         set b 1
>     }
> 
>     set info {}
>     trace add execution foo {enter enterstep leavestep
leave} \
>         [list traceExecute foo]
>     update
>     after idle {puts idle}
>     foo
> 
>     trace remove execution foo {enter enterstep leavestep
leave} \
>         [list traceExecute foo]
>     rename foo {}
>     join $info "\n"
> } {foo foo enter
> foo {set a 1} enterstep
> foo {set a 1} 0 1 leavestep
> foo {update idletasks} enterstep
> foo {puts idle} enterstep
> foo {puts idle} 0 {} leavestep
> foo {update idletasks} 0 {} leavestep
> foo {set b 1} enterstep
> foo {set b 1} 0 1 leavestep
> foo foo 0 1 leave}
> 
1845a1876,1878
> 
> # Unset the varaible when done
> catch {unset info}

vincentdarley added on 2002-10-15 00:17:51:

File Added - 33063: trace.cdiff

Logged In: YES 
user_id=32170

Attached the patch for Hemang.

dgp added on 2002-10-14 23:35:20:
Logged In: YES 
user_id=80530

Thanks for looking into this.
Could you post the patch
to the Tcl Patch Tracker?

hemanglavana added on 2002-10-14 22:30:47:
Logged In: YES 
user_id=81875

I looked into the code section questioned by  DGP.
TclTraceExecutionObjCmd() calls Tcl_TraceCommand  and passes
on execution flags to it as well as TraceCommandProc as its
trace handler. The Tcl_TraceCommand function has been
modified to register the execution flags. However, this is
not correct since such changes were not mentioned in tip62.
 Also, the current trace handler is completely ignored --
correct trace handler should have been TraceExecutionProc
whose call is hard-coded in TclCheckExecutionTraces.

I will create a patch soon for fixing the above problems:
the changes made to Tcl_TraceCommand, Tcl_UntraceCommand and
Tcl_CommandTraceInfo for execution traces should be moved
into new internal functions. Moreover a new tip will be
required to expose the functionality of execution traces as
C APIs: Tcl_TraceExecution, Tcl_UntraceExecution, and
Tcl_ExecutionTraceInfo.

Next, I have created a patch for the original problem
submitted here. It includes fixes to tclCmdMZ.c file and a
shorter script to reproduce the problem as a testcase in
trace.test. I am including the patch here since the upload
button doesn't show up in my browser:

Index: generic/tclCmdMZ.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclCmdMZ.c,v
retrieving revision 1.76
diff -r1.76 tclCmdMZ.c
49c49,54
<     int startLevel;             /* Used for bookkeeping
with execution traces */
---
>     int startLevel;             /* Used for bookkeeping
with step execution
>                                  * traces, store the level
at which the step
>                                  * trace was invoked */
>     char *startCmd;             /* Used for bookkeeping
with step execution
>                                  * traces, store the
command name which invoked
>                                  * step trace */
3189a3195
>               tcmdPtr->startCmd = NULL;
3238a3245,3247
>                             if (tcmdPtr->startCmd != NULL) {
>                               ckfree((char
*)tcmdPtr->startCmd);
>                           }
3390a3400
>               tcmdPtr->startCmd = NULL;
3965a3976,3978
>             if (tcmdPtr->startCmd != NULL) {
>               ckfree((char *)tcmdPtr->startCmd);
>           }
4292c4305,4306
<        * created an interpreter trace, we remove it
---
>        * created an interpreter trace for enterstep and/or
leavestep
>          * execution traces, we remove it here.
4295c4309,4310
<           if ((tcmdPtr->stepTrace != NULL) && (level ==
tcmdPtr->startLevel)) {
---
>           if ((tcmdPtr->stepTrace != NULL) && (level ==
tcmdPtr->startLevel)
>                 && (strcmp(command, tcmdPtr->startCmd) ==
0)) {
4297a4313,4315
>                 if (tcmdPtr->startCmd != NULL) {
>                   ckfree((char *)tcmdPtr->startCmd);
>               }
4299d4316
<           
4384,4385c4401,4406
<        * Third, create an interpreter trace, if we need
one for
<        * subsequent internal execution traces.
---
>        * Third, if there are any step execution traces for
this proc,
>          * we register an interpreter trace to invoke
enterstep and/or
>        * leavestep traces.
>        * We also need to save the current stack level and
the proc
>          * string in startLevel and startCmd so that we
can delete this
>          * interpreter trace when it reaches the end of
this proc.
4389a4411,4413
>               tcmdPtr->startCmd = 
>                   (char *) ckalloc((unsigned)
(strlen(command) + 1));
>               strcpy(tcmdPtr->startCmd, command);
4398a4423,4425
>             if (tcmdPtr->startCmd != NULL) {
>               ckfree((char *)tcmdPtr->startCmd);
>           }
Index: tests/trace.test
===================================================================
RCS file: /cvsroot/tcl/tcl/tests/trace.test,v
retrieving revision 1.22
diff -r1.22 trace.test
1840a1841,1870
> test trace-28.1 {enterstep and leavestep traces with
update idletasks (615043)} {
>     catch {rename foo {}}
>     proc foo {} {
>         set a 1
>         update idletasks
>         set b 1
>     }
> 
>     set info {}
>     trace add execution foo {enter enterstep leavestep
leave} \
>         [list traceExecute foo]
>     update
>     after idle {puts idle}
>     foo
> 
>     trace remove execution foo {enter enterstep leavestep
leave} \
>         [list traceExecute foo]
>     rename foo {}
>     join $info "\n"
> } {foo foo enter
> foo {set a 1} enterstep
> foo {set a 1} 0 1 leavestep
> foo {update idletasks} enterstep
> foo {puts idle} enterstep
> foo {puts idle} 0 {} leavestep
> foo {update idletasks} 0 {} leavestep
> foo {set b 1} enterstep
> foo {set b 1} 0 1 leavestep
> foo foo 0 1 leave}
> 
1845a1876,1878
> 
> # Unset the varaible when done
> catch {unset info}

dkf added on 2002-10-11 16:31:40:
Logged In: YES 
user_id=79902

The docs definitely need work. Whether or not that is the
only pending task in this area is another matter...

dgp added on 2002-10-11 01:03:13:
Logged In: YES 
user_id=80530

I'm confused by TclTraceExecutionObjCmd().
It appears to call Tcl_TraceCommand to get
the basic job done, passing it flags like
TCL_TRACE_ENTER_EXEC.

However, Tcl_TraceCommand is documented
to accept only the flags TCL_TRACE_RENAME
or TCL_TRACE_DELETE.  Is the documentation
just lagging behind?

The trace handler registered on line 3197 is
TraceCommandProc, and it appears to handle
only rename and delete traces.

What am I missing?

nobody added on 2002-10-11 00:10:01:
Logged In: NO 

I believe Hemang is looking into this one (could 
someone perhaps add him as a maintainer to Tcl's 
sourceforge project, so we can assign bugs to him?)

dgp added on 2002-10-10 22:54:02:
Logged In: YES 
user_id=80530

the leavestep for [update idletasks] is missing too.

vincentdarley added on 2002-09-26 23:29:25:

File Added - 31859: traceExecBug.tcl

Attachments: