Index: trunk/src/kmk/w32/winchildren.c
===================================================================
--- trunk/src/kmk/w32/winchildren.c	(revision 3181)
+++ trunk/src/kmk/w32/winchildren.c	(revision 3182)
@@ -607,4 +607,28 @@
 
 /**
+ * Closes standard handles that need closing before destruction.
+ *
+ * @param   pChild          The child (WINCHILDTYPE_PROCESS).
+ */
+static void mkWinChildcareWorkerCloseStandardHandles(PWINCHILD pChild)
+{
+    if (   pChild->u.Process.fCloseStdOut
+        && pChild->u.Process.hStdOut != INVALID_HANDLE_VALUE)
+    {
+        CloseHandle(pChild->u.Process.hStdOut);
+        pChild->u.Process.hStdOut      = INVALID_HANDLE_VALUE;
+        pChild->u.Process.fCloseStdOut = FALSE;
+    }
+    if (   pChild->u.Process.fCloseStdErr
+        && pChild->u.Process.hStdErr != INVALID_HANDLE_VALUE)
+    {
+        CloseHandle(pChild->u.Process.hStdErr);
+        pChild->u.Process.hStdErr      = INVALID_HANDLE_VALUE;
+        pChild->u.Process.fCloseStdErr = FALSE;
+    }
+}
+
+
+/**
  * Does the actual process creation given.
  *
@@ -766,19 +790,5 @@
      * Close unnecessary handles.
      */
-    if (   pChild->u.Process.fCloseStdOut
-        && pChild->u.Process.hStdOut != INVALID_HANDLE_VALUE)
-    {
-        CloseHandle(pChild->u.Process.hStdOut);
-        pChild->u.Process.hStdOut      = INVALID_HANDLE_VALUE;
-        pChild->u.Process.fCloseStdOut = FALSE;
-    }
-    if (   pChild->u.Process.fCloseStdErr
-        && pChild->u.Process.hStdErr != INVALID_HANDLE_VALUE)
-    {
-        CloseHandle(pChild->u.Process.hStdErr);
-        pChild->u.Process.hStdErr      = INVALID_HANDLE_VALUE;
-        pChild->u.Process.fCloseStdErr = FALSE;
-    }
-
+    mkWinChildcareWorkerCloseStandardHandles(pChild);
     CloseHandle(ProcInfo.hThread);
     return 0;
@@ -1019,5 +1029,6 @@
 static int mkWinChildcareWorkerConvertCommandlineWithShell(const WCHAR *pwszShell, char **papszArgs, WCHAR **ppwszCommandLine)
 {
-    return -2;
+    fprintf(stderr, "%s: not found!\n", papszArgs[0]);
+    return ERROR_FILE_NOT_FOUND;
 }
 
@@ -1025,8 +1036,9 @@
  * Searches the environment block for the PATH variable.
  *
- * @returns Pointer to the path in the block or ".".
+ * @returns Pointer to the path in the block or "." in pwszPathFallback.
  * @param   pwszzEnv            The UTF-16 environment block to search.
- */
-static const WCHAR *mkWinChildcareWorkerFindPathValue(const WCHAR *pwszzEnv)
+ * @param   pwszPathFallback    Fallback.
+ */
+static const WCHAR *mkWinChildcareWorkerFindPathValue(const WCHAR *pwszzEnv, WCHAR pwszPathFallback[4])
 {
     while (*pwszzEnv)
@@ -1040,5 +1052,7 @@
             break;
     }
-    return L".";
+    pwszPathFallback[0] = L'.';
+    pwszPathFallback[1] = L'\0';
+    return pwszPathFallback;
 }
 
@@ -1088,6 +1102,6 @@
  * @returns 0 on success, windows error code on failure.
  * @param   pszArg0         The first argument.
- * @param   pwszPath        The path if mkWinChildcareWorkerConvertEnvironment
- *                          found it.
+ * @param   pwszSearchPath  In case mkWinChildcareWorkerConvertEnvironment
+ *                          had a chance of locating the search path already.
  * @param   pwszzEnv        The environment block, in case we need to look for
  *                          the path.
@@ -1097,5 +1111,5 @@
  * @param   pfNeedShell     Where to return shell vs direct execution indicator.
  */
