Tcl Source Code

View Ticket
Login
Ticket UUID: 979879
Title: file isdirectory causing variable corruption?
Type: Bug Version: obsolete: 8.4.6
Submitter: ajpasadyn Created on: 2004-06-25 17:36:03
Subsystem: 37. File System Assigned To: vincentdarley
Priority: 5 Medium Severity:
Status: Closed Last Modified: 2004-07-02 23:52:37
Resolution: Fixed Closed By: vincentdarley
    Closed on: 2004-07-02 16:52:37
Description:
After a call to "file isdirectory" certain paths no longer 
seem to exist.  I observed this with Tcl 8.4.x on Win32, 
but not with Tcl 8.3.x.  Something must be happening to 
the variable that is passed to file isdirectory.  If I make 
sure that it's just a temporary string (as in TestFind2) 
the problem does not occur.

Example:

proc TestFind1 {d f} {
    set r1 [file exists [file join $d $f]]
    puts "TF1: [file join $d $f] found: $r1"
    puts "TF1: is dir a dir? [file isdirectory $d]"
    set r2 [file exists [file join $d $f]]
    puts "TF1: [file join $d $f] found: $r2"
    puts ""
}
proc TestFind2 {d f} {
    set r1 [file exists [file join $d $f]]
    puts "TF2: [file join $d $f] found: $r1"
    puts "TF2: is dir a dir? [file isdirectory [file join $d]]"
    set r2 [file exists [file join $d $f]]
    puts "TF2: [file join $d $f] found: $r2"
    puts ""
}

file mkdir [file join a b c]
TestFind1 a [file join b . c]
TestFind2 a [file join b . c]




My output:
TF1: a/b/./c found: 1
TF1: is dir a dir? 1
TF1: a/b/./c found: 0

TF2: a/b/./c found: 1
TF2: is dir a dir? 1
TF2: a/b/./c found: 1
User Comments: vincentdarley added on 2004-07-02 23:52:37:
Logged In: YES 
user_id=32170

Backported to 8.4 branch.

vincentdarley added on 2004-06-30 21:45:34:
Logged In: YES 
user_id=32170

Checked in fix for Tcl 8.5.

Leaving open since fix still needs applying to 8.4

ajpasadyn added on 2004-06-30 03:02:57:
Logged In: YES 
user_id=1055638

That patch seems to work for me with both the 8.4 and 8.5 
versions.  I didn't try anything other than that test yet 
though, so hopefully it doesn't break anything else.

vincentdarley added on 2004-06-30 01:17:02:

File Added - 92323: winFile.patch

Logged In: YES 
user_id=32170

Here's a proposed patch for Tcl 8.5.  Something similar (if
not identical) should work for 8.4

vincentdarley added on 2004-06-29 18:31:27:
Logged In: YES 
user_id=32170

In Tcl 8.5 the problem is caused here in tclPathObj.c (line
1590):

Tcl_AppendObjToObj(copy, fsPathPtr->normPathPtr);
/* 
 * Normalize the combined string, but only starting after
 * the end of the previously normalized 'dir'.  This should
 * be much faster!  We use 'cwdLen-1' so that we are
 * already pointing at the dir-separator that we know about.
 * The normalization code will actually start off directly
 * after that separator.
 */
TclFSNormalizeToUniquePath(interp, copy, cwdLen-1, 
  (fsPathPtr->nativePathPtr == NULL ? &clientData : NULL));

where we are calling TclFSNormalizeToUniquePath contrary to
its documentation, with a string which may still contain
'./' or '../' sequences (from fsPathPtr->normPathPtr).

It's not really clear where the fix should be -- perhaps the
special 'joined' pathObj representation shouldn't be allowed
if the second part has '.' or '..' sequences, or else this
bit of code shown above should be cleverer, or else the
native normalization code should actually cope with the
existence of such sequences.

The problem occurs because the TclpObjNormalizePath routine
tries to find the 'long, unique path name' for each path
segment (one by one), and therefore turns 'a/b/./c' into
'a/b/b/c' (since the real name of '.' is 'b' in this case).
 Similar bugs exist with '..'.  

Lastly I should add that turning on 'TclNORM_LONG_PATH' in
tclWinFile.c seems to fix the problem, at least for the
cases I've tested (it activates a different version of the
normalization), but I think that other cases might still
trigger a failure.

Anyway, this is too hard for a quick fix, so it'll take me
some time (i.e. until I have some time) -- others are very
welcome to look into it.

