VirtualBox

Changeset 95842 in vbox for trunk/src/VBox


Ignore:
Timestamp:
Jul 26, 2022 9:11:14 PM (2 years ago)
Author:
vboxsync
Message:

IPRT/env-generic.cpp: Refactored RTEnvCloneEx, rewriting the cloning of the default environment on windows to be more no-crt compatible and race free. Don't expose RTEnvGetExecEnvP on Windows, removing it from the stable function list. bugref:10261

Location:
trunk/src/VBox/Runtime
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Runtime/Makefile.kmk

    r95834 r95842  
    22602260        common/misc/json.cpp \
    22612261        common/string/ministring.cpp \
    2262         generic/env-generic.cpp \
    22632262        generic/RTLogWriteStdErr-generic.cpp \
    22642263        generic/RTLogWriteStdOut-generic.cpp \
  • trunk/src/VBox/Runtime/VBox/VBoxRTImp.def

    r94871 r95842  
    10041004    RTEnvGet
    10051005    RTEnvGetEx
    1006     RTEnvGetExecEnvP
    10071006    RTEnvPut
    10081007    RTEnvPutEx
  • trunk/src/VBox/Runtime/generic/env-generic.cpp

    r93115 r95842  
    4141#include "internal/magics.h"
    4242
    43 #include <stdlib.h>
    44 #if !defined(RT_OS_WINDOWS)
    45 # include <unistd.h>
    46 #endif
    47 #ifdef RT_OS_DARWIN
    48 # include <crt_externs.h>
    49 #endif
    50 #if defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD) || defined(RT_OS_NETBSD) || defined(RT_OS_OPENBSD)
     43#ifdef RT_OS_WINDOWS
     44# include <iprt/nt/nt.h>
     45#else
     46# include <stdlib.h>
     47# if !defined(RT_OS_WINDOWS)
     48#  include <unistd.h>
     49# endif
     50# ifdef RT_OS_DARWIN
     51#  include <crt_externs.h>
     52# endif
     53# if defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD) || defined(RT_OS_NETBSD) || defined(RT_OS_OPENBSD)
    5154RT_C_DECLS_BEGIN
    5255extern char **environ;
    5356RT_C_DECLS_END
     57# endif
    5458#endif
    5559
     
    6670#define RTENV_UNLOCK(pEnvInt)   do { } while (0)
    6771
    68 /** @def RTENV_HAVE_WENVIRON
    69  * Indicates that we have a _wenviron variable with UTF-16 strings that we
    70  * better use instead of the current-cp strings in environ. */
    71 #if defined(RT_OS_WINDOWS) || defined(DOXYGEN_RUNNING)
    72 # define RTENV_HAVE_WENVIRON 1
    73 #endif
    74 
    7572/** @def RTENV_IMPLEMENTS_UTF8_DEFAULT_ENV_API
    7673 * Indicates the RTEnv*Utf8 APIs are implemented. */
     
    7875# define RTENV_IMPLEMENTS_UTF8_DEFAULT_ENV_API 1
    7976#endif
    80 
    8177
    8278/** @def RTENV_ALLOW_EQUAL_FIRST_IN_VAR
     
    125121
    126122
     123#ifndef RT_OS_WINDOWS
    127124/**
    128125 * Internal worker that resolves the pointer to the default
     
    134131static const char * const *rtEnvDefault(void)
    135132{
    136 #ifdef RT_OS_DARWIN
     133# ifdef RT_OS_DARWIN
    137134    return *(_NSGetEnviron());
    138 #else
     135# else
    139136    return environ;
     137# endif
     138}
    140139#endif
    141 }
    142140
    143141
     
    254252
    255253
    256 RTDECL(int) RTEnvClone(PRTENV pEnv, RTENV EnvToClone)
    257 {
    258     /*
    259      * Validate input and figure out how many variable to clone and where to get them.
    260      */
     254static int rtEnvCloneDefault(PRTENV phEnv)
     255{
     256#ifdef RTENV_ALLOW_EQUAL_FIRST_IN_VAR
     257    bool const fFirstEqual = true;
     258#else
     259    bool const fFirstEqual = false;
     260#endif
     261
     262#ifdef RT_OS_WINDOWS
     263    /*
     264     * Lock the PEB, get the process environment.
     265     *
     266     * On older windows version GetEnviornmentStringsW will not copy the
     267     * environment block, but return the pointer stored in the PEB.  This
     268     * should be safer wrt to concurrent changes.
     269     */
     270    PPEB pPeb = RTNtCurrentPeb();
     271
     272    RtlAcquirePebLock();
     273
     274    /* Count variables in the block: */
     275    size_t    cVars    = 0;
     276    PCRTUTF16 pwszzEnv = pPeb->ProcessParameters ? pPeb->ProcessParameters->Environment : NULL;
     277    if (pwszzEnv)
     278    {
     279        PCRTUTF16 pwsz = pwszzEnv;
     280        while (*pwsz)
     281        {
     282            cVars++;
     283            pwsz += RTUtf16Len(pwsz) + 1;
     284        }
     285    }
     286
     287    PRTENVINTERNAL pIntEnv;
     288    int rc = rtEnvCreate(&pIntEnv, cVars + 1 /* NULL */, false /*fCaseSensitive*/, false /*fPutEnvBlock*/, fFirstEqual);
     289    if (RT_SUCCESS(rc))
     290    {
     291        size_t iDst;
     292        for (iDst = 0; iDst < cVars && *pwszzEnv; iDst++, pwszzEnv += RTUtf16Len(pwszzEnv) + 1)
     293        {
     294            int rc2 = RTUtf16ToUtf8(pwszzEnv, &pIntEnv->papszEnv[iDst]);
     295            if (RT_SUCCESS(rc2))
     296            {
     297                /* Make sure it contains an '='. */
     298                if (strchr(pIntEnv->papszEnv[iDst], '='))
     299                    continue;
     300                rc2 = RTStrAAppend(&pIntEnv->papszEnv[iDst], "=");
     301                if (RT_SUCCESS(rc2))
     302                    continue;
     303            }
     304
     305            /* failed fatally. */
     306            pIntEnv->cVars = iDst + 1;
     307            RtlReleasePebLock();
     308            RTEnvDestroy(pIntEnv);
     309            return rc2;
     310        }
     311
     312        Assert(!*pwszzEnv); Assert(iDst == cVars);
     313        pIntEnv->cVars = iDst;
     314        pIntEnv->papszEnv[iDst] = NULL;
     315
     316        /* done */
     317        *phEnv = pIntEnv;
     318    }
     319
     320    RtlReleasePebLock();
     321    return rc;
     322
     323#else /* !RT_OS_WINDOWS */
     324
     325    /*
     326     * Figure out how many variable to clone.
     327     */
     328    const char * const *papszEnv = rtEnvDefault();
     329    size_t              cVars = 0;
     330    if (papszEnv)
     331        while (papszEnv[cVars])
     332            cVars++;
     333
    261334    bool fCaseSensitive = true;
    262     bool fPutEnvBlock   = false;
    263     bool fFirstEqual    = false;
    264     size_t cVars;
    265     const char * const *papszEnv;
    266 #ifdef RTENV_HAVE_WENVIRON
    267     PCRTUTF16 const * papwszEnv = NULL;
    268 #endif
    269     PRTENVINTERNAL pIntEnvToClone;
    270     AssertPtrReturn(pEnv, VERR_INVALID_POINTER);
    271     if (EnvToClone == RTENV_DEFAULT)
    272     {
    273         cVars = 0;
    274         pIntEnvToClone = NULL;
    275 #ifdef RTENV_HAVE_WENVIRON
    276         papszEnv  = NULL;
    277         papwszEnv = (PCRTUTF16 * const)_wenviron;
    278         if (!papwszEnv)
    279         {
    280             _wgetenv(L"Path"); /* Force the CRT to initalize it. */
    281             papwszEnv = (PCRTUTF16 * const)_wenviron;
    282         }
    283         if (papwszEnv)
    284             while (papwszEnv[cVars])
    285                 cVars++;
    286 #else
    287         papszEnv = rtEnvDefault();
    288         if (papszEnv)
    289             while (papszEnv[cVars])
    290                 cVars++;
    291 #endif
    292 
    293 #if defined(RT_OS_OS2) || defined(RT_OS_WINDOWS)
    294         /* DOS systems was case insensitive.  A prime example is the 'Path'
    295            variable on windows which turns into the 'PATH' variable. */
    296         fCaseSensitive = false;
    297 #endif
    298 #ifdef RTENV_ALLOW_EQUAL_FIRST_IN_VAR
    299         fFirstEqual = true;
    300 #endif
    301     }
     335# if defined(RT_OS_OS2) || defined(RT_OS_WINDOWS)
     336    /* DOS systems was case insensitive.  A prime example is the 'Path'
     337       variable on windows which turns into the 'PATH' variable. */
     338    fCaseSensitive = false;
     339# endif
     340
     341    /*
     342     * Create the duplicate.
     343     */
     344    PRTENVINTERNAL pIntEnv;
     345    int rc = rtEnvCreate(&pIntEnv, cVars + 1 /* NULL */, fCaseSensitive, false /*fPutEnvBlock*/, fFirstEqual);
     346    if (RT_SUCCESS(rc))
     347    {
     348        pIntEnv->cVars = cVars;
     349        pIntEnv->papszEnv[pIntEnv->cVars] = NULL;
     350
     351        /* ASSUMES the default environment is in the current codepage. */
     352        size_t  iDst = 0;
     353        for (size_t iSrc = 0; iSrc < cVars; iSrc++)
     354        {
     355            int rc2 = RTStrCurrentCPToUtf8(&pIntEnv->papszEnv[iDst], papszEnv[iSrc]);
     356            if (RT_SUCCESS(rc2))
     357            {
     358                /* Make sure it contains an '='. */
     359                iDst++;
     360                if (strchr(pIntEnv->papszEnv[iDst - 1], '='))
     361                    continue;
     362                rc2 = RTStrAAppend(&pIntEnv->papszEnv[iDst - 1], "=");
     363                if (RT_SUCCESS(rc2))
     364                    continue;
     365            }
     366            else if (rc2 == VERR_NO_TRANSLATION)
     367            {
     368                rc = VWRN_ENV_NOT_FULLY_TRANSLATED;
     369                continue;
     370            }
     371
     372            /* failed fatally. */
     373            pIntEnv->cVars = iDst;
     374            RTEnvDestroy(pIntEnv);
     375            return rc2;
     376        }
     377        pIntEnv->cVars = iDst;
     378
     379        /* done */
     380        *phEnv = pIntEnv;
     381    }
     382
     383    return rc;
     384#endif /* !RT_OS_WINDOWS */
     385}
     386
     387
     388/**
     389 * Clones a non-default environment instance.
     390 *
     391 * @param   phEnv           Where to return the handle to the cloned environment.
     392 * @param   pIntEnvToClone  The source environment. Caller takes care of
     393 *                          locking.
     394 */
     395static int rtEnvCloneNonDefault(PRTENV phEnv, PRTENVINTERNAL pIntEnvToClone)
     396{
     397    PRTENVINTERNAL pIntEnv;
     398    size_t const cVars = pIntEnvToClone->cVars;
     399    int rc = rtEnvCreate(&pIntEnv, cVars + 1 /* NULL */,
     400                         pIntEnvToClone->pfnCompare != RTStrNICmp,
     401                         pIntEnvToClone->fPutEnvBlock,
     402                         pIntEnvToClone->fFirstEqual);
     403    if (RT_SUCCESS(rc))
     404    {
     405        pIntEnv->cVars = cVars;
     406        pIntEnv->papszEnv[cVars] = NULL;
     407
     408        const char * const * const papszEnv = pIntEnvToClone->papszEnv;
     409        for (size_t iVar = 0; iVar < cVars; iVar++)
     410        {
     411            char *pszVar = RTStrDup(papszEnv[iVar]);
     412            if (RT_UNLIKELY(!pszVar))
     413            {
     414                pIntEnv->cVars = iVar;
     415                RTEnvDestroy(pIntEnv);
     416                return VERR_NO_STR_MEMORY;
     417            }
     418            pIntEnv->papszEnv[iVar] = pszVar;
     419        }
     420
     421        /* done */
     422        *phEnv = pIntEnv;
     423    }
     424    return rc;
     425}
     426
     427
     428RTDECL(int) RTEnvClone(PRTENV phEnv, RTENV hEnvToClone)
     429{
     430    /*
     431     * Validate input and what kind of source block we're working with.
     432     */
     433    int rc;
     434    AssertPtrReturn(phEnv, VERR_INVALID_POINTER);
     435    if (hEnvToClone == RTENV_DEFAULT)
     436        rc = rtEnvCloneDefault(phEnv);
    302437    else
    303438    {
    304         pIntEnvToClone = EnvToClone;
     439        PRTENVINTERNAL pIntEnvToClone = hEnvToClone;
    305440        AssertPtrReturn(pIntEnvToClone, VERR_INVALID_HANDLE);
    306441        AssertReturn(pIntEnvToClone->u32Magic == RTENV_MAGIC, VERR_INVALID_HANDLE);
     442
    307443        RTENV_LOCK(pIntEnvToClone);
    308 
    309         fPutEnvBlock = pIntEnvToClone->fPutEnvBlock;
    310         fFirstEqual = pIntEnvToClone->fFirstEqual;
    311         papszEnv = pIntEnvToClone->papszEnv;
    312         cVars = pIntEnvToClone->cVars;
    313     }
    314 
    315     /*
    316      * Create the duplicate.
    317      */
    318     PRTENVINTERNAL pIntEnv;
    319     int rc = rtEnvCreate(&pIntEnv, cVars + 1 /* NULL */, fCaseSensitive, fPutEnvBlock, fFirstEqual);
    320     if (RT_SUCCESS(rc))
    321     {
    322         pIntEnv->cVars = cVars;
    323         pIntEnv->papszEnv[pIntEnv->cVars] = NULL;
    324         if (EnvToClone == RTENV_DEFAULT)
    325         {
    326             /* ASSUMES the default environment is in the current codepage. */
    327             size_t  iDst = 0;
    328             for (size_t iSrc = 0; iSrc < cVars; iSrc++)
    329             {
    330 #ifdef RTENV_HAVE_WENVIRON
    331                 int rc2 = RTUtf16ToUtf8(papwszEnv[iSrc], &pIntEnv->papszEnv[iDst]);
    332 #else
    333                 int rc2 = RTStrCurrentCPToUtf8(&pIntEnv->papszEnv[iDst], papszEnv[iSrc]);
    334 #endif
    335                 if (RT_SUCCESS(rc2))
    336                 {
    337                     /* Make sure it contains an '='. */
    338                     iDst++;
    339                     if (strchr(pIntEnv->papszEnv[iDst - 1], '='))
    340                         continue;
    341                     rc2 = RTStrAAppend(&pIntEnv->papszEnv[iDst - 1], "=");
    342                     if (RT_SUCCESS(rc2))
    343                         continue;
    344                 }
    345                 else if (rc2 == VERR_NO_TRANSLATION)
    346                 {
    347                     rc = VWRN_ENV_NOT_FULLY_TRANSLATED;
    348                     continue;
    349                 }
    350 
    351                 /* failed fatally. */
    352                 pIntEnv->cVars = iDst;
    353                 RTEnvDestroy(pIntEnv);
    354                 return rc2;
    355             }
    356             pIntEnv->cVars = iDst;
    357         }
    358         else
    359         {
    360             for (size_t iVar = 0; iVar < cVars; iVar++)
    361             {
    362                 char *pszVar = RTStrDup(papszEnv[iVar]);
    363                 if (RT_UNLIKELY(!pszVar))
    364                 {
    365                     RTENV_UNLOCK(pIntEnvToClone);
    366 
    367                     pIntEnv->cVars = iVar;
    368                     RTEnvDestroy(pIntEnv);
    369                     return VERR_NO_STR_MEMORY;
    370                 }
    371                 pIntEnv->papszEnv[iVar] = pszVar;
    372             }
    373         }
    374 
    375         /* done */
    376         *pEnv = pIntEnv;
    377     }
    378 
    379     if (pIntEnvToClone)
     444        rc = rtEnvCloneNonDefault(phEnv, pIntEnvToClone);
    380445        RTENV_UNLOCK(pIntEnvToClone);
     446    }
    381447    return rc;
    382448}
     
    917983
    918984
     985#ifndef RT_OS_WINDOWS
    919986RTDECL(char const * const *) RTEnvGetExecEnvP(RTENV Env)
    920987{
     
    9791046}
    9801047RT_EXPORT_SYMBOL(RTEnvGetExecEnvP);
     1048#endif /* !RT_OS_WINDOWS */
    9811049
    9821050
  • trunk/src/VBox/Runtime/testcase/tstRTEnv.cpp

    r93115 r95842  
    303303     * execve envp and we're done.
    304304     */
     305#ifndef RT_OS_WINDOWS
    305306    RTTestSub(hTest, "RTEnvGetExecEnvP");
    306     const char * const *papsz = RTEnvGetExecEnvP(RTENV_DEFAULT);
     307    papsz = RTEnvGetExecEnvP(RTENV_DEFAULT);
    307308    CHECK(papsz != NULL);
    308309    papsz = RTEnvGetExecEnvP(RTENV_DEFAULT);
     
    313314    papsz = RTEnvGetExecEnvP(Env);
    314315    CHECK(papsz != NULL);
     316#endif
    315317
    316318    CHECK_RC(RTEnvDestroy(Env), VINF_SUCCESS);
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette