View Ticket
Not logged in
Ticket UUID: 580808121389182456a680e5323ea346ac30e567
Title: "string length" converts bytearrays to strings when traced
Type: Bug Version: 8.6.7
Submitter: tomkiti Created on: 2017-11-22 15:44:55
Subsystem: 12. ByteArray Object Assigned To: dgp
Priority: 5 Medium Severity: Minor
Status: Closed Last Modified: 2017-11-30 17:33:12
Resolution: Fixed Closed By: sebres
    Closed on: 2017-11-30 17:33:12
Description:
When "string length" is traced, it converts a bytearray argument to a string. This happens when the the trace operation is either enterstep or leavestep, but not enter or leave. This behavior does not occur in Tcl 8.5.

Script:

    proc p {} {
        set x [binary format x]
        puts [::tcl::unsupported::representation $x]
        string length $x
        puts [::tcl::unsupported::representation $x]
    }
    
    proc traceProc {args} {}
    
    trace add execution p enterstep traceProc
    p

Output:
    value is a bytearray with a refcount of 2, object pointer at 00000000003847A0, internal representation 0000000000399860:0000000000384740, string representation " "
    value is a string with a refcount of 2, object pointer at 00000000003847A0, internal representation 000000000039AF40:0000000000384740, string representation " "
User Comments: sebres added on 2017-11-30 17:33:12:
> The completion of the solution is taking shape on the dgp-properbytearray branch...

I know, but ...

> to be merged to trunk/9.0 after TIP approval.

This meant almost "never" (well rather said "too late" in production), if we look how fast the new things are released.

dgp added on 2017-11-30 17:13:50:
sebres, the 8.7 solution is a new Tcl_ObjType that properly records bytearrays only for values that are sequences of bytes.

The completion of the solution is taking shape on the dgp-properbytearray branch, to be merged to trunk/9.0 after TIP approval.

dgp added on 2017-11-30 17:11:33:
Fixed for 8.6.8.

sebres added on 2017-11-30 17:08:49:
> After the string rep is generated, the bytearray is no longer "pure" so it becomes worthless 

That's why I always said: we need by byte-arrays the same flag like "canonical" by lists.
The current "pure" solution works only until the first time the string representation is built.

dgp added on 2017-11-30 16:24:51:
The misbehavior is fixed in 8.7a because the partial work un-breaking ByteArrays is already done there, and for this particular problem, that is enough.

dgp added on 2017-11-30 16:22:23:
Sorry again. we're not working with an empty string, but a string of 1 NUL character, which has a two-byte string rep.

dgp added on 2017-11-30 16:14:02:
The tracing forces generation of a string rep.

After the string rep is generated, the bytearray is no longer "pure" so it becomes worthless (Insert Standard Rant here), and can no longer take optimized paths in Tcl_GetCharLength() to prevent the shimmer to "string" type.

In this particular case, the string in question is the empty string.

The misbehavior does not happen in Tcl 8.7 because an additional optimization for strings of less than 2 bytes has been added.  I have no qualms about backporting that small, obviously correct bit of code.

See dgp-properbytearry branch for work toward making ByteArrays not be broken as designed anymore, but that's a Tcl 9 fix.

All that said, it's also possible that the defects of non-pure bytearray values don't actually get in the way of getting a correct value out of Tcl_GetCharLength().

dgp added on 2017-11-30 16:07:56:
Well, that was a nice theory, but it's false. stay tuned.

dgp added on 2017-11-30 15:51:36:
You're seeing a difference between bytecompiled [string length] and direct eval [string length] because tracing prevents compiling of proc bodies.

This is fixed in 8.7a where the multiple [string length] implementations have all been refactored into a single common routine.

That refactoring could conceivably be backported to the 8.6 branch, with the usual risk/reward dilemma.  My gut says don't do it, since we don't make shimmering promises anyway, but my feelings aren't set in stone.