Tcl Source Code

View Ticket
Login
Ticket UUID: da63e4c1efcfc3e68fdc4527df6a8109e1eac348
Title: Crash in Tcl_WriteChars()
Type: Bug Created on: 2022-11-16 10:16:13
Submitter: anonymous Assigned to: jan.nijtmans
Subsystem: 12. ByteArray Object Severity: Minor
Priority: 5 Medium Last modified: 2022-11-28 23:13:41
Status: Closed Closed by: jan.nijtmans
Resolution: Fixed Closed on: 2022-11-28 23:13:41
Version: 9.0a4
Description:
Tcl 9.0 crashes in Tcl_WriteChars() when calling TclDecrRefCount(copy)
(in generic/tclIO.c).  Before the crash, the Tcl_Obj *copy has the following content:

copy refcount 0
copy bytes 0x0
copy type 0x1054c77a0
copy type name bytearray

The problem happens in [1] and can be reproduced 
when compiling the tip version of NaviServer with Tcl9.0 
and running then "make test".

Adding "Tcl_IncrRefCount(copy)" after TclNarrowToBytes() helps for NaviServer 
to get past Tcl_WriteChars(), but does not solve the problem 
(as pointed out by Jan).

-gustaf

[1] https://bitbucket.org/naviserver/naviserver/src/c7b93582c076c41508dc7bf342d3fa864d3d6409/nsd/pidfile.c#lines-65
User Comments:
jan.nijtmans added on 2022-11-23 07:56:44:

See also [07563f771].

My guess is that this is introduced with TIP #568: Revise ByteArray Routines To Support Proper Value Extraction


anonymous added on 2022-11-23 08:53:24:
Hmm, the buffer passed to Tcl_WriteChars() does not look problematic to me:

[23/Nov/2022:09:51:05][14150.102ae4580][-main:conf-] Notice: buffer for Tcl_WriteChars (len 6): 31 34 31 35 30 0a

anonymous added on 2022-11-23 09:38:36:
The problem seems to be, that after

    objPtr = Tcl_NewStringObj(src, len);
    copy = TclNarrowToBytes(objPtr);

objPtr and copy point to the same Tcl_Obj, and
that after the TclDecrRefCount in

    src = (char *) Tcl_GetByteArrayFromObj(copy, &len);
    TclDecrRefCount(objPtr);

also the object pointed to by copy is cleared, such that
the final 

    TclDecrRefCount(copy);

causes the crash. So, it looks to me, that either adding 
one Tcl_IncrRefCount() or removing one of the TclDecrRefCount()
solves the issue. TclNarrowToBytes() seems to return always
the same object, or removing the first TclDecrRefCount(objPtr) seems
ok.

jan.nijtmans added on 2022-11-23 15:34:14:

First attempt for a fix [58883dde6de7f4a8|here].

Although the fix works, it shows that TIP #601 (about making encoding errors thowing exceptions) was not implemented throughout yet. For example, testcase io-1.6 does the following:

    fconfigure $f -encoding binary
    puts -nonewline $f "a乍\x00"
This is illegal, because the "binary" encoding only accepts bytes while 乍 is not a byte at all. With TIP #601, I expect this test-case to throw an exception. The solution [58883dde6de7f4a8] does this by generating this exception when converting the string to a bytearray.

What would be even better, is when "puts" would write the bytes to the channel up to the error-character (so, just 'a' in this case), and then throw the exception. That part is not done yet in this first attempt.


anonymous added on 2022-11-23 18:04:57:
I've just tested the change in Tcl_WriteChars(), and this works fine for NaviServer.

jan.nijtmans added on 2022-11-23 21:26:26:

Fix committed [3539aef815|here]. Leaving this ticket pending for possible further enhancements.


jan.nijtmans added on 2022-11-28 23:13:41:

At first sight, the use of TclNarrowToBytes() looked suspicious. Currently there's only one usage left (in "binary format"), and there it's doing exactly the right thing. Maybe not the most efficient way, but that's not enough to leave this ticket open for.

So, closing this ticket.