Ignore:
Timestamp:
Mar 16, 2020, 3:31:38 AM (5 years ago)
Author:
bird
Message:

kmk,kWorker: Assign processor groups to kWorker processes. Added --special-env hack for having a mspdbsrv.exe instance per processor group (using _MSPDBSRV_ENDPOINT_). This was complicated by PCH requiring to share .pdb file and therefore mspdbsrv.exe instance, requiring a mspdb100.dll re-init hack to disconnect kWorker from the previous mspdbsrv when switching. fun.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/kWorker/kWorker.c

    r3200 r3313  
    195195
    196196
     197/**
     198 * Generate CRT slot wrapper functions.
     199 */
     200#define CRT_SLOT_FUNCTION_WRAPPER(a_RetTypeAndCallConv, a_FnName, a_aArgsDecl, a_aArgCall) \
     201    static a_RetTypeAndCallConv a_FnName##00 a_aArgsDecl { const unsigned iCrtSlot =  0; return a_FnName##_wrapped a_aArgCall; } \
     202    static a_RetTypeAndCallConv a_FnName##01 a_aArgsDecl { const unsigned iCrtSlot =  1; return a_FnName##_wrapped a_aArgCall; } \
     203    static a_RetTypeAndCallConv a_FnName##02 a_aArgsDecl { const unsigned iCrtSlot =  2; return a_FnName##_wrapped a_aArgCall; } \
     204    static a_RetTypeAndCallConv a_FnName##03 a_aArgsDecl { const unsigned iCrtSlot =  3; return a_FnName##_wrapped a_aArgCall; } \
     205    static a_RetTypeAndCallConv a_FnName##04 a_aArgsDecl { const unsigned iCrtSlot =  4; return a_FnName##_wrapped a_aArgCall; } \
     206    static a_RetTypeAndCallConv a_FnName##05 a_aArgsDecl { const unsigned iCrtSlot =  5; return a_FnName##_wrapped a_aArgCall; } \
     207    static a_RetTypeAndCallConv a_FnName##06 a_aArgsDecl { const unsigned iCrtSlot =  6; return a_FnName##_wrapped a_aArgCall; } \
     208    static a_RetTypeAndCallConv a_FnName##07 a_aArgsDecl { const unsigned iCrtSlot =  7; return a_FnName##_wrapped a_aArgCall; } \
     209    static a_RetTypeAndCallConv a_FnName##08 a_aArgsDecl { const unsigned iCrtSlot =  8; return a_FnName##_wrapped a_aArgCall; } \
     210    static a_RetTypeAndCallConv a_FnName##09 a_aArgsDecl { const unsigned iCrtSlot =  9; return a_FnName##_wrapped a_aArgCall; } \
     211    static a_RetTypeAndCallConv a_FnName##10 a_aArgsDecl { const unsigned iCrtSlot = 10; return a_FnName##_wrapped a_aArgCall; } \
     212    static a_RetTypeAndCallConv a_FnName##11 a_aArgsDecl { const unsigned iCrtSlot = 11; return a_FnName##_wrapped a_aArgCall; } \
     213    static a_RetTypeAndCallConv a_FnName##12 a_aArgsDecl { const unsigned iCrtSlot = 12; return a_FnName##_wrapped a_aArgCall; } \
     214    static a_RetTypeAndCallConv a_FnName##13 a_aArgsDecl { const unsigned iCrtSlot = 13; return a_FnName##_wrapped a_aArgCall; } \
     215    static a_RetTypeAndCallConv a_FnName##14 a_aArgsDecl { const unsigned iCrtSlot = 14; return a_FnName##_wrapped a_aArgCall; } \
     216    static a_RetTypeAndCallConv a_FnName##15 a_aArgsDecl { const unsigned iCrtSlot = 15; return a_FnName##_wrapped a_aArgCall; } \
     217    static a_RetTypeAndCallConv a_FnName##16 a_aArgsDecl { const unsigned iCrtSlot = 16; return a_FnName##_wrapped a_aArgCall; } \
     218    static a_RetTypeAndCallConv a_FnName##17 a_aArgsDecl { const unsigned iCrtSlot = 17; return a_FnName##_wrapped a_aArgCall; } \
     219    static a_RetTypeAndCallConv a_FnName##18 a_aArgsDecl { const unsigned iCrtSlot = 18; return a_FnName##_wrapped a_aArgCall; } \
     220    static a_RetTypeAndCallConv a_FnName##19 a_aArgsDecl { const unsigned iCrtSlot = 19; return a_FnName##_wrapped a_aArgCall; } \
     221    static a_RetTypeAndCallConv a_FnName##20 a_aArgsDecl { const unsigned iCrtSlot = 20; return a_FnName##_wrapped a_aArgCall; } \
     222    static a_RetTypeAndCallConv a_FnName##21 a_aArgsDecl { const unsigned iCrtSlot = 21; return a_FnName##_wrapped a_aArgCall; } \
     223    static a_RetTypeAndCallConv a_FnName##22 a_aArgsDecl { const unsigned iCrtSlot = 22; return a_FnName##_wrapped a_aArgCall; } \
     224    static a_RetTypeAndCallConv a_FnName##23 a_aArgsDecl { const unsigned iCrtSlot = 23; return a_FnName##_wrapped a_aArgCall; } \
     225    static a_RetTypeAndCallConv a_FnName##24 a_aArgsDecl { const unsigned iCrtSlot = 24; return a_FnName##_wrapped a_aArgCall; } \
     226    static a_RetTypeAndCallConv a_FnName##25 a_aArgsDecl { const unsigned iCrtSlot = 25; return a_FnName##_wrapped a_aArgCall; } \
     227    static a_RetTypeAndCallConv a_FnName##26 a_aArgsDecl { const unsigned iCrtSlot = 26; return a_FnName##_wrapped a_aArgCall; } \
     228    static a_RetTypeAndCallConv a_FnName##27 a_aArgsDecl { const unsigned iCrtSlot = 27; return a_FnName##_wrapped a_aArgCall; } \
     229    static a_RetTypeAndCallConv a_FnName##28 a_aArgsDecl { const unsigned iCrtSlot = 28; return a_FnName##_wrapped a_aArgCall; } \
     230    static a_RetTypeAndCallConv a_FnName##29 a_aArgsDecl { const unsigned iCrtSlot = 29; return a_FnName##_wrapped a_aArgCall; } \
     231    static a_RetTypeAndCallConv a_FnName##30 a_aArgsDecl { const unsigned iCrtSlot = 30; return a_FnName##_wrapped a_aArgCall; } \
     232    static a_RetTypeAndCallConv a_FnName##31 a_aArgsDecl { const unsigned iCrtSlot = 31; return a_FnName##_wrapped a_aArgCall; } \
     233    static const KUPTR a_FnName[] = \
     234    { \
     235        (KUPTR)a_FnName##00, \
     236        (KUPTR)a_FnName##01, \
     237        (KUPTR)a_FnName##02, \
     238        (KUPTR)a_FnName##03, \
     239        (KUPTR)a_FnName##04, \
     240        (KUPTR)a_FnName##05, \
     241        (KUPTR)a_FnName##06, \
     242        (KUPTR)a_FnName##07, \
     243        (KUPTR)a_FnName##08, \
     244        (KUPTR)a_FnName##09, \
     245        (KUPTR)a_FnName##10, \
     246        (KUPTR)a_FnName##11, \
     247        (KUPTR)a_FnName##12, \
     248        (KUPTR)a_FnName##13, \
     249        (KUPTR)a_FnName##14, \
     250        (KUPTR)a_FnName##15, \
     251        (KUPTR)a_FnName##16, \
     252        (KUPTR)a_FnName##17, \
     253        (KUPTR)a_FnName##18, \
     254        (KUPTR)a_FnName##19, \
     255        (KUPTR)a_FnName##20, \
     256        (KUPTR)a_FnName##21, \
     257        (KUPTR)a_FnName##22, \
     258        (KUPTR)a_FnName##23, \
     259        (KUPTR)a_FnName##24, \
     260        (KUPTR)a_FnName##25, \
     261        (KUPTR)a_FnName##26, \
     262        (KUPTR)a_FnName##27, \
     263        (KUPTR)a_FnName##28, \
     264        (KUPTR)a_FnName##29, \
     265        (KUPTR)a_FnName##30, \
     266        (KUPTR)a_FnName##31, \
     267    }
     268
     269
    197270/*********************************************************************************************************************************
    198271*   Structures and Typedefs                                                                                                      *
     
    221294typedef struct KWMODULE
    222295{
    223     /** Pointer to the next image. */
    224     PKWMODULE           pNext;
     296    /** Pointer to the next image withe the same hash. */
     297    PKWMODULE           pNextHash;
     298    /** Pointer to the next image in the global list. */
     299    PKWMODULE           pNextList;
    225300    /** The normalized path to the image. */
    226301    const char         *pszPath;
     
    243318    /** The of the loaded image bits. */
    244319    KSIZE               cbImage;
     320    /** The CRT slot for this module, if applicable (KU8_MAX when not). */
     321    KU8                 iCrtSlot;
     322    /** Loop prevention when working the tree. */
     323    KBOOL               fVisited;
     324    /** HACK: Set if re-init is needed (fReInitOnMsPdbSrvEndpointChange). */
     325    KBOOL               fNeedReInit;
     326    /** HACK: Reinit when _MSPDBSRV_ENDPOINT_ changes, K_FALSE if not applicable.
     327     * 1 if applicable but not yet used, 2 if used and have pszMsPdbSrvEndpoint. */
     328    KU8                 fReInitOnMsPdbSrvEndpointChange;
     329    /** HACK: The old _MSPDBSRV_ENDPOINT_ value. */
     330    char               *pszMsPdbSrvEndpoint;
    245331
    246332    union
     
    851937} KWSANDBOX;
    852938
     939
     940/** A CRT slot.  */
     941typedef struct KWCRTSLOT
     942{
     943    KU32        iSlot;
     944
     945    /** The CRT module data.    */
     946    PKWMODULE   pModule;
     947    /** Pointer to the malloc function.   */
     948    void * (__cdecl *pfnMalloc)(size_t);
     949
     950} KWCRTSLOT;
     951typedef KWCRTSLOT *PKWCRTSLOT;
     952
     953
    853954/** Replacement function entry. */
    854955typedef struct KWREPLACEMENTFUNCTION
     
    860961    /** The module name (optional). */
    861962    const char *pszModule;
    862     /** The replacement function or data address. */
     963    /** The replacement function, data address or CRT slot function array. */
    863964    KUPTR       pfnReplacement;
    864965    /** Only replace in the executable.
    865966     * @todo fix the reinitialization of non-native DLLs!  */
    866967    KBOOL       fOnlyExe;
     968    /** Set if pfnReplacement points to a CRT slot function array. */
     969    KBOOL       fCrtSlotArray;
    867970} KWREPLACEMENTFUNCTION;
    868971typedef KWREPLACEMENTFUNCTION const *PCKWREPLACEMENTFUNCTION;
     
    884987#endif
    885988
     989/**
     990 * One test job (--full-test).
     991 */
     992typedef struct KWONETEST
     993{
     994    /** Where this job originated. */
     995    const char     *pszJobSrc;
     996    /** The argument number it started with. */
     997    unsigned        iJobSrc;
     998    /** Set if virgin, clear if modified. */
     999    KBOOL           fVirgin;
     1000
     1001    /** Number of runs to give it. */
     1002    unsigned        cRuns;
     1003
     1004    /** @name kSubmitHandleJobUnpacked arguments
     1005     * @{ */
     1006    const char     *pszExecutable;
     1007    const char     *pszCwd;
     1008    KU32            cArgs;
     1009    const char    **papszArgs;
     1010    KU32            cEnvVars;
     1011    const char    **papszEnvVars;
     1012    const char     *pszSpecialEnv;
     1013    KBOOL           fWatcomBrainDamange;
     1014    KBOOL           fNoPchCaching;
     1015    KU32            cPostCmdArgs;
     1016    const char    **papszPostCmdArgs;
     1017    /** @} */
     1018
     1019    /** Pointer to the next one. */
     1020    struct KWONETEST *pNext;
     1021} KWONETEST;
     1022/** Pointer to one test job. */
     1023typedef KWONETEST *PKWONETEST;
     1024
    8861025
    8871026/*********************************************************************************************************************************
     
    8971036static PKWMODULE    g_pModPrevInLdBuf = NULL;
    8981037
     1038/** Module list head. */
     1039static PKWMODULE    g_pModuleHead = NULL;
     1040/** Where to insert the next module. */
     1041static PKWMODULE   *g_ppModuleNext = &g_pModuleHead;
     1042
    8991043/** Module hash table. */
    9001044static PKWMODULE    g_apModules[127];
     
    9111055static PKWMODULE    g_pModPendingTlsAlloc = NULL;
    9121056
     1057/** CRT slots.
     1058 * @note The number of entires here must match CRT_SLOT_FUNCTION_WRAPPER. */
     1059static KWCRTSLOT    g_aCrtSlots[32];
    9131060
    9141061/** The file system cache. */
     
    9261073/** Whether we should restart the worker. */
    9271074static KBOOL        g_fRestart = K_FALSE;
     1075
     1076/** The process group this worker is tied to (--group option), -1 if none. */
     1077static KI32         g_iProcessGroup = -1;
    9281078
    9291079/** Whether control-C/SIGINT or Control-Break/SIGBREAK have been seen. */
     
    10461196static int kwLdrModuleResolveAndLookup(const char *pszName, PKWMODULE pExe, PKWMODULE pImporter,
    10471197                                       const char *pszSearchPath, PKWMODULE *ppMod);
     1198static PKWMODULE kwLdrModuleForLoadedNative(const char *pszName, KBOOL fEnsureCrtSlot);
     1199static char *kwSandboxDoGetEnvA(PKWSANDBOX pSandbox, const char *pchVar, KSIZE cchVar);
    10481200static KBOOL kwSandboxHandleTableEnter(PKWSANDBOX pSandbox, PKWHANDLE pHandle, HANDLE hHandle);
    10491201#ifdef WITH_CONSOLE_OUTPUT_BUFFERING
     
    11601312    fprintf(stderr, "kWorker: error: ");
    11611313    vfprintf(stderr, pszFormat, va);
     1314    fflush(stderr); /* In case it's a pipe. */
    11621315
    11631316    SetLastError(dwSavedErr);
     
    16241777    if (--pMod->cRefs == 0)
    16251778    {
    1626         /* Unlink it. */
     1779        /* Unlink it from the hash table. */
    16271780        if (!pMod->fExe)
    16281781        {
     
    16301783            unsigned  idx   = pMod->uHashPath % K_ELEMENTS(g_apModules);
    16311784            if (g_apModules[idx] == pMod)
    1632                 g_apModules[idx] = pMod->pNext;
     1785                g_apModules[idx] = pMod->pNextHash;
    16331786            else
    16341787            {
    16351788                PKWMODULE pPrev = g_apModules[idx];
    16361789                kHlpAssert(pPrev != NULL);
    1637                 while (pPrev->pNext != pMod)
     1790                while (pPrev->pNextHash != pMod)
    16381791                {
    1639                     pPrev = pPrev->pNext;
     1792                    pPrev = pPrev->pNextHash;
    16401793                    kHlpAssert(pPrev != NULL);
    16411794                }
    1642                 pPrev->pNext = pMod->pNext;
    1643             }
     1795                pPrev->pNextHash = pMod->pNextHash;
     1796            }
     1797        }
     1798
     1799        /* Unlink it from the list. */
     1800        if (pMod != g_pModuleHead)
     1801        {
     1802            PKWMODULE pPrev = g_pModuleHead;
     1803            while (pPrev)
     1804            {
     1805                if (pPrev->pNextList == pMod)
     1806                {
     1807                    pPrev->pNextList = pMod->pNextList;
     1808                    if (!pMod->pNextList)
     1809                        g_ppModuleNext = &pPrev->pNextList;
     1810                    break;
     1811                }
     1812                pPrev = pPrev->pNextList;
     1813            }
     1814            kHlpAssert(pPrev != NULL);
     1815        }
     1816        else
     1817        {
     1818            g_pModuleHead = pMod->pNextList;
     1819            if (!pMod->pNextList)
     1820                g_ppModuleNext = &g_pModuleHead;
    16441821        }
    16451822
     
    16661843        }
    16671844
     1845        if (pMod->iCrtSlot != KU8_MAX)
     1846            g_aCrtSlots[pMod->iCrtSlot].pModule = NULL;
     1847
     1848        if (pMod->pszMsPdbSrvEndpoint)
     1849        {
     1850            kHlpFree(pMod->pszMsPdbSrvEndpoint);
     1851            pMod->pszMsPdbSrvEndpoint = NULL;
     1852        }
     1853
    16681854        kHlpFree(pMod);
    16691855    }
     
    16811867static PKWMODULE kwLdrModuleLink(PKWMODULE pMod)
    16821868{
    1683     unsigned idx = pMod->uHashPath % K_ELEMENTS(g_apModules);
    1684     pMod->pNext = g_apModules[idx];
    1685     g_apModules[idx] = pMod;
     1869    if (!pMod->fExe)
     1870    {
     1871        unsigned idx = pMod->uHashPath % K_ELEMENTS(g_apModules);
     1872        pMod->pNextHash = g_apModules[idx];
     1873        g_apModules[idx] = pMod;
     1874    }
     1875
     1876    pMod->pNextList = NULL;
     1877    *g_ppModuleNext = pMod;
     1878    g_ppModuleNext = &pMod->pNextList;
     1879
    16861880    return pMod;
    16871881}
     
    17481942            KU32                iThunk;
    17491943            const char * const  pszImport   = (const char *)&pbImage[pImpDesc->Name];
     1944            PKWMODULE           pImportMod  = NULL;
    17501945            PIMAGE_THUNK_DATA   paThunks    = (PIMAGE_THUNK_DATA)&pbImage[pImpDesc->FirstThunk];
    17511946            PIMAGE_THUNK_DATA   paOrgThunks = (PIMAGE_THUNK_DATA)&pbImage[pImpDesc->OriginalFirstThunk];
     
    18182013                                }
    18192014
    1820                                 paThunks[iThunk].u1.AddressOfData = g_aSandboxNativeReplacements[i].pfnReplacement;
     2015                                /*
     2016                                 * Unslotted replacements are simple.
     2017                                 */
     2018                                if (!g_aSandboxNativeReplacements[i].fCrtSlotArray)
     2019                                    paThunks[iThunk].u1.AddressOfData = g_aSandboxNativeReplacements[i].pfnReplacement;
     2020                                else
     2021                                {
     2022                                    /*
     2023                                     * Must find our module entry for this module, possibly creating one.
     2024                                     */
     2025                                    if (!pImportMod)
     2026                                    {
     2027                                        pImportMod = kwLdrModuleForLoadedNative(pszImport, K_TRUE /*fEnsureCrtSlot*/);
     2028                                        if (!pImportMod)
     2029                                        {
     2030                                            kwErrPrintf("Failed to get module '%s' when performing replacements on module '%s'!\n",
     2031                                                        pszImport, pMod->pszPath);
     2032                                            break;
     2033                                        }
     2034                                    }
     2035                                    paThunks[iThunk].u1.AddressOfData
     2036                                        = ((KUPTR *)g_aSandboxNativeReplacements[i].pfnReplacement)[pImportMod->iCrtSlot];
     2037                                }
    18212038                                break;
    18222039                            }
     
    18592076     * Create the entry.
    18602077     */
    1861     PKWMODULE pMod   = (PKWMODULE)kHlpAllocZ(sizeof(*pMod) + cbPath + cbPath * 2 * sizeof(wchar_t));
     2078    PKWMODULE pMod = (PKWMODULE)kHlpAllocZ(sizeof(*pMod) + cbPath + cbPath * 2 * sizeof(wchar_t));
    18622079    if (pMod)
    18632080    {
     
    18732090        pMod->hOurMod       = (HMODULE)(KUPTR)pLdrMod->aSegments[0].MapAddress;
    18742091        pMod->cbImage       = (KSIZE)kLdrModSize(pLdrMod);
     2092        pMod->iCrtSlot      = KU8_MAX;
     2093        pMod->fNeedReInit   = K_FALSE;
     2094        pMod->pszMsPdbSrvEndpoint = NULL;
     2095        pMod->fReInitOnMsPdbSrvEndpointChange = kHlpStrNICompAscii(&pMod->pszPath[pMod->offFilename], TUPLE("mspdb")) == 0;
    18752096
    18762097        if (fDoReplacements)
     
    19062127     */
    19072128    PKLDRMOD pLdrMod;
    1908     int rc = kLdrModOpenNative(pszPath, &pLdrMod);
     2129    int rc = kLdrModOpenNative(pszPath, KLDRMOD_OPEN_FLAGS_NATIVE_ALLOW_INIT_TERM, &pLdrMod);
    19092130    if (rc == 0)
    19102131    {
     
    22672488                    pMod->fNative       = K_FALSE;
    22682489                    pMod->pLdrMod       = pLdrMod;
    2269                     pMod->u.Manual.cImpMods = (KU32)cImports;
     2490                    pMod->iCrtSlot      = KU8_MAX;
     2491                    pMod->fNeedReInit   = K_FALSE;
     2492                    pMod->fReInitOnMsPdbSrvEndpointChange = K_FALSE;
     2493                    pMod->pszMsPdbSrvEndpoint       = NULL;
     2494                    pMod->u.Manual.cImpMods         = (KU32)cImports;
    22702495#if defined(KBUILD_OS_WINDOWS) && defined(KBUILD_ARCH_AMD64)
    22712496                    pMod->u.Manual.fRegisteredFunctionTable = K_FALSE;
     
    23102535                             */
    23112536                            pMod->hOurMod = (HMODULE)pMod->u.Manual.pbLoad;
    2312                             if (!fExe)
    2313                                 kwLdrModuleLink(pMod);
     2537                            kwLdrModuleLink(pMod);
    23142538                            KW_LOG(("New module: %p LB %#010x %s (kLdr)\n",
    23152539                                    pMod->u.Manual.pbLoad, pMod->cbImage, pMod->pszPath));
     
    26462870                        && kHlpStrComp(pMod->pszPath, szNormPath) == 0)
    26472871                        return kwLdrModuleRetain(pMod);
    2648                     pMod = pMod->pNext;
     2872                    pMod = pMod->pNextHash;
    26492873                } while (pMod);
    26502874            }
     
    27763000    *ppMod = NULL;
    27773001    return KERR_GENERAL_FAILURE;
     3002}
     3003
     3004
     3005/**
     3006 * Creates a CRT slot for the given module.
     3007 *
     3008 * @returns 0 on success, non-zero on failure.
     3009 * @param   pModule             The module.
     3010 */
     3011static int kwLdrModuleCreateCrtSlot(PKWMODULE pModule)
     3012{
     3013    KSIZE iSlot;
     3014    kHlpAssert(pModule->iCrtSlot == KU8_MAX);
     3015    for (iSlot = 0; iSlot < K_ELEMENTS(g_aCrtSlots); iSlot++)
     3016        if (g_aCrtSlots[iSlot].pModule == NULL)
     3017        {
     3018            KLDRADDR uAddr;
     3019            int rc;
     3020
     3021            /* Do the linking: */
     3022            g_aCrtSlots[iSlot].pModule = pModule;
     3023            g_aCrtSlots[iSlot].iSlot   = (KU32)iSlot;
     3024            pModule->iCrtSlot          = (KU8)iSlot;
     3025
     3026            /* resolve symbols: */
     3027            rc = kLdrModQuerySymbol(pModule->pLdrMod, NULL /*pvBits*/, KLDRMOD_BASEADDRESS_MAP, KU32_MAX, "malloc", 6,
     3028                                    NULL /*pvszVersion*/, NULL /*pfnGetForwarder*/, NULL /*pvUser*/, &uAddr, NULL);
     3029            *(KUPTR *)&g_aCrtSlots[iSlot].pfnMalloc = rc == 0 ? (KUPTR)uAddr : 0;
     3030            if (rc != 0)
     3031                kwErrPrintf("Failed to resolved 'malloc' in '%s': %d\n", pModule->pszPath, rc);
     3032
     3033            return 0;
     3034        }
     3035    kwErrPrintf("Out of CRT slots!\n");
     3036    return KERR_NO_MEMORY;
     3037}
     3038
     3039
     3040/**
     3041 * Locates the module structure for an already loaded native module.
     3042 *
     3043 * This will create a module structure if needed.
     3044 *
     3045 * @returns Pointer to the module structure on success, NULL on failure.
     3046 * @param   pszName         The name of the module.
     3047 * @param   fEnsureCrtSlot  Whether to ensure that it has a valid CRT slot.
     3048 */
     3049static PKWMODULE kwLdrModuleForLoadedNative(const char *pszName, KBOOL fEnsureCrtSlot)
     3050{
     3051    /*
     3052     * Locate the module and get a normalized path for it.
     3053     */
     3054    HANDLE hModule = GetModuleHandleA(pszName);
     3055    if (hModule)
     3056    {
     3057        char szModPath[1024];
     3058        if (GetModuleFileNameA(hModule, szModPath, sizeof(szModPath)) > 0)
     3059        {
     3060            char szNormPath[1024];
     3061            int rc = kwPathNormalize(szModPath, szNormPath, sizeof(szNormPath));
     3062            if (rc == 0)
     3063            {
     3064                /*
     3065                 * Hash the path and look it up.
     3066                 */
     3067                KU32        uHashPath;
     3068                KSIZE const cchPath   = kwStrHashEx(szNormPath, &uHashPath);
     3069                unsigned    idxHash   = uHashPath % K_ELEMENTS(g_apModules);
     3070                PKWMODULE   pMod      = g_apModules[idxHash];
     3071                if (pMod)
     3072                {
     3073                    do
     3074                    {
     3075                        if (   pMod->uHashPath == uHashPath
     3076                            && kHlpStrComp(pMod->pszPath, szNormPath) == 0)
     3077                        {
     3078                            kwLdrModuleRetain(pMod);
     3079                            break;
     3080                        }
     3081                        pMod = pMod->pNextHash;
     3082                    } while (pMod);
     3083                }
     3084
     3085                /*
     3086                 * If not in the hash table, so create a module entry.
     3087                 */
     3088                if (!pMod)
     3089                {
     3090                    PKLDRMOD pLdrMod;
     3091                    rc = kLdrModOpenNativeByHandle((KUPTR)hModule, KLDRMOD_OPEN_FLAGS_NATIVE_ALLOW_INIT_TERM, &pLdrMod);
     3092                    if (rc == 0)
     3093                    {
     3094                        pMod = kwLdrModuleCreateForNativekLdrModule(pLdrMod, szNormPath, cchPath + 1, uHashPath,
     3095                                                                    K_FALSE /*fDoReplacements*/);
     3096                        if (!pMod)
     3097                        {
     3098                            kLdrModClose(pLdrMod);
     3099                            kwErrPrintf("out of memory\n");
     3100                        }
     3101                    }
     3102                    else
     3103                        kwErrPrintf("kLdrModOpenNativeByHandle failed for %p / '%s': %d\n", hModule, pszName, rc);
     3104                }
     3105                if (pMod)
     3106                {
     3107                    /*
     3108                     * Create a CRT slot for the module if necessary.
     3109                     */
     3110                    if (!fEnsureCrtSlot || pMod->iCrtSlot != KU8_MAX)
     3111                        return pMod;
     3112                    rc = kwLdrModuleCreateCrtSlot(pMod);
     3113                    if (rc == 0)
     3114                        return pMod;
     3115                    kwLdrModuleRelease(pMod);
     3116                }
     3117            }
     3118            else
     3119                kwErrPrintf("kwPathNormalize failed for '%s' (%s): %u!\n", szModPath, pszName, GetLastError());
     3120        }
     3121        else
     3122            kwErrPrintf("GetModuleFileNameA failed for '%s': %u!\n", pszName, GetLastError());
     3123    }
     3124    else
     3125        kwErrPrintf("Module '%s' was not found by GetModuleHandleA!\n", pszName);
     3126    return NULL;
    27783127}
    27793128
     
    29423291                pMod->u.Manual.enmState = KWMODSTATE_INIT_FAILED;
    29433292        }
     3293    }
     3294    /*
     3295     * Special hack to disconnect mspdbXXX.dll from mspdbsrv.exe when
     3296     * _MSPDBSRV_ENDPOINT_ changes value.
     3297     */
     3298    else if (pMod->fNeedReInit)
     3299    {
     3300        int rc2;
     3301        KWLDR_LOG(("kwLdrModuleInitTree: mspdb re-init hack: %s\n", pMod->pszPath));
     3302        //fprintf(stderr, "%d: kwLdrModuleInitTree: mspdb re-init hack: %s\n", getpid(), kwSandboxDoGetEnvA(&g_Sandbox, TUPLE("_MSPDBSRV_ENDPOINT_"))); fflush(stderr);
     3303        rc = kLdrModCallTerm(pMod->pLdrMod, pMod->u.Manual.pbLoad, (KUPTR)pMod->hOurMod);
     3304        rc2 = kLdrModCallInit(pMod->pLdrMod, pMod->u.Manual.pbLoad, (KUPTR)pMod->hOurMod);
     3305        if (!rc && !rc2)
     3306        { /* likely */ }
     3307        else
     3308        {
     3309            kwErrPrintf("Re-init of '%s' failed: rc=%d rc2=%d\n", pMod->pszPath, rc, rc2);
     3310            if (rc2 && !rc)
     3311                rc = rc2;
     3312        }
     3313        pMod->fNeedReInit = K_FALSE;
    29443314    }
    29453315    return rc;
     
    45864956
    45874957
     4958/** CRT - _wdupenv_s() (see _tdupenv_s(). */
     4959static errno_t __cdecl kwSandbox_msvcrt__wdupenv_s_wrapped(wchar_t **ppwszValue, size_t *pcwcValue, const wchar_t *pwszVarName,
     4960                                                           PKWCRTSLOT pSlot)
     4961{
     4962    errno_t rc;
     4963    wchar_t *pwszValue;
     4964    kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
     4965
     4966    if (ppwszValue)
     4967    {
     4968        pwszValue = kwSandboxDoGetEnvW(&g_Sandbox, pwszVarName, wcslen(pwszVarName));
     4969        if (pwszValue)
     4970        {
     4971            size_t cwcValue = wcslen(pwszValue);
     4972            wchar_t *pwszDst = pSlot->pfnMalloc ? (wchar_t *)pSlot->pfnMalloc((cwcValue + 1) * sizeof(wchar_t)) : NULL;
     4973            if (pwszDst)
     4974            {
     4975                memcpy(pwszDst, pwszValue, cwcValue * sizeof(wchar_t));
     4976                pwszDst[cwcValue] = '\0';
     4977                *ppwszValue = pwszDst;
     4978                if (pcwcValue)
     4979                    *pcwcValue = cwcValue;
     4980                rc = 0;
     4981            }
     4982            else
     4983            {
     4984                *ppwszValue = NULL;
     4985                if (pcwcValue)
     4986                    *pcwcValue  = 0;
     4987                rc = ENOMEM;
     4988            }
     4989        }
     4990        else
     4991        {
     4992            *ppwszValue = NULL;
     4993            if (pcwcValue)
     4994                *pcwcValue = 0;
     4995            rc = 0;
     4996        }
     4997        KW_LOG(("_wdupenv_s(,,%ls) -> %d '%ls'\n", pwszVarName, rc, *ppwszValue ? *ppwszValue : L"<null>"));
     4998        //fprintf(stderr, "%d: _wdupenv_s(,,%ls) -> %d '%ls'\n", getpid(), pwszVarName, rc, *ppwszValue ? *ppwszValue : L"<null>"); fflush(stderr); // HACKING
     4999    }
     5000    else
     5001    {
     5002        /*
     5003         * Warning! If mspdb100.dll ends up here, it won't reinitialize the event name
     5004         *          and continue to use the one it constructed when _MSPDBSRV_ENDPOINT_
     5005         *          was set to a value.
     5006         */
     5007        if (pcwcValue)
     5008            *pcwcValue = 0;
     5009        rc = EINVAL;
     5010        KW_LOG(("_wdupenv_s(,,%ls) -> EINVAL\n", pwszVarName));
     5011        //fprintf(stderr, "%d: _wdupenv_s(,,%ls) -> EINVAL\n", getpid(), pwszVarName); fflush(stderr); // HACKING
     5012    }
     5013    return rc;
     5014}
     5015CRT_SLOT_FUNCTION_WRAPPER(errno_t __cdecl, kwSandbox_msvcrt__wdupenv_s,
     5016                          (wchar_t **ppwszValue, size_t *pcwcValue, const wchar_t *pwszVarName),
     5017                          (ppwszValue, pcwcValue, pwszVarName, &g_aCrtSlots[iCrtSlot]));
     5018
     5019
    45885020
    45895021/*
     
    46655097                return pDynLoad->hmod;
    46665098            }
    4667             pMod = pMod->pNext;
     5099            pMod = pMod->pNextHash;
    46685100        } while (pMod);
    46695101    }
     
    46775109    {
    46785110        PKLDRMOD pLdrMod;
    4679         int rc = kLdrModOpenNativeByHandle((KUPTR)hmod, &pLdrMod);
     5111        int rc = kLdrModOpenNativeByHandle((KUPTR)hmod, KLDRMOD_OPEN_FLAGS_NATIVE_ALLOW_INIT_TERM, &pLdrMod);
    46805112        if (rc == 0)
    46815113        {
     
    77908222
    77918223    /*
    7792      * Flush the two line buffer, the the combined buffer.
     8224     * Flush the two line buffer, then the combined buffer.
    77938225     */
    77948226    kwSandboxConsoleFinalFlushLineBuf(pSandbox, &pSandbox->StdErr, "StdErr");
     
    95089940    { TUPLE("_amsg_exit"),                  NULL,       (KUPTR)kwSandbox_msvcrt__amsg_exit },
    95099941    { TUPLE("terminate"),                   NULL,       (KUPTR)kwSandbox_msvcrt_terminate },
     9942    { TUPLE("_wdupenv_s"),                  NULL,       (KUPTR)kwSandbox_msvcrt__wdupenv_s, K_FALSE /*fOnlyExe*/, K_TRUE /*fCrtSlotArray*/ },
    95109943
    95119944#if 0 /* used by mspdbXXX.dll */
     
    960410037
    960510038/**
     10039 * Resets the KWMODULE::fVisited flag for _all_ known modules.
     10040 */
     10041static void kwSandboxResetModuleVisited(void)
     10042{
     10043    PKWMODULE pMod = g_pModuleHead;
     10044    while (pMod)
     10045    {
     10046        pMod->fVisited = K_FALSE;
     10047        pMod = pMod->pNextList;
     10048    }
     10049}
     10050
     10051
     10052/**
    960610053 * Used by kwSandboxExec to reset the state of the module tree.
    960710054 *
     
    961210059static void kwSandboxResetModuleState(PKWMODULE pMod)
    961310060{
    9614     if (   !pMod->fNative
    9615         && pMod->u.Manual.enmState != KWMODSTATE_NEEDS_BITS)
    9616     {
    9617         KSIZE iImp;
     10061    KWLDR_LOG(("kwSandboxResetModuleState: %d %d %s\n", pMod->fNative, pMod->fVisited, pMod->pszPath));
     10062    if (!pMod->fNative)
     10063    {
    961810064        pMod->u.Manual.enmState = KWMODSTATE_NEEDS_BITS;
    9619         iImp = pMod->u.Manual.cImpMods;
    9620         while (iImp-- > 0)
    9621             kwSandboxResetModuleState(pMod->u.Manual.apImpMods[iImp]);
     10065        if (!pMod->fVisited) /* Avoid loops. */
     10066        {
     10067            KSIZE iImp;
     10068            pMod->fVisited = K_TRUE;
     10069            iImp = pMod->u.Manual.cImpMods;
     10070            while (iImp-- > 0)
     10071                kwSandboxResetModuleState(pMod->u.Manual.apImpMods[iImp]);
     10072        }
     10073    }
     10074    /* Hack: Re-init mspdbXXX.dll when we want to use a different mspdbsrv.exe instance. */
     10075    else if (pMod->fReInitOnMsPdbSrvEndpointChange)
     10076    {
     10077        const char *pszValue = kwSandboxDoGetEnvA(&g_Sandbox, TUPLE("_MSPDBSRV_ENDPOINT_"));
     10078        if (pMod->fReInitOnMsPdbSrvEndpointChange == 1)
     10079        {
     10080            pMod->fReInitOnMsPdbSrvEndpointChange = 2;
     10081            pMod->pszMsPdbSrvEndpoint = pszValue ? kHlpStrDup(pszValue) : NULL;
     10082            KWLDR_LOG(("Not re-initing '%s': first time used (_MSPDBSRV_ENDPOINT_ is '%s')\n",
     10083                       pMod->pszPath, pszValue ? pszValue : "<null>"));
     10084        }
     10085        else if (   (pszValue == NULL && pMod->pszMsPdbSrvEndpoint == NULL)
     10086                 || (pszValue != NULL && pMod->pszMsPdbSrvEndpoint != NULL && kHlpStrComp(pszValue, pMod->pszMsPdbSrvEndpoint) == 0))
     10087            KWLDR_LOG(("Not re-initing '%s': _MSPDBSRV_ENDPOINT_ unchanged ('%s')\n",
     10088                       pMod->pszPath, pszValue ? pszValue : "<null>"));
     10089        else
     10090        {
     10091            KWLDR_LOG(("Re-initing '%s': _MSPDBSRV_ENDPOINT_ changed from '%s' to '%s'\n", pMod->pszPath,
     10092                       pMod->pszMsPdbSrvEndpoint ? pMod->pszMsPdbSrvEndpoint : "<null>", pszValue ? pszValue : "<null>"));
     10093            kHlpFree(pMod->pszMsPdbSrvEndpoint);
     10094            if (pszValue != NULL)
     10095                pMod->pszMsPdbSrvEndpoint = kHlpStrDup(pszValue);
     10096            else
     10097                pMod->pszMsPdbSrvEndpoint = NULL;
     10098            pMod->fNeedReInit = K_TRUE;
     10099        }
    962210100    }
    962310101}
     
    1020710685         * Do module initialization.
    1020810686         */
     10687        kwSandboxResetModuleVisited();
    1020910688        kwSandboxResetModuleState(pTool->u.Sandboxed.pExe);
    1021010689        rc = kwLdrModuleInitTree(pTool->u.Sandboxed.pExe);
     
    1029210771#endif
    1029310772        kwSandboxCleanup(&g_Sandbox);
     10773        /** @todo Flush sandboxed native CRTs too. */
    1029410774    }
    1029510775    else
     
    1032310803    }
    1032410804
    10325     return kwErrPrintfRc(42 + 5 , "Unknown post command: '%s'\n", pszCmd);
     10805    return kwErrPrintfRc(42 + 5, "Unknown post command: '%s'\n", pszCmd);
     10806}
     10807
     10808
     10809/**
     10810 * Helper for kSubmitHandleSpecialEnvVar that gets the current process group.
     10811 */
     10812static unsigned kwGetCurrentProcessorGroup(void)
     10813{
     10814    typedef BOOL (WINAPI *PFNGETTHREADGROUPAFFINITY)(HANDLE, GROUP_AFFINITY *);
     10815    HMODULE                   hmodKernel32 = GetModuleHandleW(L"KERNEL32.DLL");
     10816    PFNGETTHREADGROUPAFFINITY pfnGetter    = (PFNGETTHREADGROUPAFFINITY)GetProcAddress(hmodKernel32, "GetThreadGroupAffinity");
     10817    if (pfnGetter)
     10818    {
     10819        GROUP_AFFINITY GroupAffinity;
     10820        memset(&GroupAffinity, 0, sizeof(GroupAffinity));
     10821        if (pfnGetter(GetCurrentThread(), &GroupAffinity))
     10822            return GroupAffinity.Group;
     10823    }
     10824    return 0;
     10825}
     10826
     10827
     10828/**
     10829 * Helper for kSubmitHandleSpecialEnvVar that gets the current process group.
     10830 */
     10831static KSIZE kwGetCurrentAuthenticationIdAsString(char *pszValue)
     10832{
     10833    KSIZE  cchRet = 0;
     10834    HANDLE hToken;
     10835    if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
     10836    {
     10837        DWORD cbRet;
     10838        TOKEN_STATISTICS TokenStats;
     10839        memset(&TokenStats, 0, sizeof(TokenStats));
     10840        if (GetTokenInformation(hToken, TokenStatistics, &TokenStats, sizeof(TokenStats), &cbRet))
     10841            cchRet = sprintf(pszValue, "%" KX64_PRI,
     10842                             ((KU64)TokenStats.AuthenticationId.HighPart << 32) | TokenStats.AuthenticationId.LowPart);
     10843        else
     10844            kwErrPrintf("GetTokenInformation/TokenStatistics failed: %u\n", GetLastError());
     10845        CloseHandle(hToken);
     10846    }
     10847    else
     10848        kwErrPrintf("OpenProcessToken failed: %u\n", GetLastError());
     10849    return cchRet;
     10850}
     10851
     10852
     10853/**
     10854 * Look for and expand the special environment variable.
     10855 * 
     10856 * We the special variable contains elements like "@@VAR_NAME@@" that kmk
     10857 * couldn't accuratly determine.  Currently the following variables are
     10858 * implemented:
     10859 *     - "@@PROCESSOR_GROUP@@"   - The processor group number.
     10860 *     - "@@AUTHENTICATION_ID@@" - The authentication ID from the process token.
     10861 *     - "@@PID@@"               - The kWorker process ID.
     10862 *     - "@@@@"                  - Escaped "@@".
     10863 *     - "@@DEBUG_COUNTER@@"     - An ever increasing counter (starts at zero).
     10864 */ 
     10865static int kSubmitHandleSpecialEnvVar(KU32 cEnvVars, const char **papszEnvVars, const char *pszSpecialEnv, char **ppszToFree)
     10866{
     10867    KSIZE const cchSpecialEnv = kHlpStrLen(pszSpecialEnv);
     10868    KU32 i = cEnvVars;
     10869    while (i-- > 0)
     10870        if (   kHlpStrNComp(papszEnvVars[i], pszSpecialEnv, cchSpecialEnv) == 0
     10871            && papszEnvVars[i][cchSpecialEnv] == '=')
     10872        {
     10873            /* We will expand stuff like @@NAME@@ */
     10874            const char *pszValue = papszEnvVars[i];
     10875            KSIZE       offDst   = 0;
     10876            char        szTmp[1024];
     10877            for (;;)
     10878            {
     10879                const char *pszAt = kHlpStrChr(pszValue, '@');
     10880                while (pszAt && pszAt[1] != '@')
     10881                    pszAt = kHlpStrChr(pszAt + 1, '@');
     10882                if (pszAt)
     10883                {
     10884                    KSIZE cchSrc = pszAt - pszValue;
     10885                    if (offDst + cchSrc < sizeof(szTmp))
     10886                    {
     10887                        char szSrc[64];
     10888
     10889                        kHlpMemCopy(&szTmp[offDst], pszValue, cchSrc);
     10890                        offDst += cchSrc;
     10891                        pszValue = pszAt + 2;
     10892
     10893                        if (kHlpStrNComp(pszValue, "PROCESS_GROUP@@", 15) == 0)
     10894                        {
     10895                            pszValue += 15;
     10896                            if (g_iProcessGroup == -1)
     10897                                g_iProcessGroup = kwGetCurrentProcessorGroup();
     10898                            cchSrc = sprintf(szSrc, "%u", g_iProcessGroup);
     10899                        }
     10900                        else if (kHlpStrNComp(pszValue, "AUTHENTICATION_ID@@", 19) == 0)
     10901                        {
     10902                            pszValue += 19;
     10903                            cchSrc = kwGetCurrentAuthenticationIdAsString(szSrc);
     10904                        }
     10905                        else if (kHlpStrNComp(pszValue, "PID@@", 5) == 0)
     10906                        {
     10907                            pszValue += 5;
     10908                            cchSrc = sprintf(szSrc, "%d", getpid());
     10909                        }
     10910                        else if (kHlpStrNComp(pszValue, "@@", 2) == 0)
     10911                        {
     10912                            pszValue += 2;
     10913                            szSrc[0] = '@';
     10914                            szSrc[1] = '@';
     10915                            szSrc[2] = '\0';
     10916                            cchSrc = 2;
     10917                        }
     10918                        else if (kHlpStrNComp(pszValue, "DEBUG_COUNTER@@", 15) == 0)
     10919                        {
     10920                            static unsigned int s_iCounter = 0;
     10921                            pszValue += 15;
     10922                            cchSrc = sprintf(szSrc, "%u", s_iCounter++);
     10923                        }
     10924                        else
     10925                            return kwErrPrintfRc(42 + 6, "Special environment variable contains unknown reference: '%s'!\n",
     10926                                                 pszValue - 2);
     10927                        if (offDst + cchSrc < sizeof(szTmp))
     10928                        {
     10929                            kHlpMemCopy(&szTmp[offDst], szSrc, cchSrc);
     10930                            offDst += cchSrc;
     10931                            continue;
     10932                        }
     10933                    }
     10934                }
     10935                else
     10936                {
     10937                    KSIZE cchSrc = kHlpStrLen(pszValue);
     10938                    if (offDst + cchSrc < sizeof(szTmp))
     10939                    {
     10940                        kHlpMemCopy(&szTmp[offDst], pszValue, cchSrc);
     10941                        offDst += cchSrc;
     10942                        break;
     10943                    }
     10944                }
     10945                return kwErrPrintfRc(42 + 6, "Special environment variable value too long!\n");
     10946            }
     10947            szTmp[offDst] = '\0';
     10948
     10949            /* Return a copy of it: */
     10950            papszEnvVars[i] = *ppszToFree = kHlpDup(szTmp, offDst + 1);
     10951            if (papszEnvVars[i])
     10952            {
     10953                SetEnvironmentVariableA(pszSpecialEnv, kHlpStrChr(papszEnvVars[i], '=') + 1); /* hack */
     10954                return 0;
     10955            }
     10956            return kwErrPrintfRc(42 + 6, "Special environment variable: out of memory\n");
     10957        }
     10958
     10959    return kwErrPrintfRc(42 + 6, "Special environment variable not found: '%s'\n", pszSpecialEnv);
    1032610960}
    1032710961
     
    1033810972 * @param   cEnvVars            The number of environment variables.
    1033910973 * @param   papszEnvVars        The environment vector.
     10974 * @param   pszSpecialEnv       Name of special environment variable that
     10975 *                              requires selective expansion here.
    1034010976 * @param   fNoPchCaching       Whether to disable precompiled header file
    1034110977 *                              caching.  Avoid trouble when creating them.
     
    1034510981static int kSubmitHandleJobUnpacked(const char *pszExecutable, const char *pszCwd,
    1034610982                                    KU32 cArgs, const char **papszArgs, KBOOL fWatcomBrainDamange,
    10347                                     KU32 cEnvVars, const char **papszEnvVars, KBOOL fNoPchCaching,
    10348                                     KU32 cPostCmdArgs, const char **papszPostCmdArgs)
     10983                                    KU32 cEnvVars, const char **papszEnvVars, const char *pszSpecialEnv,
     10984                                    KBOOL fNoPchCaching, KU32 cPostCmdArgs, const char **papszPostCmdArgs)
    1034910985{
    1035010986    int rcExit;
    1035110987    PKWTOOL pTool;
     10988    char *pszSpecialEnvFree = NULL;
    1035210989
    1035310990    KW_LOG(("\n\nkSubmitHandleJobUnpacked: '%s' in '%s' cArgs=%u cEnvVars=%u cPostCmdArgs=%u\n",
     
    1036311000#endif
    1036411001    g_cJobs++;
     11002
     11003    /*
     11004     * Expand pszSpecialEnv if present.
     11005     */
     11006    if (*pszSpecialEnv)
     11007    {
     11008        rcExit = kSubmitHandleSpecialEnvVar(cEnvVars, papszEnvVars, pszSpecialEnv, &pszSpecialEnvFree);
     11009        if (!rcExit)
     11010        { /* likely */ }
     11011        else
     11012            return rcExit;
     11013    }
    1036511014
    1036611015    /*
     
    1043411083    else
    1043511084        rcExit = 42 + 1;
     11085    if (pszSpecialEnvFree)
     11086    {
     11087        SetEnvironmentVariableA(pszSpecialEnv, NULL); /* hack */
     11088        kHlpFree(pszSpecialEnvFree);
     11089    }
    1043611090    return rcExit;
    1043711091}
     
    1054411198                                    cbMsg -= 2;
    1054511199
    10546                                     /* Post command argument count (can be zero). */
    10547                                     if (cbMsg >= sizeof(KU32))
     11200                                    /* Name of special enviornment variable requiring selective expansion. */
     11201                                    if (cbMsg >= 1)
    1054811202                                    {
    10549                                         KU32 cPostCmdArgs;
    10550                                         kHlpMemCopy(&cPostCmdArgs, pszMsg, sizeof(cPostCmdArgs));
    10551                                         pszMsg += sizeof(cPostCmdArgs);
    10552                                         cbMsg  -= sizeof(cPostCmdArgs);
    10553 
    10554                                         if (cPostCmdArgs >= 0 && cPostCmdArgs < 32)
     11203                                        const char *pszSpecialEnv = pszMsg;
     11204                                        cbTmp = kHlpStrLen(pszMsg);
     11205                                        pszMsg += cbTmp + 1;
     11206                                        cbMsg  -= K_MIN(cbMsg, cbTmp + 1);
     11207
     11208                                        /* Post command argument count (can be zero). */
     11209                                        if (cbMsg >= sizeof(KU32))
    1055511210                                        {
    10556                                             char const *apszPostCmdArgs[32+1];
    10557                                             for (i = 0; i < cPostCmdArgs; i++)
     11211                                            KU32 cPostCmdArgs;
     11212                                            kHlpMemCopy(&cPostCmdArgs, pszMsg, sizeof(cPostCmdArgs));
     11213                                            pszMsg += sizeof(cPostCmdArgs);
     11214                                            cbMsg  -= sizeof(cPostCmdArgs);
     11215
     11216                                            if (cPostCmdArgs >= 0 && cPostCmdArgs < 32)
    1055811217                                            {
    10559                                                 apszPostCmdArgs[i] = pszMsg;
    10560                                                 cbTmp = kHlpStrLen(pszMsg) + 1;
    10561                                                 pszMsg += cbTmp;
    10562                                                 if (   cbTmp < cbMsg
    10563                                                     || (cbTmp == cbMsg && i + 1 == cPostCmdArgs))
    10564                                                     cbMsg -= cbTmp;
     11218                                                char const *apszPostCmdArgs[32+1];
     11219                                                for (i = 0; i < cPostCmdArgs; i++)
     11220                                                {
     11221                                                    apszPostCmdArgs[i] = pszMsg;
     11222                                                    cbTmp = kHlpStrLen(pszMsg) + 1;
     11223                                                    pszMsg += cbTmp;
     11224                                                    if (   cbTmp < cbMsg
     11225                                                        || (cbTmp == cbMsg && i + 1 == cPostCmdArgs))
     11226                                                        cbMsg -= cbTmp;
     11227                                                    else
     11228                                                    {
     11229                                                        cbMsg = KSIZE_MAX;
     11230                                                        break;
     11231                                                    }
     11232                                                }
     11233                                                if (cbMsg == 0)
     11234                                                {
     11235                                                    apszPostCmdArgs[cPostCmdArgs] = NULL;
     11236
     11237                                                    /*
     11238                                                     * The next step.
     11239                                                     */
     11240                                                    rcExit = kSubmitHandleJobUnpacked(pszExecutable, pszCwd,
     11241                                                                                      cArgs, papszArgs, fWatcomBrainDamange,
     11242                                                                                      cEnvVars, papszEnvVars, pszSpecialEnv,
     11243                                                                                      fNoPchCaching,
     11244                                                                                      cPostCmdArgs, apszPostCmdArgs);
     11245                                                }
     11246                                                else if (cbMsg == KSIZE_MAX)
     11247                                                    kwErrPrintf("Detected bogus message unpacking post command and its arguments!\n");
    1056511248                                                else
    10566                                                 {
    10567                                                     cbMsg = KSIZE_MAX;
    10568                                                     break;
    10569                                                 }
     11249                                                    kwErrPrintf("Message has %u bytes unknown trailing bytes\n", cbMsg);
    1057011250                                            }
    10571                                             if (cbMsg == 0)
    10572                                             {
    10573                                                 apszPostCmdArgs[cPostCmdArgs] = NULL;
    10574 
    10575                                                 /*
    10576                                                  * The next step.
    10577                                                  */
    10578                                                 rcExit = kSubmitHandleJobUnpacked(pszExecutable, pszCwd,
    10579                                                                                   cArgs, papszArgs, fWatcomBrainDamange,
    10580                                                                                   cEnvVars, papszEnvVars, fNoPchCaching,
    10581                                                                                   cPostCmdArgs, apszPostCmdArgs);
    10582                                             }
    10583                                             else if (cbMsg == KSIZE_MAX)
    10584                                                 kwErrPrintf("Detected bogus message unpacking post command and its arguments!\n");
    1058511251                                            else
    10586                                                 kwErrPrintf("Message has %u bytes unknown trailing bytes\n", cbMsg);
     11252                                                kwErrPrintf("Bogus post command argument count: %u %#x\n", cPostCmdArgs, cPostCmdArgs);
    1058711253                                        }
    1058811254                                        else
    10589                                             kwErrPrintf("Bogus post command argument count: %u %#x\n", cPostCmdArgs, cPostCmdArgs);
     11255                                            kwErrPrintf("Detected bogus message looking for the post command argument count!\n");
    1059011256                                    }
    1059111257                                    else
    10592                                         kwErrPrintf("Detected bogus message looking for the post command argument count!\n");
     11258                                        kwErrPrintf("Detected bogus message unpacking special environment variable!\n");
    1059311259                                }
    1059411260                                else
    10595                                     kwErrPrintf("Detected bogus message unpacking environment variables!\n");
     11261                                    kwErrPrintf("Detected bogus message unpacking flags!\n");
    1059611262                                kHlpFree((void *)papszEnvVars);
    1059711263                            }
     
    1088911555    const char *pszCwd = getcwd(szCwd, sizeof(szCwd));
    1089011556    KU32        cEnvVars;
     11557    char      **papszEnvVars;
     11558    const char *pszSpecialEnv = "";
     11559    const char *pszSpecialEnvFull = NULL;
    1089111560    KBOOL       fWatcomBrainDamange = K_FALSE;
    1089211561    KBOOL       fNoPchCaching = K_FALSE;
     
    1093411603        }
    1093511604
     11605        /* Optional directory change. */
     11606        if (   i < argc
     11607            && (   strcmp(argv[i], "--set-special") == 0
     11608                || strcmp(argv[i], "-s")      == 0 ) )
     11609        {
     11610            i++;
     11611            if (i >= argc)
     11612                return kwErrPrintfRc(2, "--set-special takes an argument!\n");
     11613            pszSpecialEnvFull = argv[i++];
     11614            putenv(pszSpecialEnvFull);
     11615            pszSpecialEnv = strdup(pszSpecialEnvFull);
     11616            *strchr(pszSpecialEnv, '=') = '\0';
     11617        }
     11618
    1093611619        /* Trigger breakpoint */
    1093711620        if (   i < argc
     
    1095811641
    1095911642    /*
    10960      * Do the job.
     11643     * Duplicate the environment.
    1096111644     */
    1096211645    cEnvVars = 0;
    1096311646    while (environ[cEnvVars] != NULL)
    1096411647        cEnvVars++;
    10965 
     11648    papszEnvVars = (char **)kHlpAllocZ(sizeof(papszEnvVars[0]) * (cEnvVars + 2));
     11649
     11650    /*
     11651     * Do the job.
     11652     */
    1096611653    for (j = 0; j < cRepeats; j++)
    1096711654    {
     11655        memcpy(papszEnvVars, environ, sizeof(papszEnvVars[0]) * cEnvVars);
    1096811656        rcExit = kSubmitHandleJobUnpacked(argv[i], pszCwd,
    1096911657                                          argc - i, &argv[i], fWatcomBrainDamange,
    10970                                           cEnvVars, environ, fNoPchCaching,
     11658                                          cEnvVars, papszEnvVars, pszSpecialEnv, fNoPchCaching,
    1097111659                                          0, NULL);
    1097211660        KW_LOG(("rcExit=%d\n", rcExit));
    1097311661        kwSandboxCleanupLate(&g_Sandbox);
     11662    }
     11663
     11664    if (getenv("KWORKER_STATS") != NULL)
     11665        kwPrintStats();
     11666
     11667# ifdef WITH_LOG_FILE
     11668    if (g_hLogFile != INVALID_HANDLE_VALUE && g_hLogFile != NULL)
     11669        CloseHandle(g_hLogFile);
     11670# endif
     11671    return rcExit;
     11672}
     11673
     11674
     11675/**
     11676 * Reads @a pszFile into memory and chops it up into an argument vector.
     11677 *
     11678 * @returns Pointer to the argument vector on success, NULL on failure.
     11679 * @param   pszFile         The file to load.
     11680 * @param   pcArgs          Where to return the number of arguments.
     11681 * @param   ppszFileContent Where to return the allocation.
     11682 */
     11683static char **kwFullTestLoadArgvFile(const char *pszFile, int *pcArgs, char **ppszFileContent)
     11684{
     11685    char **papszArgs = NULL;
     11686    FILE  *pFile     = fopen(pszFile, "r");
     11687    if (pFile)
     11688    {
     11689        long cbFile;
     11690        if (   fseek(pFile, 0, SEEK_END) == 0
     11691            && (cbFile = ftell(pFile)) >= 0
     11692            && fseek(pFile, 0, SEEK_SET) == 0)
     11693        {
     11694            char *pszFile = kHlpAllocZ(cbFile + 3);
     11695            if (pszFile)
     11696            {
     11697                size_t cbRead = fread(pszFile, 1, cbFile + 1, pFile);
     11698                if (   feof(pFile)
     11699                    && !ferror(pFile))
     11700                {
     11701                    size_t off        = 0;
     11702                    int    cArgs      = 0;
     11703                    int    cAllocated = 0;
     11704                    char   ch;
     11705
     11706                    pszFile[cbRead]     = '\0';
     11707                    pszFile[cbRead + 1] = '\0';
     11708                    pszFile[cbRead + 2] = '\0';
     11709
     11710                    while ((ch = pszFile[off]) != '\0')
     11711                    {
     11712                        char *pszArg;
     11713                        switch (ch)
     11714                        {
     11715                            case ' ':
     11716                            case '\t':
     11717                            case '\n':
     11718                            case '\r':
     11719                                off++;
     11720                                continue;
     11721
     11722                            case '\\':
     11723                                if (pszFile[off + 1] == '\n' || pszFile[off + 1] == '\r')
     11724                                {
     11725                                    off += 2;
     11726                                    continue;
     11727                                }
     11728                                /* fall thru */
     11729                            default:
     11730                                pszArg = &pszFile[off];
     11731                                do
     11732                                    ch = pszFile[++off];
     11733                                while (ch != '\0' && ch != ' ' && ch != '\t' && ch != '\n' && ch != '\r');
     11734                                pszFile[off++] = '\0';
     11735                                break;
     11736
     11737                            case '\'':
     11738                                pszArg = &pszFile[++off];
     11739                                while ((ch = pszFile[off]) != '\0' && ch != '\'')
     11740                                    off++;
     11741                                pszFile[off++] = '\0';
     11742                                break;
     11743
     11744                            case '\"': /** @todo escape sequences */
     11745                                pszArg = &pszFile[++off];
     11746                                while ((ch = pszFile[off]) != '\0' && ch != '"')
     11747                                    off++;
     11748                                pszFile[off++] = '\0';
     11749                                break;
     11750                        }
     11751                        if (cArgs + 1 >= cAllocated)
     11752                        {
     11753                            void *pvNew;
     11754                            cAllocated = cAllocated ? cAllocated * 2 : 16;
     11755                            pvNew = kHlpRealloc(papszArgs, cAllocated * sizeof(papszArgs[0]));
     11756                            if (pvNew)
     11757                                papszArgs = (char **)pvNew;
     11758                            else
     11759                            {
     11760                                kHlpFree(papszArgs);
     11761                                papszArgs = NULL;
     11762                                break;
     11763                            }
     11764                        }
     11765                        papszArgs[cArgs] = pszArg;
     11766                        papszArgs[++cArgs] = NULL;
     11767                    }
     11768                    *pcArgs = cArgs;
     11769                }
     11770                else
     11771                    kwErrPrintf("Error reading '%s'!\n", pszFile);
     11772            }
     11773            else
     11774                kwErrPrintf("Error allocating %lu bytes!\n", cbFile + 2);
     11775        }
     11776        else
     11777            kwErrPrintf("Error seeking '%s'!\n", pszFile);
     11778        fclose(pFile);
     11779    }
     11780    else
     11781        kwErrPrintf("Error opening '%s'!\n", pszFile);
     11782    return papszArgs;
     11783}
     11784
     11785/**
     11786 * Appends a string to an string vector (arguments or enviornment).
     11787 *
     11788 * @returns 0 on success, non-zero on failure (exit code).
     11789 * @param   ppapszVector    Pointer to the string pointer array.
     11790 * @param   pcEntries       Pointer to the array size.
     11791 * @param   pszAppend       The string to append.
     11792 */
     11793static int kwFullTestVectorAppend(const char ***ppapszVector, int *pcEntries, char const *pszAppend)
     11794{
     11795    unsigned cEntries = *pcEntries;
     11796    if (!(cEntries & 15))
     11797    {
     11798        void *pvNew = kHlpRealloc((void *)*ppapszVector, sizeof(char *) * (cEntries + 16 + 1));
     11799        if (pvNew)
     11800            *ppapszVector = (const char **)pvNew;
     11801        else
     11802            return kwErrPrintfRc(2, "Out of memory!\n");
     11803    }
     11804    (*ppapszVector)[cEntries] = pszAppend;
     11805    (*ppapszVector)[++cEntries] = NULL;
     11806    *pcEntries = cEntries;
     11807    return 0;
     11808}
     11809
     11810
     11811/**
     11812 * Parses arguments for --full-test.
     11813 *
     11814 * @returns 0 on success, non-zero on failure (exit code).
     11815 */
     11816static int kwFullTestRunParseArgs(PKWONETEST *ppHead, int *piState, int argc, char **argv,
     11817                                  const char *pszDefaultCwd, int cRecursions, const char *pszJobSrc)
     11818{
     11819    PKWONETEST pCur = *ppHead;
     11820    int i;
     11821    for (i = 0; i < argc; i++)
     11822    {
     11823        int         rc     = 0;
     11824        const char *pszArg = argv[i];
     11825        if (*pszArg == 'k' && kHlpStrComp(pszArg, "kSubmit") == 0)
     11826        {
     11827            if (*piState != 0)
     11828            {
     11829                pCur = (PKWONETEST)kHlpAllocZ(sizeof(*pCur));
     11830                if (!pCur)
     11831                    return kwErrPrintfRc(2, "Out of memory!\n");
     11832                pCur->fVirgin   = K_TRUE;
     11833                pCur->pszCwd    = pszDefaultCwd;
     11834                pCur->cRuns     = 1;
     11835                pCur->pNext     = *ppHead;
     11836                *ppHead = pCur;
     11837                *piState = 0;
     11838            }
     11839            else if (!pCur->fVirgin)
     11840                return kwErrPrintfRc(2, "Unexpected 'kSubmit' as argument #%u\n", i);
     11841            pCur->pszJobSrc = pszJobSrc;
     11842            pCur->iJobSrc   = i;
     11843            continue; /* (to stay virgin) */
     11844        }
     11845        else if (*pszArg == '-' && *piState == 0)
     11846        {
     11847            const char *pszValue = NULL;
     11848            char        ch       = *++pszArg;
     11849            pszArg++;
     11850            if (ch == '-')
     11851            {
     11852                ch = '\0';
     11853                if (*pszArg == '\0') /* -- */
     11854                    *piState = 2;
     11855                /* Translate or handle long options: */
     11856                else if (kHlpStrComp(pszArg, "putenv") == 0 || kHlpStrComp(pszArg, "set") == 0)
     11857                    ch = 'E';
     11858                else if (kHlpStrComp(pszArg, "special-env") == 0)
     11859                    ch = 's';
     11860                else if (kHlpStrComp(pszArg, "default-env") == 0)
     11861                {
     11862                    unsigned i;
     11863                    pCur->cEnvVars = 0;
     11864                    for (i = 0; environ[i] && rc == 0; i++)
     11865                        rc = kwFullTestVectorAppend(&pCur->papszEnvVars, &pCur->cEnvVars, kHlpStrDup(environ[i])); /* leaks; unchecked */
     11866                }
     11867                else if (kHlpStrComp(pszArg, "chdir") == 0)
     11868                    ch = 'C';
     11869                else if (kHlpStrComp(pszArg, "post-cmd") == 0)
     11870                    ch = 'P';
     11871                else if (kHlpStrComp(pszArg, "response-file") == 0)
     11872                    ch = '@';
     11873                else if (kHlpStrComp(pszArg, "runs") == 0)
     11874                    ch = 'R';
     11875                else if (kHlpStrComp(pszArg, "watcom-brain-damage") == 0)
     11876                    pCur->fWatcomBrainDamange = K_TRUE;
     11877                else if (kHlpStrComp(pszArg, "no-pch-caching") == 0)
     11878                    pCur->fNoPchCaching = K_TRUE;
     11879                else if (kHlpStrComp(pszArg, "executable") == 0)
     11880                    ch = 'e';
     11881                else if (kHlpStrComp(pszArg, "breakpoint") == 0)
     11882                {
     11883                    __debugbreak();
     11884                    continue; /* (to stay virgin) */
     11885                }
     11886                else
     11887                    return kwErrPrintfRc(2, "Unknown option: --%s\n", pszArg);
     11888                pszArg = "";
     11889            }
     11890
     11891            while (ch != '\0' && rc == 0)
     11892            {
     11893                /* Fetch value if needed: */
     11894                switch (ch)
     11895                {
     11896                    case '@':
     11897                    case 'e':
     11898                    case 'E':
     11899                    case 's':
     11900                    case 'C':
     11901                    case 'R':
     11902                        if (*pszArg == ':' || *pszArg == '=')
     11903                            pszValue = &pszArg[1];
     11904                        else if (*pszArg)
     11905                            pszValue = pszArg;
     11906                        else if (i + 1 < argc)
     11907                            pszValue = argv[++i];
     11908                        else
     11909                            return kwErrPrintfRc(2, "Option -%c takes a value\n", ch);
     11910                        pszArg = "";
     11911                        break;
     11912                }
     11913
     11914                /* Handle the option: */
     11915                switch (ch)
     11916                {
     11917                    case 'E':
     11918                        rc = kwFullTestVectorAppend(&pCur->papszEnvVars, &pCur->cEnvVars, pszValue);
     11919                        break;
     11920                    case 'C':
     11921                        pCur->pszCwd = pszValue;
     11922                        break;
     11923                    case 's':
     11924                        pCur->pszSpecialEnv = pszValue;
     11925                        break;
     11926                    case 'e':
     11927                        pCur->pszExecutable = pszValue;
     11928                        break;
     11929                    case 'P':
     11930                        *piState = 1;
     11931                        if (*pszArg)
     11932                            return kwErrPrintfRc(2, "Option -P cannot be followed by other options!\n");
     11933                        break;
     11934                    case 'R':
     11935                        pCur->cRuns = atoi(pszValue);
     11936                        if ((int)pCur->cRuns < 0)
     11937                            return kwErrPrintfRc(2, "Option -R takes a positive (or zero) integer as value: %s\n", pszValue);
     11938                        break;
     11939                    case '@':
     11940                        if (cRecursions < 5)
     11941                        {
     11942                            char    *pszLeaked = NULL;
     11943                            int      cArgs     = 0;
     11944                            char   **papszArgsLeaked = kwFullTestLoadArgvFile(pszValue, &cArgs, &pszLeaked);
     11945                            if (papszArgsLeaked)
     11946                            {
     11947                                rc = kwFullTestRunParseArgs(ppHead, piState, cArgs, papszArgsLeaked, pszDefaultCwd,
     11948                                                            cRecursions + 1, pszValue);
     11949                                pCur = *ppHead;
     11950                            }
     11951                            else
     11952                                return 2;
     11953                        }
     11954                        else
     11955                            return kwErrPrintfRc(2, "Too deep response file nesting!\n");
     11956                        break;
     11957                }
     11958
     11959                /* next */
     11960                ch = *pszArg++;
     11961            }
     11962        }
     11963        else if (*piState == 2)
     11964            rc = kwFullTestVectorAppend(&pCur->papszArgs, &pCur->cArgs, pszArg);
     11965        else if (*piState == 1)
     11966        {
     11967            if (pszArg[0] != '-' || pszArg[1] != '-' || pszArg[2] != '\0')
     11968                rc = kwFullTestVectorAppend(&pCur->papszPostCmdArgs, &pCur->cPostCmdArgs, pszArg);
     11969            else
     11970                *piState = 2;
     11971        }
     11972        else
     11973            return kwErrPrintfRc(2, "Unexpected argument: %s\n", pszArg);
     11974        if (rc)
     11975            return rc;
     11976        pCur->fVirgin = K_FALSE;
     11977    }
     11978    return 0;
     11979}
     11980
     11981
     11982/**
     11983 * Handles what comes after --full-test.
     11984 *
     11985 * @returns Exit code.
     11986 * @param   argc                Number of arguments after --full-test.
     11987 * @param   argv                Arguments after --full-test.
     11988 */
     11989static int kwFullTestRun(int argc, char **argv)
     11990{
     11991    char        szDefaultCwd[MAX_PATH];
     11992    const char *pszDefaultCwd = getcwd(szDefaultCwd, sizeof(szDefaultCwd));
     11993    KWONETEST   FirstTest;
     11994    PKWONETEST  pHead = &FirstTest;
     11995    PKWONETEST  pCur;
     11996    int         iState = 0;
     11997    int         rcExit;
     11998
     11999    /*
     12000     * Parse arguments.
     12001     */
     12002    kHlpMemSet(&FirstTest, 0, sizeof(FirstTest));
     12003    FirstTest.pszJobSrc = "command-line";
     12004    FirstTest.iJobSrc   = 1;
     12005    FirstTest.fVirgin   = K_TRUE;
     12006    FirstTest.pszCwd    = pszDefaultCwd;
     12007    FirstTest.cRuns     = 1;
     12008
     12009    rcExit = kwFullTestRunParseArgs(&pHead, &iState, argc, argv, pszDefaultCwd, 0, "command-line");
     12010    if (rcExit)
     12011        return rcExit;
     12012
     12013    /*
     12014     * Do the job.  LIFO ordering (see kSubmit).
     12015     */
     12016    for (pCur = pHead; pCur; pCur = pCur->pNext)
     12017    {
     12018        if (!pCur->pszExecutable && pCur->papszArgs)
     12019            pCur->pszExecutable = pCur->papszArgs[0];
     12020        if (   pCur->pszExecutable
     12021            && pCur->cArgs > 0
     12022            && pCur->cEnvVars > 0)
     12023        {
     12024            size_t const    cbEnvVarCopy     = sizeof(pCur->papszEnvVars[0]) * (pCur->cEnvVars + 1);
     12025            char ** const   papszEnvVarsCopy = (char **)kHlpDup(pCur->papszEnvVars, cbEnvVarCopy);
     12026            unsigned        iRun;
     12027
     12028            for (iRun = 0; iRun < pCur->cRuns; iRun++)
     12029            {
     12030                rcExit = kSubmitHandleJobUnpacked(pCur->pszExecutable, pCur->pszCwd,
     12031                                                  pCur->cArgs, pCur->papszArgs, pCur->fWatcomBrainDamange,
     12032                                                  pCur->cEnvVars, pCur->papszEnvVars, pCur->pszSpecialEnv,
     12033                                                  pCur->fNoPchCaching, pCur->cPostCmdArgs, pCur->papszPostCmdArgs);
     12034
     12035                KW_LOG(("rcExit=%d\n", rcExit));
     12036                kwSandboxCleanupLate(&g_Sandbox);
     12037
     12038                memcpy((void *)pCur->papszEnvVars, papszEnvVarsCopy, cbEnvVarCopy);
     12039            }
     12040            kHlpFree(papszEnvVarsCopy);
     12041        }
     12042        else
     12043            rcExit = kwErrPrintfRc(2, "Job is underspecified! %s%s%s (Job started with argument #%u, %s)\n",
     12044                                   pCur->pszExecutable ? "" : " No executable!",
     12045                                   pCur->cArgs < 1 ? " No arguments!" : "",
     12046                                   pCur->cEnvVars < 1 ? " No environment!" : "",
     12047                                   pCur->iJobSrc, pCur->pszJobSrc);
    1097412048    }
    1097512049
     
    1116712241        else if (strcmp(argv[i], "--test") == 0)
    1116812242            return kwTestRun(argc - i - 1, &argv[i + 1]);
     12243        else if (strcmp(argv[i], "--full-test") == 0)
     12244            return kwFullTestRun(argc - i - 1, &argv[i + 1]);
    1116912245        else if (strcmp(argv[i], "--priority") == 0)
    1117012246        {
Note: See TracChangeset for help on using the changeset viewer.