This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
allow ext/XS-APItest/t/win32.t to pass with both E: and T: drives
authorTony Cook <tony@develop-help.com>
Wed, 1 Jun 2016 07:23:05 +0000 (17:23 +1000)
committerTony Cook <tony@develop-help.com>
Wed, 1 Jun 2016 07:23:24 +0000 (17:23 +1000)
Encountered while testing locally on Windows 7 x64.

cmd.exe stores the current directory for each drive as entries in the
environment, like:

  C:\Users\tony>set "" | findstr "^="
  =::=::\
  =C:=C:\Users\tony
  =D:=D:\ASM1061

When a Win32 build of perl built with USE_IMP_SYS starts up it saves
the current directories of each drive in a per-thread structure so
that each pseudo-forked process can have it's own set of drive current
directories.

If you run an external command, some versions of cmd.exe will add
an entry to the environment storing the result of that command, for
example:

  C:\Users\tony>set "" | find "ExitCode"

  C:\Users\tony>git status
  fatal: Not a git repository (or any of the parent directories): .git

  C:\Users\tony>set "" | find "ExitCode"
  =ExitCode=00000080

which is similar to the current directory entries.

The sloppy parsing by VDir::FromEnv[WA]() would treat that as a
current directory entry for the E: drive, copying the "tCode=...."
into the current directory.  Normally these values include a leading
drive letter and \, like "E:\", but this case leaves us without that.

Later, when harness spawns the child process it builds a new environment
block, including the drive current directories, which is done by
VDir::BuildEnvironmentSpace().  This, rather than using the index of
the drive to build the "=C:=..." entries above, uses the first
letter of the stored entry, so the environment block would have
something like:

  t:=tCode=00000080

which the child perl would treat as the current directory for the T:
drive.

win32/vdir.h

index b5c6bc6..9ff225e 100644 (file)
@@ -203,7 +203,8 @@ int VDir::SetDirA(char const *pPath, int index)
 void VDir::FromEnvA(char *pEnv, int index)
 {   /* gets the directory for index from the environment variable. */
     while (*pEnv != '\0') {
-       if ((pEnv[0] == '=') && (DriveIndex(pEnv[1]) == index)) {
+       if ((pEnv[0] == '=') && (DriveIndex(pEnv[1]) == index)
+            && pEnv[2] == ':' && pEnv[3] == '=') {
            SetDirA(&pEnv[4], index);
            break;
        }
@@ -215,7 +216,8 @@ void VDir::FromEnvA(char *pEnv, int index)
 void VDir::FromEnvW(WCHAR *pEnv, int index)
 {   /* gets the directory for index from the environment variable. */
     while (*pEnv != '\0') {
-       if ((pEnv[0] == '=') && (DriveIndex((char)pEnv[1]) == index)) {
+       if ((pEnv[0] == '=') && (DriveIndex((char)pEnv[1]) == index)
+            && pEnv[2] == ':' && pEnv[3] == '=') {
            SetDirW(&pEnv[4], index);
            break;
        }