Tcl Source Code

View Ticket
Login
Ticket UUID: 057b7dbd3d558921a9b1f33268035521ec39e6b3
Title: Const-folding by Expression Compiler borks Ensemble rewrite machinery
Type: Bug Version: 8.7a6
Submitter: aku Created on: 2021-12-01 21:13:37
Subsystem: 47. Bytecode Compiler Assigned To: nobody
Priority: 5 Medium Severity: Minor
Status: Open Last Modified: 2021-12-01 21:13:37
Resolution: None Closed By: nobody
    Closed on:
Description:
Wrt version: Already present in 8.6.10. Possibly earlier.

This started with a `this is weird` moment when in the testsuite of a personal project the error message for a wrong#args invokation of a (oo::util) classmethod for a class in an ensemble command was not of the expected form, with the command properly rewritten.

Using the demo script I reduced this to the invokation

	::x point validate

which got
reported as	  wrong # args: should be "::x::point validate x"
instead of 	  wrong # args: should be "x point validate x"

I found that I was able to get the correct message by changing the body of the classmethod from

     expr {$z <= -1}
to   expr {$z <= 1}
or   expr {$z <= $z}

While I initially suspected a memory corruption issue both builtin memory debugging and valgrind were clean. I tracked the issue then down to `ExecConstantExprTree` (ECET).

The good cases (`1`, `$z`) do not invoke it. The `-1` however is actually an unary `-` operating on `1`, i.e. something which can and is const-folded.

As part of this ECET essentially compiles the expression to byte code and then invokes `TclNRExecuteByteCode` (TNEBC) to get the const result to put into the outer bytecode.

The problem is, this touches on the machinery for rewriting ensembles in error messages. Specifically, we get additional calls to `TclResetRewriteEnsemble` (TRRE), and this messes with the data structures already set up by the dispatcher for `x point` before compilation happened.

In the good cases nothing can be const folded, neither TNEBC nor TRRE are called, the rewrite data structures are left in a good state, and the message is as expected.

From my look at things I believe that ECET has to save/restore the rewrite machinery state before and after it invokes TNEBC to make things good again.

Note: While debugging and tracing this issue was done for Tcl 8.7a6,
commit `010d43daee` the initial issue was seen with 8.6.10.

Attached a zip file containing:

  - Demo script good case `weird-good.tcl`, plus output `GOOD`.
  - Demo script good case `weird-bad.tcl`, plus output `BAD`

  - My changes to commit `010d43daee` as `TRACE.patch`.
    I.e. printf's added as investigation zeroed in.
    Present only to enable reproduction of the logs, if needed.

  - `PushMethodCallFrame` was found by stepping through things in gdb
    because it was unclear where exactly the bogus TRRE calls got
    triggered.

The important parts of GOOD and BAD are found after the marker line

`________________________________________________________________/////////`

You can clearly see the additional TRRE in the BAD case, and how it got called from the const-folding code.

Attachments: