Tcl Source Code

View Ticket
Login
Ticket UUID: 60559fd4a618258cceacc8d8966ea17b2ec7bc15
Title: -singleproc + coroutine-7.6 + info-23.0.1 => fail
Type: Bug Version: 8.6+
Submitter: dgp Created on: 2019-04-11 16:02:52
Subsystem: 45. Parsing and Eval Assigned To: dgp
Priority: 6 Severity: Minor
Status: Closed Last Modified: 2019-04-17 15:09:51
Resolution: Fixed Closed By: dgp
    Closed on: 2019-04-17 15:09:51
Description:
$ make test-tcl TESTFLAGS='-singleproc -file "coroutine.test info.test" -match "coroutine-7.6 info-23.0.1"'
...
==== info-23.0.1 eval'd info frame FAILED
==== Contents of test case:

    eval {info frame}

---- Result was:
13
---- Result should have been (glob matching):
1[12]
==== info-23.0.1 FAILED
User Comments: dkf added on 2019-04-11 21:41:55:

See https://core.tcl-lang.org/tcl/timeline?r=bug-60559fd4a6 for what I think the fix should be.


dkf added on 2019-04-11 21:39:09:

It's totally the epoch bump. That pushes that stack frame's evaluation engine into a state where it uses interpretation instead of compilation until the frame is purged, which is a long time away for the global stack frame in a -singleproc 1 situation (longer than in 8.5; 8.6 compiles more aggressively for good NRE-support reasons), and interpretation sees more frames in info frame than compilation.

This is evil evil evil, and not a bug that we should fix. Except for the tests being too keen on triggering the bump. The tests that cause the problem (that I've seen; there might be more) are coroutine-7.6 and coroutine-7.7.


sebres added on 2019-04-11 20:58:46:

It looks like the epoch-bump (with followed re-compilation) is indirectly responsible for this disaster:

set result {}
proc bar args {}
proc foo args {}
set BaseFrameLevel [info frame]
eval {
  lappend result [expr {[info frame] - $BaseFrameLevel}] [regexp -inline {^\S+} [dict get [info frame -1] cmd]]
  rename bar buz; ## ********** change of compileEpoch.
  lappend result [expr {[info frame] - $BaseFrameLevel}] [regexp -inline {^\S+} [dict get [info frame -1] cmd]]
  puts $result
}

set result {} eval { lappend result [expr {[info frame] - $BaseFrameLevel}] [regexp -inline {^\S+} [dict get [info frame -1] cmd]] rename buz bar; ## ********** change of compileEpoch. lappend result [expr {[info frame] - $BaseFrameLevel}] [regexp -inline {^\S+} [dict get [info frame -1] cmd]] puts $result }

So interpreter tracing is not involved.


dkf added on 2019-04-11 19:28:49:

The following test case (provisionally named) shows that this has nothing to do with coroutines. It does have plenty to do with foo having a direct compileProc (special case to allow disabling logging/asserts).

test coroutine-7.6a {Early yield crashes} -setup {
    set result {}
} -body {
    proc foo args {}
    set BaseFrameLevel [info frame]
    eval {
        lappend result [expr {[info frame] - $BaseFrameLevel}]
        trace add execution foo enter list
        lappend result [expr {[info frame] - $BaseFrameLevel}]
    }
} -cleanup {
    rename foo {}
    unset -nocomplain result BaseFrameLevel
} -result {1 1}
This is weird stuff!


dkf added on 2019-04-11 18:32:41:

Seems to be an inconsistent state somewhere. Here's an illustrative interactive session:

% info frame
1
% eval {
    proc foo args {}
    trace add execution foo enter {catch yield}
    coroutine demo foo
    rename foo {}
}
% info frame
1
% eval {
    info frame
}
2
% eval {
    proc foo args {}
    trace add execution foo enter {catch yield}
    coroutine demo foo
    rename foo {}
    info frame
}
3


dgp added on 2019-04-11 16:53:11:
Bisecting says then unhappiness starts here:

https://core.tcl-lang.org/tcl/info/0c54ff4afafe9fe2