dkf added on 2004-06-29 14:47:37:
Logged In: YES 
user_id=79902

I suspect that the work done on path normalization fixes in
the HEAD allows the fault results to propagate further, but
that the problem is not that at all.

Currently, #1 suspicion points at bad information getting
attached to the Tcl_Obj inside $d, and that this bad info is
coming from a mistake in the Win native FS.

hobbs added on 2004-06-29 03:14:24:
Logged In: YES 
user_id=72656

Confirmed that this is a bug in 8-4-head and HEAD of
2004-06-28 on Windows, but not on Linux (and that HEAD fails
with 110 110 as Vince noted).

ajpasadyn added on 2004-06-28 23:11:16:
Logged In: YES 
user_id=1055638

Just FYI: looks like 8.4.1 acts normally (111 111) and 8.4.2 is 
when the problem started showing up (110 111)

vincentdarley added on 2004-06-28 22:24:43:
Logged In: YES 
user_id=32170

I'll look into this.  I can reproduce it, so shouldn't be
too hard to solve.  Only subtlety is that it fails in
different ways on 8.4 vs 8.5 (8.4 = 110 111, 8.5 = 110 110)

dkf added on 2004-06-28 22:22:37:
Logged In: YES 
user_id=79902

BTW, the fact that it doesn't happen under Joe Mistachkin's
config might just mean that the problem is Win specific.

(It works for me with 8.4.1, but that doesn't necessarily
mean very much except for the fact that I ought to upgrade
sometime!)

dkf added on 2004-06-28 22:19:21:
Logged In: YES 
user_id=79902

Sounds offhand like something is getting cached in the
internal rep of $d that is semantics-altering.  This is
really really bad.

ajpasadyn added on 2004-06-28 21:42:09:
Logged In: YES 
user_id=1055638

My earlier tests were from the 8.4.5 and 8.4.6 releases on 
Windows 2000, using threaded builds from both msys-mingw 
and MSVC.  I just tried the same test using the 8.5a1 release 
(threaded builds on both compilers), and I got the following 
output (even worse than before):

TF1: a/b/./c found: 1
TF1: is dir a dir? 1
TF1: a/b/./c found: 0

TF2: a/b/./c found: 1
TF2: is dir a dir? 1
TF2: a/b/./c found: 0

This is really strange.  The way I found this was that I had a 
set of scripts that was assembling paths from multiple 
sources, and when I upgraded from 8.3 to 8.4 it stopped 
working.  This is the smallest test that still showed the 
problem.  

I cannot access the CVS repository from here, but this 
evening I can pull it, and I can test using Linux as well.  
Maybe this only happens on Win32.

mistachkin added on 2004-06-28 16:27:52:
Logged In: YES 
user_id=113501


Is there any way we can find out what was causing this and 
how it was fixed (in case the root problem has just been 
obscured and not really fixed)?

Submitter: Was this in a released build and if so, what build?

vincentdarley added on 2004-06-28 16:16:27:
Logged In: YES 
user_id=32170

It looks from mistachkin's comments that this, if it was a
bug, has been fixed in both 8.4 and 8.5 branches.

mistachkin added on 2004-06-28 15:38:54:
Logged In: YES 
user_id=113501

Results from NON-THREADED build of core-8-4-branch on 
FreeBSD 4.10-STABLE:

TF1: a/b/./c found: 1
TF1: is dir a dir? 1
TF1: a/b/./c found: 1

TF2: a/b/./c found: 1
TF2: is dir a dir? 1
TF2: a/b/./c found: 1

Results from THREADED build of core-8-4-branch on FreeBSD 
4.10-STABLE:

TF1: a/b/./c found: 1
TF1: is dir a dir? 1
TF1: a/b/./c found: 1

TF2: a/b/./c found: 1
TF2: is dir a dir? 1
TF2: a/b/./c found: 1

Results from NON-THREADED build of HEAD on FreeBSD 4.10-
STABLE:

TF1: a/b/./c found: 1
TF1: is dir a dir? 1
TF1: a/b/./c found: 1

TF2: a/b/./c found: 1
TF2: is dir a dir? 1
TF2: a/b/./c found: 1

Results from THREADED build of HEAD on FreeBSD 4.10-
STABLE:

TF1: a/b/./c found: 1
TF1: is dir a dir? 1
TF1: a/b/./c found: 1

TF2: a/b/./c found: 1
TF2: is dir a dir? 1
TF2: a/b/./c found: 1

Attachments: