@@ -930,7 +930,7 @@ nothrow:
930930 }
931931
932932 /* *****************************************
933- * Return canonical version of name in a malloc'd buffer .
933+ * Return canonical version of name.
934934 * This code is high risk.
935935 */
936936 extern (C++ ) static const (char )* canonicalName(const (char )* name)
@@ -975,14 +975,16 @@ nothrow:
975975 char [PATH_MAX ] buf = void ;
976976 auto path = name.toCStringThen! ((n) => realpath(n.ptr, buf.ptr));
977977 if (path ! is null )
978- return mem.xstrdup (path) .toDString;
978+ return xarraydup (path.toDString) ;
979979 }
980980 else static if (__traits(compiles, canonicalize_file_name))
981981 {
982982 // Have canonicalize_file_name, which malloc's memory.
983+ // We need a dmd.root.rmem allocation though.
983984 auto path = name.toCStringThen! ((n) => canonicalize_file_name(n.ptr));
985+ scope (exit) .free(path.ptr);
984986 if (path ! is null )
985- return path.toDString;
987+ return xarraydup ( path.toDString) ;
986988 }
987989 else static if (__traits(compiles, _PC_PATH_MAX))
988990 {
@@ -994,14 +996,14 @@ nothrow:
994996 scope (exit) mem.xfree(buf);
995997 auto path = name.toCStringThen! ((n) => realpath(n.ptr, buf));
996998 if (path ! is null )
997- return mem.xstrdup (path) .toDString;
999+ return xarraydup (path.toDString) ;
9981000 }
9991001 }
10001002 // Give up trying to support this platform, just duplicate the filename
10011003 // unless there is nothing to copy from.
10021004 if (! name.length)
10031005 return null ;
1004- return mem.xstrdup (name.ptr)[ 0 .. name.length] ;
1006+ return xarraydup (name) ;
10051007 }
10061008 else version (Windows )
10071009 {
@@ -1011,18 +1013,18 @@ nothrow:
10111013 /* Apparently, there is no good way to do this on Windows.
10121014 * GetFullPathName isn't it, but use it anyway.
10131015 */
1014- // First find out how long the buffer has to be.
1015- const fullPathLength = GetFullPathNameW(&wname[0 ], 0 , null , null );
1016- if (! fullPathLength ) return null ;
1017- auto fullPath = ( cast (wchar * ) mem.xmalloc_noscan((fullPathLength + 1 ) * wchar .sizeof))[ 0 .. fullPathLength + 1 ] ;
1018- scope (exit) mem.xfree(fullPath.ptr );
1019-
1020- // Actually get the full path name
1021- const length = GetFullPathNameW(
1022- &wname[0 ], cast ( DWORD ) fullPath.length, &fullPath[ 0 ] , null /* filePart*/ );
1023- assert (length == fullPathLength );
1024-
1025- return toNarrowStringz (fullPath [0 .. length]);
1016+ // First find out how long the buffer has to be, incl. terminating null .
1017+ const capacity = GetFullPathNameW(&wname[0 ], 0 , null , null );
1018+ if (! capacity ) return null ;
1019+ auto buffer = cast (wchar * ) mem.xmalloc_noscan(capacity * wchar .sizeof);
1020+ scope (exit) mem.xfree(buffer );
1021+
1022+ // Actually get the full path name. If the buffer is large enough,
1023+ // the returned length does NOT include the terminating null...
1024+ const length = GetFullPathNameW( &wname[0 ], capacity , buffer , null /* filePart*/ );
1025+ assert (length == capacity - 1 );
1026+
1027+ return toNarrowStringz (buffer [0 .. length]);
10261028 });
10271029 }
10281030 else
@@ -1031,6 +1033,15 @@ nothrow:
10311033 }
10321034 }
10331035
1036+ unittest
1037+ {
1038+ string filename = " foo.bar" ;
1039+ const path = canonicalName(filename);
1040+ scope (exit) free (path.ptr);
1041+ assert (path.length >= filename.length);
1042+ assert (path[$ - filename.length .. $] == filename);
1043+ }
1044+
10341045 /* *******************************
10351046 * Free memory allocated by FileName routines
10361047 */
0 commit comments