#23 Tclvfs crash on Win2000 - Crash in TclIO.c

closed-fixed
9
2004-07-15
2004-07-02
No

I wrote a very simple vfs that mounts a virtual
directory which does nothing but redirect all access to
a specified real directory. I was using Windows
ActiveState ActiveTcl 8.4.1.0 with tclvfs 1.0.

When I opened file for writing, then immediately closed
it, tcl crashed (the file was created in the real
directory). Debugging showed that it crashed on the
actual close statement, not in any of my code.

I installed tclvfs 1.1 from sourceforge, and to my
distress I found that now the crash occurs on opening
the file rather than closing. Debugging shows that the
crash occurs before my handler proc is ever reached.

Discussion

  • Stephen Huntley

    Stephen Huntley - 2004-07-06

    Logged In: YES
    user_id=128673

    I just installed ActiveState 8.4.6.1 on my win2000 machine
    and tried using my vfs, and found that Tcl still crashes on
    attempt to close a file opened for writing.

     
  • Stephen Huntley

    Stephen Huntley - 2004-07-06

    template vfs causes crash on close

     
  • Stephen Huntley

    Stephen Huntley - 2004-07-06

    Logged In: YES
    user_id=128673

    I am uploading the vfs I am attempting to use. I wrote it
    as a learning exercise; it does nothing but redirect file
    accesses in a virtual fs to a real location. Usage:

    ::vfs::template Mount <real directory> <virtual directory>

    I used:
    ::vfs::template Mount C:/temp /template

     
  • Stephen Huntley

    Stephen Huntley - 2004-07-06

    Logged In: YES
    user_id=128673

    To reproduce the bug:

    source templatevfs.tcl
    ::vfs::template::Mount C:/temp /template
    cd /template
    set f [open test.txt w]
    puts $f hello
    close $f

    Tcl crashes on the close command.

     
  • Vince Darley

    Vince Darley - 2004-07-06

    Logged In: YES
    user_id=32170

    With Tcl 8.5a2 and latest cvs head of tclvfs 1.3, this works
    for me and does not crash.

    However, with Tcl8.4 cvs branch and tclvfs 1.3, it does
    crash, and the crash is here in tclIO.c:

    static int
    DetachChannel(interp, chan)
    Tcl_Interp *interp; /* Interpreter in which channel is
    defined. */
    Tcl_Channel chan; /* Channel to delete. */
    {
    Tcl_HashTable *hTblPtr; /* Hash table of channels. */
    Tcl_HashEntry *hPtr; /* Search variable. */
    Channel *chanPtr; /* The real IO channel. */
    ChannelState *statePtr; /* State of the real channel. */

    /*
    * Always (un)register bottom-most channel in the stack.
    This makes
    * management of the channel list easier because no
    manipulation is
    * necessary during (un)stack operation.
    */
    chanPtr = ((Channel *) chan)->state->bottomChanPtr;

    where ((Channel *)chan)->state appears to be nonsense, and
    in fact the entire 'chan' structure appears to have been
    freed already. I don't know where this means this bug is,
    but given that the same version (same binary) of tclvfs is
    used in both cases, I have to think the bug is in Tcl, and
    in particular in tclIO.c or related code. Could you
    therefore please report it against the Tcl project?

    Thanks for the detailed report and test scripts which
    allowed easy reproducibility. Unfortunately someone with
    more IO knowledge will have to debug it.

    I'll assign this to Andreas, since he actually knows the IO
    stuff well.

    (Note: testing above done not with ActiveTcl but with direct
    builds of Tcl 8.4, 8.5, tclvfs from the source trees).

     
  • Vince Darley

    Vince Darley - 2004-07-06
    • assigned_to: nobody --> andreas_kupries
     
  • Andreas Kupries

    Andreas Kupries - 2004-07-08
    • labels: --> Vfs Extension
    • priority: 5 --> 9
    • summary: Tclvfs crash on Win2000 --> Tclvfs crash on Win2000 - Crash in TclIO.c
     
  • Andreas Kupries

    Andreas Kupries - 2004-07-08

    Logged In: YES
    user_id=75003

    Using the provided code I was able to generate the crash on
    Linux as well. I just replaced 'c:\' with [pwd] to get a
    unix path instead of a windows one. Stacktrace:

    #0 0x40061ee0 in HashStringKey () from
    /home/andreask/tdk31/lib/libtcl8.4.so
    #1 0x400617c6 in Tcl_FindHashEntry () from
    /home/andreask/tdk31/lib/libtcl8.4.so
    #2 0x40064ddf in DetachChannel () from
    /home/andreask/tdk31/lib/libtcl8.4.so
    #3 0x40064d8e in Tcl_DetachChannel () from
    /home/andreask/tdk31/lib/libtcl8.4.so
    #4 0x401e3487 in VfsCloseProc () from
    /home/andreask/tdk31/lib/vfs1.3/libvfs1.3.so
    #5 0x40065ba1 in Tcl_Close () from
    /home/andreask/tdk31/lib/libtcl8.4.so
    #6 0x40064d33 in Tcl_UnregisterChannel () from
    /home/andreask/tdk31/lib/libtcl8.4.so
    #7 0x4006b042 in Tcl_CloseObjCmd () from
    /home/andreask/tdk31/lib/libtcl8.4.so
    #8 0x400356dd in TclEvalObjvInternal () from
    /home/andreask/tdk31/lib/libtcl8.4.so
    #9 0x4003602f in Tcl_EvalEx () from
    /home/andreask/tdk31/lib/libtcl8.4.so
    #10 0x4006dcdd in Tcl_FSEvalFile () from
    /home/andreask/tdk31/lib/libtcl8.4.so

     
  • Andreas Kupries

    Andreas Kupries - 2004-07-08

    Logged In: YES
    user_id=75003

    Side note. In other words, this has nothing to do with the
    crash. It is however a problem to trip over in the future:

    A number of places use

    return "$cmd [file join $root $relative] $mode"

    to return a command callback. That should be

    return [list $cmd [file join $root $relative] $mode]

    The list ensures that spaces in [file join $root $relative],
    and any other parts are properly quoted.

    Hm. I wonder. Why is anything returned at all. The result of
    'createdirectory' for example is ignored. Ditto
    'deletefile', 'utime', and 'access'. This could be a
    documentation issue.

     
  • Andreas Kupries

    Andreas Kupries - 2004-07-15

    Logged In: YES
    user_id=75003

    > Debugging showed that it crashed on the actual close
    statement, not in any of my code.

    This part is something I cannot confirm. For me the crash
    does happen in your close handler for the open file.

    Attached a modified crash.tcl file, and modified templatevfs.tcl
    I basically added some output statements in various places
    (The handler entry, and close handler entry).

    I also have a statement in the central Tcl_Close of the core.

    I get the following output (snipped stuff at the head about
    other channels):

    TH
    (/nfs/crimper/home/andreask/activetcl/dbn/wb/iocrash/temp)
    (stat) (/template) () (/template) -- ()
    TH
    (/nfs/crimper/home/andreask/activetcl/dbn/wb/iocrash/temp)
    (access) (/template) () (/template) -- (4)
    TH
    (/nfs/crimper/home/andreask/activetcl/dbn/wb/iocrash/temp)
    (open) (/template) (test.txt) (test.txt) -- (w) (438)
    file4 {::vfs::template::Close file4
    /nfs/crimper/home/andreask/activetcl/dbn/wb/iocrash/temp
    /template test.txt test.txt}
    ===================================================
    Tcl_Close(0x804c6a8,0x80a5218)
    CL (file4)
    (/nfs/crimper/home/andreask/activetcl/dbn/wb/iocrash/temp)
    (/template) (test.txt) (test.txt)
    Tcl_Close(0x804c6a8,0x80a5218)
    Segmentation fault (core dumped)

    The first Tcl_Close is the 'close $f' in your 'crash.tcl'
    script. This detaches the channel, calls the VFS layer. The
    VFS layers goes into the TclvFS layer. This finds a callback
    for the channel, and calls it. This prints the line "CL
    (file4) ...". In this callback you are _closing the channel
    again_. While it is already more or less dead. So a crash is
    not surprising.

    If you look at the 'do_close' in vfs/mk4vfs.tcl you will see
    that a limited set of operations is still possible on the
    channel, namely seeking and reading. Care was taken to make
    this possible, because the channel may contain data to save
    somewhere else and we have to be able to get at the data
    before the channel is completely gone. This is actually the
    reson behind the close callback. It is not for you to close
    the channel, but to get notified when it closes so that you
    can do last-minute things with it. Note that this callback
    is optional. In the case of template I guess that it is not
    needed.

    Now what is suprising is that 8.5 is not crashing on us as well.

    Oh, oh. Vince. Try this with 8.5 and you will see less
    output than with 8.4. It seems that in 8.5 the vfs handler
    is not called for 'open', nor for 'close'. That explains why
    it doesn't crash. The new mystery is why the handler is not
    called. This could be a bug in the tcl core vfs layer. Given
    that is was changed lots between 8.4 and 8.5.

    I've attached the log outputs for both.

    My final conclusions are

    1) The original bug is bug in the implementation
    of the 'template' fs.

    2) This bug is partially facilitated by not making it
    excruiatingly clear that [close] is not allowed in the
    'close' callback.

    The doc (vfs-fsapi) says:

    "If present the specified callback will be evaluated by the
    generic filesystem
    layer just before the channel whose handle was returned as
    the first element
    of the list is closed"

    and then goes on talking about seeking, reading, etc. like
    I did above.
    The latter may cloud the fact that the channel is in
    closing already
    and that no close is required.

    The sentence quoted above could get an emphasis as well on
    "just before the channel ... is closed".

    I recommened to rephrase and extend the documentation
    regarding this point.

    3) We possibly have bugs in Tcl 8.5, in the vfs layer, which
    prevent tclvfs
    from working.

     
  • Andreas Kupries

    Andreas Kupries - 2004-07-15

    Logged In: YES
    user_id=75003

    Extended the documentation to clarify that the 'close'
    command must not be used in the close callback. The crash
    will be fixed in the tcl core.

     
  • Andreas Kupries

    Andreas Kupries - 2004-07-15
    • status: open --> closed-fixed
     

Log in to post a comment.