Tcl Source Code

View Ticket
Login
Ticket UUID: 2710920
Title: [file tail] gives wrong result
Type: Bug Version: obsolete: 8.5.6
Submitter: jepler Created on: 2009-03-25 03:05:51
Subsystem: 36. Pathname Management Assigned To: dgp
Priority: 9 Immediate Severity:
Status: Closed Last Modified: 2009-03-28 05:02:23
Resolution: Fixed Closed By: dgp
    Closed on: 2009-03-27 19:20:43
Description:
This problem occurs on a freshly built 8.5.6 (unmodified) on Ubuntu Hardy and is also seen on 8.5.3-2 on ubuntu jaunty alpha (ubuntu modified).  The bug is not seen in 8.4.16-4ubuntu1 (ubuntu modified) on ubuntu hardy.

In a specific scenario involving [glob] with a trailing slash, the resulting files are treated improperly by [file tail].  An attached script, which can be run by
$ make shell SCRIPT=filetailbug.tcl
demonstrates the problem on my system.

Expected output:
 /bin bin
Actual output:
 /bin {}
User Comments: ferrieux added on 2009-03-28 05:02:23:
It hardly gets colder than that, eh ?

dgp added on 2009-03-28 04:45:39:
No; I like to limit the docs to
things I like and want to keep.

Internal details of dubious wisdom
deserve writeups sometimes, but
not in the docs.

ferrieux added on 2009-03-28 04:30:10:
Perhaps some chosen pieces of the very detailed and interesting description below could find a place in Filesystem.3 ?

dgp added on 2009-03-28 02:20:43:

allow_comments - 1


Fixed for 8.5.7 and 8.6b2

dgp added on 2009-03-28 02:04:53:

File Added - 319929: 2710920.patch

dgp added on 2009-03-28 01:47:57:
[file dirname] suffers an analogous bug.

dgp added on 2009-03-28 01:07:00:
The mystery as to why the behavior
is different whether or not the demo
script is [source]d by relative or absolute
name is complex, but explainable.

When the file name is absolute, there's
never any need to ask what the [pwd]
value is in order to open and read that
file.  In this simple test script, it happens
that nothing else needed to know that value
either, so the value of [pwd] has never
been determined.

In the innermost part of the [glob] operation,
we need to query the actual filesystem to
determine what files exist.  The routine
TclpMatchInDirectory() in tclUnixFile.c does
this, and it must construct the "native"
name of the file to do so.  It calls the
routine Tcl_FSGetNativePath() to get that
native name.  This works its way back to
the routine TclNativeCreateNativeRep()
also in tclUnixFile.c.  TNCNR has two
branches depending on whether or not
the [pwd] value is known to be in the
native filesystem.  In the case where we've
never had reason to determine [pwd]
up to that point, [pwd] is not known to
be in the native filesystem, so a less
efficient, safer path to generating the
native name is taken by normalizing the
path first.  Normalizing the path converts
it out of the intrep which triggers the bug.

On the other hand, when the pathname
of the demo script is relative, we had to
compute [pwd] just to find and source the
script, so we have the value and we know
it's in the native filesystem, so within
TNCNR we take a more efficient path to
computing the native name which also
preserves the intrep which is needed to
demo the [file tail] bug.

Perhaps more than you wanted to know,
but I figured it should be written down
somewhere.

dgp added on 2009-03-27 04:20:26:
Appears that the fix of 1972879 did
not create this bug, but just exposed it,
by permitting some otherwise untested
codepaths to execute.

Problem is that [file tail] on the
PATHFLAGS !=0 intrep for path values
is just broken when paths have trailing
separators.

dgp added on 2009-03-27 03:12:28:
The fix for Bug 1972879 is to blame.

dgp added on 2009-03-27 02:18:07:
Bug introduced between 8.5.2 and 8.5.3.

dgp added on 2009-03-27 01:19:48:
Sorry, I was misled by --enable-shared builds.