-static int mkWinChildcareWorkerFindImage(char const *pszArg0, WCHAR const *pwszPath, WCHAR const *pwszzEnv,
+static int mkWinChildcareWorkerFindImage(char const *pszArg0, WCHAR *pwszSearchPath, WCHAR const *pwszzEnv,
                                          const char *pszShell, WCHAR **ppwszImagePath, BOOL *pfNeedShell)
 {
@@ -1211,7 +1225,9 @@
         else
         {
-            BOOL fSearchedCwd = FALSE;
-            if (!pwszPath)
-                pwszPath = mkWinChildcareWorkerFindPathValue(pwszzEnv);
+            BOOL  fSearchedCwd = FALSE;
+            WCHAR wszPathFallback[4];
+            if (!pwszSearchPath)
+                pwszSearchPath = (WCHAR *)mkWinChildcareWorkerFindPathValue(pwszzEnv, wszPathFallback);
+
             for (;;)
             {
@@ -1225,5 +1241,5 @@
                 size_t cwcComponent = 0;
                 WCHAR  wc;
-                while ((wc = pwszPath[cwcComponent]) != L'\0')
+                while ((wc = pwszSearchPath[cwcComponent]) != L'\0')
                 {
                     if (wc != ';' && wc != ':')
@@ -1231,5 +1247,5 @@
                     else if (wc == ';')
                         break;
-                    else if (cwcComponent != pwszPath[cwcComponent] != L'"' ? 1 : 2)
+                    else if (cwcComponent != (pwszSearchPath[cwcComponent] != L'"' ? 1 : 2))
                         break;
                    cwcComponent++;
@@ -1239,7 +1255,7 @@
                 /* Trim leading spaces and double quotes. */
                 while (   cwcComponent > 0
-                       && ((wc = *pwszPath) == L'"' || wc == L' ' || wc == L'\t'))
+                       && ((wc = *pwszSearchPath) == L'"' || wc == L' ' || wc == L'\t'))
                 {
-                    pwszPath++;
+                    pwszSearchPath++;
                     cwcComponent--;
                 }
@@ -1248,5 +1264,5 @@
                 /* Trim trailing spaces & double quotes. */
                 while (   cwcComponent > 0
-                       && ((wc = pwszPath[cwcComponent - 1]) == L'"' || wc == L' ' || wc == L'\t'))
+                       && ((wc = pwszSearchPath[cwcComponent - 1]) == L'"' || wc == L' ' || wc == L'\t'))
                     cwcComponent--;
 
@@ -1262,11 +1278,13 @@
                     /* Copy the component into wszPathBuf, maybe abspath'ing it. */
                     DWORD  cwcAbsPath = 0;
-                    if (   *pwszPath != L'\\'
-                        && (pwszPath[1] != ':' || pwszPath[2] != L'\\') )
+                    if (   *pwszSearchPath != L'\\'
+                        && (pwszSearchPath[1] != ':' || pwszSearchPath[2] != L'\\') )
                     {
-                        WCHAR const wcSaved = pwszPath[cwcCombined];
-                        *(WCHAR *)&pwszPath[cwcCombined] = '\0'; /* Pointing to our converted buffer, so this is okay for now. */
-                        cwcAbsPath = GetFullPathNameW(pwszPath, MKWINCHILD_MAX_PATH, wszPathBuf, NULL);
-                        *(WCHAR *)&pwszPath[cwcCombined] = wcSaved;
+                        /* To save an extra buffer + copying, we'll temporarily modify the PATH
+                           value in our converted UTF-16 environment block.  */
+                        WCHAR const wcSaved = pwszSearchPath[cwcComponent];
+                        pwszSearchPath[cwcComponent] = L'\0';
+                        cwcAbsPath = GetFullPathNameW(pwszSearchPath, MKWINCHILD_MAX_PATH, wszPathBuf, NULL);
+                        pwszSearchPath[cwcComponent] = wcSaved;
                         if (cwcAbsPath > 0 && cwcAbsPath + 1 + cwcArg0 <= MKWINCHILD_MAX_PATH)
                             cwcCombined = cwcAbsPath + 1 + cwcArg0;
@@ -1276,5 +1294,5 @@
                     if (cwcAbsPath == 0)
                     {
-                        memcpy(wszPathBuf, pwszPath, cwcComponent);
+                        memcpy(wszPathBuf, pwszSearchPath, cwcComponent * sizeof(WCHAR));
                         cwcAbsPath = cwcComponent;
                     }
@@ -1338,5 +1356,5 @@
                  */
                 if (wcEnd != '\0')
-                    pwszPath += cwcSkip + 1;
+                    pwszSearchPath += cwcSkip + 1;
                 else if (fSearchedCwd)
                     break;
@@ -1344,5 +1362,7 @@
                 {
                     fSearchedCwd = TRUE;
-                    pwszPath = L".";
+                    wszPathFallback[0] = L'.';
+                    wszPathFallback[1] = L'\0';
+                    pwszSearchPath = wszPathFallback;
                 }
             }
@@ -1354,8 +1374,17 @@
          */
         *pfNeedShell = TRUE;
-        cwc = MultiByteToWideChar(CP_ACP, 0 /*fFlags*/, pszShell, strlen(pszShell), wszPathBuf, MKWINCHILD_MAX_PATH);
-        if (cwc > 0)
-            return mkWinChildDuplicateUtf16String(wszPathBuf, cwc, ppwszImagePath);
-        dwErr = GetLastError();
+        if (pszShell)
+        {
+            cwc = MultiByteToWideChar(CP_ACP, 0 /*fFlags*/, pszShell, strlen(pszShell) + 1, wszPathBuf, MKWINCHILD_MAX_PATH);
+            if (cwc > 0)
+                return mkWinChildDuplicateUtf16String(wszPathBuf, cwc, ppwszImagePath);
+            dwErr = GetLastError();
+            fprintf(stderr, _("MultiByteToWideChar failed to convert shell (%s): %u\n"), pszShell, dwErr);
+        }
+        else
+        {
+            fprintf(stderr, "%s: not found!\n", pszArg0);
+            dwErr = ERROR_FILE_NOT_FOUND;
+        }
     }
     else
@@ -1376,11 +1405,11 @@
  * @param   ppwszEnv        Where to return the pointer to the environment
  *                          block.
- * @param   ppwszPath       Where to return the pointer to the path value within
- *                          the environment block.  This will not be set if
- *                          cbEnvStrings is non-zero, more efficient to let
+ * @param   ppwszSearchPath Where to return the pointer to the path value
+ *                          within the environment block.  This will not be set
+ *                          if cbEnvStrings is non-zero, more efficient to let
  *                          mkWinChildcareWorkerFindImage() search when needed.
  */
 static int mkWinChildcareWorkerConvertEnvironment(char **papszEnv, size_t cbEnvStrings,
-                                                  WCHAR **ppwszEnv, WCHAR const **ppwszPath)
+                                                  WCHAR **ppwszEnv, WCHAR const **ppwszSearchPath)
 {
     DWORD  dwErr;
@@ -1389,5 +1418,5 @@
     WCHAR *pwszzDst;
 
-    *ppwszPath = NULL;
+    *ppwszSearchPath = NULL;
 
     /*
@@ -1519,5 +1548,5 @@
 
         if (offPathValue != ~(size_t)0)
-            *ppwszPath = &pwszzDst[offPathValue];
+            *ppwszSearchPath = &pwszzDst[offPathValue];
         *ppwszEnv = pwszzDst;
         return 0;
@@ -1535,10 +1564,10 @@
 static void mkWinChildcareWorkerThreadHandleProcess(PWINCHILDCAREWORKER pWorker, PWINCHILD pChild)
 {
-    WCHAR const            *pwszPath         = NULL;
-    WCHAR                  *pwszzEnvironment = NULL;
-    WCHAR                  *pwszCommandLine  = NULL;
-    WCHAR                  *pwszImageName    = NULL;
-    BOOL                    fNeedShell       = FALSE;
-    int                     rc;
+    WCHAR  *pwszSearchPath   = NULL;
+    WCHAR  *pwszzEnvironment = NULL;
+    WCHAR  *pwszCommandLine  = NULL;
+    WCHAR  *pwszImageName    = NULL;
+    BOOL    fNeedShell       = FALSE;
+    int     rc;
 
     /*
@@ -1548,5 +1577,5 @@
     rc = mkWinChildcareWorkerConvertEnvironment(pChild->u.Process.papszEnv ? pChild->u.Process.papszEnv : environ,
                                                 pChild->u.Process.cbEnvStrings,
-                                                &pwszzEnvironment, &pwszPath);
+                                                &pwszzEnvironment, &pwszSearchPath);
     /*
      * Find the executable and maybe checking if it's a shell script, then
@@ -1554,5 +1583,5 @@
      */
     if (rc == 0)
-        rc = mkWinChildcareWorkerFindImage(pChild->u.Process.papszArgs[0], pwszzEnvironment, pwszPath,
+        rc = mkWinChildcareWorkerFindImage(pChild->u.Process.papszArgs[0], pwszSearchPath, pwszzEnvironment,
                                            pChild->u.Process.pszShell, &pwszImageName, &fNeedShell);
     if (rc == 0)
@@ -1587,4 +1616,9 @@
     free(pwszImageName);
     free(pwszzEnvironment);
+
+    /* In case we failed, we must make sure the child end of pipes
+       used by $(shell no_such_command.exe) are closed, otherwise
+       the main thread will be stuck reading the parent end.  */
+    mkWinChildcareWorkerCloseStandardHandles(pChild);
 }
 
@@ -1954,18 +1988,5 @@
                 pChild->u.Process.hProcess = NULL;
             }
-            if (   pChild->u.Process.fCloseStdOut
-                && pChild->u.Process.hStdOut != INVALID_HANDLE_VALUE)
-            {
-                CloseHandle(pChild->u.Process.hStdOut);
-                pChild->u.Process.hStdOut      = INVALID_HANDLE_VALUE;
-                pChild->u.Process.fCloseStdOut = FALSE;
-            }
-            if (   pChild->u.Process.fCloseStdErr
-                && pChild->u.Process.hStdErr != INVALID_HANDLE_VALUE)
-            {
-                CloseHandle(pChild->u.Process.hStdErr);
-                pChild->u.Process.hStdErr      = INVALID_HANDLE_VALUE;
-                pChild->u.Process.fCloseStdErr = FALSE;
-            }
+            mkWinChildcareWorkerCloseStandardHandles(pChild);
             break;
         }
