Changeset 3196 in kBuild
- Timestamp:
- Mar 27, 2018 7:47:42 PM (7 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/kmk/w32/winchildren.c
r3195 r3196 172 172 /** Set if core was dumped. */ 173 173 int fCoreDumped; 174 /** Set if the a child process is a candidate for cl.exe where we supress 175 * annoying source name output. */ 176 BOOL fProbableClExe; 174 177 175 178 /** Type specific data. */ … … 268 271 /** Set if we've got a read pending already. */ 269 272 BOOL fReadPending; 273 /** Indicator that we've written out something. This is cleared before 274 * we start catching output from a new child and use in the CL.exe 275 * supression heuristics. */ 276 BOOL fHaveWrittenOut; 270 277 /** Number of bytes at the start of the buffer that we've already 271 278 * written out. We try write out whole lines. */ … … 641 648 static void mkWinChildcareWorkerFlushUnwritten(PWINCHILD pChild, PWINCCWPIPE pPipe) 642 649 { 643 DWORD cbUnwritten = pPipe->cbWritten - pPipe->offPendingRead; 650 DWORD cbUnwritten = pPipe->offPendingRead - pPipe->cbWritten; 651 assert(pPipe->cbWritten <= pPipe->cbBuffer - 16); 652 assert(pPipe->offPendingRead <= pPipe->cbBuffer - 16); 644 653 if (cbUnwritten) 645 654 { … … 658 667 pPipe->cbWritten += cbWritten <= cbUnwritten ? cbWritten : cbUnwritten; /* paranoia */ 659 668 } 660 } 669 pPipe->fHaveWrittenOut = TRUE; 670 } 671 } 672 673 /** 674 * This logic mirrors kwSandboxConsoleFlushAll. 675 * 676 * @returns TRUE if it looks like a CL.EXE source line, otherwise FALSE. 677 * @param pPipe The pipe. 678 * @param offStart The start of the output in the pipe buffer. 679 * @param offEnd The end of the output in the pipe buffer. 680 */ 681 static BOOL mkWinChildcareWorkerIsClExeSourceLine(PWINCCWPIPE pPipe, DWORD offStart, DWORD offEnd) 682 { 683 if (offEnd < offStart + 2) 684 return FALSE; 685 if (offEnd - offStart > 80) 686 return FALSE; 687 688 if ( pPipe->pbBuffer[offEnd - 2] != '\r' 689 || pPipe->pbBuffer[offEnd - 1] != '\n') 690 return FALSE; 691 692 offEnd -= 2; 693 while (offEnd-- > offStart) 694 { 695 char ch = pPipe->pbBuffer[offEnd]; 696 if (isalnum(ch) || ch == '.' || ch == ' ' || ch == '_' || ch == '-') 697 { /* likely */ } 698 else 699 return FALSE; 700 } 701 702 return TRUE; 661 703 } 662 704 … … 675 717 DWORD offStart = pPipe->cbWritten; 676 718 assert(offStart <= pPipe->offPendingRead); 719 assert(offStart <= pPipe->cbBuffer - 16); 720 assert(pPipe->offPendingRead <= pPipe->cbBuffer - 16); 677 721 if (cbNewData > 0) 678 722 { … … 692 736 /* If none were found and we've less than 16 bytes left in the buffer, try 693 737 find a word boundrary to flush on instead. */ 694 if ( offRest > offStart 695 || pPipe->cbBuffer - pPipe->offPendingRead + offStart > 16) 696 { /* likely */ } 697 else 738 if ( offRest <= offStart 739 && pPipe->cbBuffer - pPipe->offPendingRead + offStart < 16) 698 740 { 699 741 offRest = pPipe->offPendingRead; … … 704 746 offRest = pPipe->offPendingRead; 705 747 } 748 /* If this is a potential CL.EXE process, we will keep the source 749 filename unflushed and maybe discard it at the end. */ 750 else if ( pChild->fProbableClExe 751 && pPipe->iWhich == 1 752 && offRest == pPipe->offPendingRead 753 && mkWinChildcareWorkerIsClExeSourceLine(pPipe, offStart, offRest)) 754 offRest = offStart; 755 706 756 if (offRest > offStart) 707 757 { … … 726 776 } 727 777 } 778 pPipe->fHaveWrittenOut = TRUE; 728 779 } 729 780 } … … 745 796 * @param pChild The child. 746 797 * @param pPipe The pipe. 747 * @param f Flushing Set if we're flushing the pipe after the process798 * @param fDraining Set if we're draining the pipe after the process 748 799 * terminated. 749 800 */ 750 static void mkWinChildcareWorkerCatchOutput(PWINCHILD pChild, PWINCCWPIPE pPipe, BOOL f Flushing)801 static void mkWinChildcareWorkerCatchOutput(PWINCHILD pChild, PWINCCWPIPE pPipe, BOOL fDraining) 751 802 { 752 803 /* … … 756 807 { 757 808 DWORD cbRead = 0; 758 if (GetOverlappedResult(pPipe->hPipeMine, &pPipe->Overlapped, &cbRead, !f Flushing))809 if (GetOverlappedResult(pPipe->hPipeMine, &pPipe->Overlapped, &cbRead, !fDraining)) 759 810 { 760 811 mkWinChildcareWorkerCaughtMoreOutput(pChild, pPipe, cbRead); 761 812 pPipe->fReadPending = FALSE; 762 813 } 763 else if (fFlushing && GetLastError() == ERROR_IO_INCOMPLETE) 764 { 765 if (pPipe->offPendingRead > pPipe->cbWritten) 766 mkWinChildcareWorkerFlushUnwritten(pChild, pPipe); 814 else if (fDraining && GetLastError() == ERROR_IO_INCOMPLETE) 767 815 return; 768 }769 816 else 770 817 { 771 818 fprintf(stderr, "warning: GetOverlappedResult failed: %u\n", GetLastError()); 772 819 pPipe->fReadPending = FALSE; 773 if (f Flushing)820 if (fDraining) 774 821 return; 775 822 } … … 807 854 808 855 /** 856 * Makes sure the output pipes are drained and pushed to output. 857 * 858 * @param pWorker The worker. 859 * @param pChild The child. 860 */ 861 static void mkWinChildcareWorkerDrainPipes(PWINCHILDCAREWORKER pWorker, PWINCHILD pChild) 862 { 863 mkWinChildcareWorkerCatchOutput(pChild, &pWorker->StdOut, TRUE /*fDraining*/); 864 mkWinChildcareWorkerCatchOutput(pChild, &pWorker->StdErr, TRUE /*fDraining*/); 865 866 /* Drop lone 'source.c' line from CL.exe, but only if no other output at all. */ 867 if ( pChild->fProbableClExe 868 && !pWorker->StdOut.fHaveWrittenOut 869 && !pWorker->StdErr.fHaveWrittenOut 870 && pWorker->StdErr.cbWritten == pWorker->StdErr.offPendingRead 871 && pWorker->StdOut.cbWritten < pWorker->StdOut.offPendingRead 872 && mkWinChildcareWorkerIsClExeSourceLine(&pWorker->StdOut, pWorker->StdOut.cbWritten, pWorker->StdOut.offPendingRead)) 873 { 874 if (!pWorker->StdOut.fReadPending) 875 pWorker->StdOut.cbWritten = pWorker->StdOut.offPendingRead = 0; 876 else 877 pWorker->StdOut.cbWritten = pWorker->StdOut.offPendingRead; 878 } 879 else 880 { 881 mkWinChildcareWorkerFlushUnwritten(pChild, &pWorker->StdOut); 882 mkWinChildcareWorkerFlushUnwritten(pChild, &pWorker->StdErr); 883 } 884 } 885 886 /** 809 887 * Commmon worker for waiting on a child process and retrieving the exit code. 810 888 * … … 822 900 DWORD const msStart = GetTickCount(); 823 901 DWORD msNextMsg = msStart + 15000; 902 903 /* Reset the written indicators on the pipes before we start loop. */ 904 pWorker->StdOut.fHaveWrittenOut = FALSE; 905 pWorker->StdErr.fHaveWrittenOut = FALSE; 906 824 907 for (;;) 825 908 { … … 835 918 dwStatus = WaitForMultipleObjects(3, ahHandles, FALSE /*fWaitAll*/, 1000 /*ms*/); 836 919 if (dwStatus == WAIT_OBJECT_0 + 1) 837 mkWinChildcareWorkerCatchOutput(pChild, &pWorker->StdOut, FALSE /*f Flushing*/);920 mkWinChildcareWorkerCatchOutput(pChild, &pWorker->StdOut, FALSE /*fDraining*/); 838 921 else if (dwStatus == WAIT_OBJECT_0 + 2) 839 mkWinChildcareWorkerCatchOutput(pChild, &pWorker->StdErr, FALSE /*f Flushing*/);922 mkWinChildcareWorkerCatchOutput(pChild, &pWorker->StdErr, FALSE /*fDraining*/); 840 923 } 841 924 assert(dwStatus != WAIT_FAILED); … … 850 933 { 851 934 pChild->iExitCode = (int)dwExitCode; 852 if (!fCatchOutput) 853 { 854 mkWinChildcareWorkerCatchOutput(pChild, &pWorker->StdOut, TRUE /*fFlushing*/); 855 mkWinChildcareWorkerCatchOutput(pChild, &pWorker->StdErr, TRUE /*fFlushing*/); 856 } 935 if (fCatchOutput) 936 mkWinChildcareWorkerDrainPipes(pWorker, pChild); 857 937 return dwExitCode; 858 938 } … … 1464 1544 } 1465 1545 1546 /** 1547 * Checks if the image path looks like microsoft CL.exe. 1548 * 1549 * @returns TRUE / FALSE. 1550 * @param pwszImagePath The executable image path to evalutate. 1551 * @param cwcImagePath The length of the image path. 1552 */ 1553 static BOOL mkWinChildIsProbableClExe(WCHAR const *pwszImagePath, size_t cwcImagePath) 1554 { 1555 assert(pwszImagePath[cwcImagePath] == '\0'); 1556 return cwcImagePath > 7 1557 && (pwszImagePath[cwcImagePath - 7] == L'/' || pwszImagePath[cwcImagePath - 7] == L'\\') 1558 && (pwszImagePath[cwcImagePath - 6] == L'c' || pwszImagePath[cwcImagePath - 6] == L'C') 1559 && (pwszImagePath[cwcImagePath - 5] == L'l' || pwszImagePath[cwcImagePath - 5] == L'L') 1560 && pwszImagePath[cwcImagePath - 4] == L'.' 1561 && (pwszImagePath[cwcImagePath - 3] == L'e' || pwszImagePath[cwcImagePath - 3] == L'E') 1562 && (pwszImagePath[cwcImagePath - 2] == L'x' || pwszImagePath[cwcImagePath - 2] == L'X') 1563 && (pwszImagePath[cwcImagePath - 1] == L'e' || pwszImagePath[cwcImagePath - 1] == L'E'); 1564 } 1466 1565 1467 1566 /** … … 1483 1582 * could be the shell. 1484 1583 * @param pfNeedShell Where to return shell vs direct execution indicator. 1584 * @param pfProbableClExe Where to return an indicator of probably CL.EXE. 1485 1585 */ 1486 1586 static int mkWinChildcareWorkerFindImage(char const *pszArg0, WCHAR *pwszSearchPath, WCHAR const *pwszzEnv, 1487 const char *pszShell, WCHAR **ppwszImagePath, BOOL *pfNeedShell )1587 const char *pszShell, WCHAR **ppwszImagePath, BOOL *pfNeedShell, BOOL *pfProbableClExe) 1488 1588 { 1489 1589 /** @todo Slap a cache on this code. We usually end up executing the same … … 1528 1628 *pwc++ = L'\\'; 1529 1629 1530 /* Don't need to set th isall the time... */1630 /* Don't need to set these all the time... */ 1531 1631 *pfNeedShell = FALSE; 1632 *pfProbableClExe = FALSE; 1532 1633 1533 1634 /* … … 1572 1673 if (GetFileAttributesW(pwszPath) != INVALID_FILE_ATTRIBUTES) 1573 1674 #endif 1675 { 1676 *pfProbableClExe = mkWinChildIsProbableClExe(pwszPath, cwcPath + 4 - 1); 1574 1677 return mkWinChildDuplicateUtf16String(pwszPath, cwcPath + 4, ppwszImagePath); 1678 } 1575 1679 1576 1680 /* … … 1592 1696 CloseHandle(hFile); 1593 1697 if (!*pfNeedShell) 1698 { 1699 *pfProbableClExe = mkWinChildIsProbableClExe(pwszPath, cwcPath - 1); 1594 1700 return mkWinChildDuplicateUtf16String(pwszPath, cwcPath, ppwszImagePath); 1701 } 1595 1702 } 1596 1703 } … … 1714 1821 && !(dwAttribs & FILE_ATTRIBUTE_DIRECTORY)) 1715 1822 #endif 1823 { 1824 *pfProbableClExe = mkWinChildIsProbableClExe(wszPathBuf, cwcCombined + (fHasExeSuffix ? 0 : 4) - 1); 1716 1825 return mkWinChildDuplicateUtf16String(wszPathBuf, cwcCombined + (fHasExeSuffix ? 0 : 4), ppwszImagePath); 1826 } 1717 1827 if (!fHasExeSuffix) 1718 1828 { … … 1733 1843 CloseHandle(hFile); 1734 1844 if (!*pfNeedShell) 1845 { 1846 *pfProbableClExe = mkWinChildIsProbableClExe(wszPathBuf, cwcCombined - 1); 1735 1847 return mkWinChildDuplicateUtf16String(wszPathBuf, cwcCombined, ppwszImagePath); 1848 } 1736 1849 break; 1737 1850 } … … 1957 2070 WCHAR *pwszImageName = NULL; 1958 2071 BOOL fNeedShell = FALSE; 2072 BOOL fProbableClExe = FALSE; 1959 2073 int rc; 1960 2074 … … 1972 2086 if (rc == 0) 1973 2087 rc = mkWinChildcareWorkerFindImage(pChild->u.Process.papszArgs[0], pwszSearchPath, pwszzEnvironment, 1974 pChild->u.Process.pszShell, &pwszImageName, &fNeedShell );2088 pChild->u.Process.pszShell, &pwszImageName, &fNeedShell, &pChild->fProbableClExe); 1975 2089 if (rc == 0) 1976 2090 { … … 2928 3042 WCHAR *pwszCwd = NULL; 2929 3043 BOOL fNeedShell = FALSE; 3044 PWINCHILD pChild; 2930 3045 int rc; 2931 3046 assert(pWorker->uMagic == WINCHILDCAREWORKER_MAGIC); 2932 assert(pWorker->pCurChild != NULL && pWorker->pCurChild->uMagic == WINCHILD_MAGIC); 3047 pChild = pWorker->pCurChild; 3048 assert(pChild != NULL && pChild->uMagic == WINCHILD_MAGIC); 2933 3049 2934 3050 /* … … 2961 3077 */ 2962 3078 if (rc == 0) 2963 rc = mkWinChildcareWorkerFindImage(pszExecutable, pwszSearchPath, pwszzEnvironment, 2964 NULL /*pszNull*/, &pwszImageName, &fNeedShell);3079 rc = mkWinChildcareWorkerFindImage(pszExecutable, pwszSearchPath, pwszzEnvironment, NULL /*pszShell*/, 3080 &pwszImageName, &fNeedShell, &pChild->fProbableClExe); 2965 3081 if (rc == 0) 2966 3082 { … … 2984 3100 * Wait for the child to complete. 2985 3101 */ 2986 rc = mkWinChildcareWorkerWaitForProcess(pWorker, pWorker->pCurChild, hProcess, pwszImageName, 2987 TRUE /*fCatchOutput*/); 3102 rc = mkWinChildcareWorkerWaitForProcess(pWorker, pChild, hProcess, pwszImageName, TRUE /*fCatchOutput*/); 2988 3103 CloseHandle(hProcess); 2989 3104 }
Note:
See TracChangeset
for help on using the changeset viewer.