dgp added on 2009-03-27 00:58:50:
Further testing indicates that
Tcl 8.5.0 works, while 8.5.1 has
the bug.

jepler added on 2009-03-27 00:53:36:
I'm glad you found how to reproduce it!

I can confirm what dgp says: whether the script is given as an absolute path or not affects the output.

dgp added on 2009-03-27 00:47:41:
I can now reproduce the problem with Tcl 8.5.6:

$ make shell SCRIPT=fff.tcl
...
LD_LIBRARY_PATH="`pwd`:${LD_LIBRARY_PATH}"; export LD_LIBRARY_PATH; \
        TCL_LIBRARY="/home/dgp/cvs/tcl8.5.6/library"; export TCL_LIBRARY; \
        ./tclsh fff.tcl
/opt/ {}

Note that a very similar attempt yields different results:

$ make shell SCRIPT=~/fff.tcl
...
LD_LIBRARY_PATH="`pwd`:${LD_LIBRARY_PATH}"; export LD_LIBRARY_PATH; \
        TCL_LIBRARY="/home/dgp/cvs/tcl8.5.6/library"; export TCL_LIBRARY; \
        ./tclsh ~/fff.tcl
/opt/ opt

Same script in a different place and accessed via
an absolute path.  So inspired by that difference, try:

$ make shell SCRIPT=`pwd`/fff.tcl
...
LD_LIBRARY_PATH="`pwd`:${LD_LIBRARY_PATH}"; export LD_LIBRARY_PATH; \
        TCL_LIBRARY="/home/dgp/cvs/tcl8.5.6/library"; export TCL_LIBRARY; \
        ./tclsh /home/dgp/cvs/tcl8.5.6/unix/fff.tcl
/opt/ opt

jepler added on 2009-03-26 07:08:33:
I failed to correctly minimize the test case in my original submission.  Please see the attached 'fff.tcl' instead of the original attachment.

$ cat fff.tcl 
proc f {} {
    set d [glob -nocomplain /*/]
    set d [lindex $d 0]
    #set d [format %s $d]   # uncommenting this line makes both 8.4 and 8.5 work
    puts stderr [list $d [file tail $d]]
}

f

$ make shell SCRIPT=fff.tcl
LD_LIBRARY_PATH="`pwd`:${LD_LIBRARY_PATH}"; export LD_LIBRARY_PATH; \
TCL_LIBRARY="/tmp/tcl8.5.6/library"; export TCL_LIBRARY; \
./tclsh fff.tcl
/mnt/ {}
$

jepler added on 2009-03-26 07:06:19:

File Added - 319626: fff.tcl

jepler added on 2009-03-26 07:05:49:

File Deleted - 319464:

jepler added on 2009-03-25 10:07:16:
I am not familiar with the tcl path object, but I attempted to generate some useful debugging information.  I found that the 'normPathPtr' is an empty string, and that TclPathpart returns normPathPtr, leading to the result I am seeing.  Perhaps the problem is occurring earlier at the point where this path object is constructed?

Breakpoint 3, TclPathPart (interp=0x606400, pathPtr=0x62aa00, 
    portion=TCL_PATH_TAIL) at /tmp/tcl8.5.6/unix/../generic/tclPathObj.c:596
596const char *rest = TclGetString(fsPathPtr->normPathPtr);
(gdb) print fsPathPtr->translatedPathPtr->bytes
$32 = 0x636be0 "/bin"
(gdb) print fsPathPtr->normPathPtr->bytes
$33 = 0x7f2ed6902b48 ""
(gdb) next
598if (strchr(rest, '/') != NULL) {
(gdb) 
601if (tclPlatform == TCL_PLATFORM_WINDOWS
(gdb) 
605Tcl_IncrRefCount(fsPathPtr->normPathPtr);
(gdb) 
606return fsPathPtr->normPathPtr;
(gdb) 
747}
(gdb)

jepler added on 2009-03-25 10:05:52:

File Added - 319464: filetailbug.tcl

Attachments: