Consolidate environment code in environ.cpp.
authorAditya Mandaleeka <adityam@microsoft.com>
Tue, 9 Feb 2016 00:14:57 +0000 (16:14 -0800)
committerAditya Mandaleeka <adityam@microsoft.com>
Fri, 26 Feb 2016 20:52:14 +0000 (12:52 -0800)
Commit migrated from https://github.com/dotnet/coreclr/commit/404c73d924bd999df383a5ed46ca6d65d9b57131

src/coreclr/src/pal/src/cruntime/misc.cpp
src/coreclr/src/pal/src/debug/debug.cpp
src/coreclr/src/pal/src/include/pal/environ.h [new file with mode: 0644]
src/coreclr/src/pal/src/include/pal/misc.h
src/coreclr/src/pal/src/init/pal.cpp
src/coreclr/src/pal/src/misc/dbgmsg.cpp
src/coreclr/src/pal/src/misc/environ.cpp
src/coreclr/src/pal/src/thread/process.cpp
src/coreclr/src/pal/src/thread/thread.cpp

index 107d5e3..d267341 100644 (file)
@@ -20,7 +20,6 @@ Abstract:
 
 #include "pal/thread.hpp"
 #include "pal/threadsusp.hpp"
-#include "pal/malloc.hpp"
 #include "pal/palinternal.h"
 #include "pal/dbgmsg.h"
 #include "pal/misc.h"
@@ -43,10 +42,6 @@ Abstract:
 
 SET_DEFAULT_DEBUG_CHANNEL(CRT);
 
-char **palEnvironment = NULL;
-
-CRITICAL_SECTION gcsEnvironment;
-
 using namespace CorUnix;
 
 /*++
@@ -139,65 +134,6 @@ int * __cdecl PAL_errno( int caller )
 }
 
 /*++
-
-Function : _putenv.
-    
-See MSDN for more details.
-
-Note:   The BSD implementation can cause
-        memory leaks. See man pages for more details.
---*/
-int
-__cdecl 
-_putenv( const char * envstring )
-{
-    int ret = -1;
-
-    PERF_ENTRY(_putenv);
-    ENTRY( "_putenv( %p (%s) )\n", envstring ? envstring : "NULL", envstring ? envstring : "NULL") ;
-    
-    if (!envstring)
-    {
-        ERROR( "_putenv() called with NULL envstring!\n");
-        goto EXIT;
-    }
-
-    ret = MiscPutenv(envstring, TRUE) ? 0 : -1;
-
-EXIT:    
-    LOGEXIT( "_putenv returning %d\n", ret);
-    PERF_EXIT(_putenv);
-    return ret;
-}
-
-/*++
-
-Function : PAL_getenv
-    
-See MSDN for more details.
---*/
-char * __cdecl PAL_getenv(const char *varname)
-{
-    char *retval;
-
-    PERF_ENTRY(getenv);
-    ENTRY("getenv (%p (%s))\n", varname ? varname : "NULL", varname ? varname : "NULL");
-    
-    if (strcmp(varname, "") == 0)
-    {
-        ERROR("getenv called with a empty variable name\n");
-        LOGEXIT("getenv returning NULL\n");
-        PERF_EXIT(getenv);
-        return(NULL);
-    }
-    retval = MiscGetenv(varname);
-
-    LOGEXIT("getenv returning %p\n", retval);
-    PERF_EXIT(getenv);
-    return(retval);
-}
-
-/*++
 Function:
 
     mktime
@@ -361,306 +297,6 @@ void PAL__mm_setcsr(unsigned int i)
 
 #endif // _AMD64_ 
 
-/*++
-Function:
-  MiscGetEnvArray
-
-Get a reference to the process's environ array into palEnvironment
-
-NOTE: This function MUST be called while holding the gcsEnvironment 
-      critical section (except if the caller is the initialization 
-      routine)
---*/
-void
-MiscGetEnvArray(void)
-{
-#if HAVE__NSGETENVIRON
-    palEnvironment = *(_NSGetEnviron());
-#else   // HAVE__NSGETENVIRON
-    extern char **environ;
-    palEnvironment = environ;
-#endif  // HAVE__NSGETENVIRON
-}
-
-/*++
-Function:
-  MiscSetEnvArray
-
-Make sure the process's environ array is in sync with palEnvironment variable
-
-NOTE: This function MUST be called while holding the gcsEnvironment 
-      critical section (except if the caller is the initialization 
-      routine)
---*/
-void
-MiscSetEnvArray(void)
-{
-#if HAVE__NSGETENVIRON
-    *(_NSGetEnviron()) = palEnvironment;
-#else   // HAVE__NSGETENVIRON
-    extern char **environ;
-    environ = palEnvironment;
-#endif  // HAVE__NSGETENVIRON
-}
-
-/*++
-Function:
-  MiscInitialize
-
-Initialization function called from PAL_Initialize.
-Allocates the TLS Index. On systems that use extern variables for
-time zone information, this also initializes those variables.
-
-Note: This is called before debug channels are initialized, so it
-      cannot use debug tracing calls.
---*/
-BOOL
-MiscInitialize(void)
-{
-    InternalInitializeCriticalSection(&gcsEnvironment);
-    MiscGetEnvArray();
-
-    return TRUE;
-}
-
-/*++
-Function:
-  MiscCleanup
-
-Termination function called from PAL_Terminate to delete the
-TLS Keys created in MiscInitialize
---*/
-void MiscCleanup(void)
-{
-     TRACE("Cleaning Misc...\n");
-     InternalDeleteCriticalSection(&gcsEnvironment);
-}
-
-/*++
-Function:
-  MiscGetenv
-
-Gets an environment variable's value from environ. The returned buffer
-must not be modified or freed.
---*/
-char *MiscGetenv(const char *name)
-{
-    int i, length;
-    char *equals;
-    char *pRet = NULL;
-    CPalThread * pthrCurrent = InternalGetCurrentThread();
-
-    InternalEnterCriticalSection(pthrCurrent, &gcsEnvironment);
-
-    length = strlen(name);
-    for(i = 0; palEnvironment[i] != NULL; i++)
-    {
-        if (memcmp(palEnvironment[i], name, length) == 0)
-        {
-            equals = palEnvironment[i] + length;
-            if (*equals == '\0')
-            {
-                pRet = (char *) "";
-                goto done;
-            } 
-            else if (*equals == '=') 
-            {
-                pRet = equals + 1;
-                goto done;
-            }
-        }
-    }
-
-done:
-    InternalLeaveCriticalSection(pthrCurrent, &gcsEnvironment);
-    return pRet;
-}
-
-
-/*++
-Function:
-  MiscPutenv
-
-Sets an environment variable's value by directly modifying palEnvironment.
-Returns TRUE if the variable was set, or FALSE if PAL_malloc or realloc
-failed or if the given string is malformed.
---*/
-BOOL MiscPutenv(const char *string, BOOL deleteIfEmpty)
-{
-    const char *equals, *existingEquals;
-    char *copy = NULL;
-    int length;
-    int i, j;
-    bool fOwningCS = false;
-    BOOL result = FALSE;
-    CPalThread * pthrCurrent = InternalGetCurrentThread();
-    
-    equals = strchr(string, '=');
-    if (equals == string || equals == NULL)
-    {
-        // "=foo" and "foo" have no meaning
-        goto done;
-    }
-    if (equals[1] == '\0' && deleteIfEmpty)
-    {
-        // "foo=" removes foo from the environment in _putenv() on Windows.
-        // The same string can result from a call to SetEnvironmentVariable()
-        // with the empty string as the value, but in that case we want to
-        // set the variable's value to "". deleteIfEmpty will be FALSE in
-        // that case.
-        length = strlen(string);
-        copy = (char *) InternalMalloc(length);
-        if (copy == NULL)
-        {
-            goto done;
-        }
-        memcpy(copy, string, length - 1);
-        copy[length - 1] = '\0';    // Change '=' to '\0'
-        MiscUnsetenv(copy);
-        result = TRUE;
-    }
-    else
-    {
-        // See if we are replacing an item or adding one.
-        
-        // Make our copy up front, since we'll use it either way.
-        copy = strdup(string);
-        if (copy == NULL)
-        {
-            goto done;
-        }
-        
-        length = equals - string;
-
-        InternalEnterCriticalSection(pthrCurrent, &gcsEnvironment);
-        fOwningCS = true;
-        
-        for(i = 0; palEnvironment[i] != NULL; i++)
-        {
-            existingEquals = strchr(palEnvironment[i], '=');
-            if (existingEquals == NULL)
-            {
-                // The PAL screens out malformed strings, but
-                // environ comes from the system, so it might
-                // have strings without '='. We treat the entire
-                // string as a name in that case.
-                existingEquals = palEnvironment[i] + strlen(palEnvironment[i]);
-            }
-            if (existingEquals - palEnvironment[i] == length)
-            {
-                if (memcmp(string, palEnvironment[i], length) == 0)
-                {
-                    // Replace this one. Don't free the original,
-                    // though, because there may be outstanding
-                    // references to it that were acquired via
-                    // getenv. This is an unavoidable memory leak.
-                    palEnvironment[i] = copy;
-                    
-                    // Set 'copy' to NULL so it won't be freed
-                    copy = NULL;
-                    
-                    result = TRUE;
-                    break;
-                }
-            }
-        }
-        if (palEnvironment[i] == NULL)
-        {            
-            static BOOL sAllocatedEnviron = FALSE;
-            // Add a new environment variable.
-            // We'd like to realloc palEnvironment, but we can't do that the
-            // first time through.
-            char **newEnviron = NULL;
-            
-            if (sAllocatedEnviron) {
-                if (NULL == (newEnviron = 
-                        (char **)InternalRealloc(palEnvironment, (i + 2) * sizeof(char *))))
-                {
-                    goto done;
-                }
-            }
-            else
-            {
-                // Allocate palEnvironment ourselves so we can realloc it later.
-                newEnviron = (char **)InternalMalloc((i + 2) * sizeof(char *));
-                if (newEnviron == NULL)
-                {
-                    goto done;
-                }
-                for(j = 0; palEnvironment[j] != NULL; j++)
-                {
-                    newEnviron[j] = palEnvironment[j];
-                }
-                sAllocatedEnviron = TRUE;
-            }
-            palEnvironment = newEnviron;
-            MiscSetEnvArray();
-            palEnvironment[i] = copy;
-            palEnvironment[i + 1] = NULL;
-
-            // Set 'copy' to NULL so it won't be freed
-            copy = NULL;
-            
-            result = TRUE;
-        }
-    }
-done:
-
-    if (fOwningCS)
-    {
-        InternalLeaveCriticalSection(pthrCurrent, &gcsEnvironment);
-    }
-    if (NULL != copy)
-    {
-        InternalFree(copy);
-    }
-    return result;
-}
-
-/*++
-Function:
-  MiscUnsetenv
-
-Removes a variable from the environment. Does nothing if the variable
-does not exist in the environment.
---*/
-void MiscUnsetenv(const char *name)
-{
-    const char *equals;
-    int length;
-    int i, j;
-    CPalThread * pthrCurrent = InternalGetCurrentThread();
-    
-    length = strlen(name);
-
-    InternalEnterCriticalSection(pthrCurrent, &gcsEnvironment);
-    for(i = 0; palEnvironment[i] != NULL; i++)
-    {
-        equals = strchr(palEnvironment[i], '=');
-        if (equals == NULL)
-        {
-            equals = palEnvironment[i] + strlen(palEnvironment[i]);
-        }
-        if (equals - palEnvironment[i] == length)
-        {
-            if (memcmp(name, palEnvironment[i], length) == 0)
-            {
-                // Remove this one. Don't free it, though, since
-                // there might be oustanding references to it that
-                // were acquired via getenv. This is an
-                // unavoidable memory leak.
-                for(j = i + 1; palEnvironment[j] != NULL; j++) { }
-                // i is now the one we want to remove. j is the
-                // last index in palEnvironment, which is NULL.
-
-                // Shift palEnvironment down by the difference between i and j.
-                memmove(palEnvironment + i, palEnvironment + i + 1, (j - i) * sizeof(char *));
-            }
-        }
-    }
-    InternalLeaveCriticalSection(pthrCurrent, &gcsEnvironment);
-}
-
 #if defined(_DEBUG)
 
 /*++
index dd4ea27..c71bf59 100644 (file)
@@ -34,7 +34,7 @@ Revision History:
 #include "pal/process.h"
 #include "pal/context.h"
 #include "pal/debug.h"
-#include "pal/misc.h"
+#include "pal/environ.h"
 #include "pal/malloc.hpp"
 #include "pal/module.h"
 #include "pal/stackstring.hpp"
@@ -174,15 +174,15 @@ OutputDebugStringA(
     ENTRY("OutputDebugStringA (lpOutputString=%p (%s))\n",
           lpOutputString?lpOutputString:"NULL",
           lpOutputString?lpOutputString:"NULL");
-    
+
     /* as we don't support debug events, we are going to output the debug string
       to stderr instead of generating OUT_DEBUG_STRING_EVENT */
     if ( (lpOutputString != NULL) && 
-         (NULL != MiscGetenv(PAL_OUTPUTDEBUGSTRING)))
+         (NULL != EnvironGetenv(PAL_OUTPUTDEBUGSTRING)))
     {
         fprintf(stderr, "%s", lpOutputString);
     }
-        
+
     LOGEXIT("OutputDebugStringA returns\n");
     PERF_EXIT(OutputDebugStringA);
 }
@@ -370,7 +370,7 @@ DebugBreakCommand()
            variables in the child process, but if we do that we can't check
            for errors. putenv/setenv can fail when out of memory */
 
-        if (!MiscPutenv (pid_buf, FALSE) || !MiscPutenv (exe_buf, FALSE)) {
+        if (!EnvironPutenv (pid_buf, FALSE) || !EnvironPutenv (exe_buf, FALSE)) {
             goto FAILED;
         }
         if (run_debug_command (command_string)) {
diff --git a/src/coreclr/src/pal/src/include/pal/environ.h b/src/coreclr/src/pal/src/include/pal/environ.h
new file mode 100644 (file)
index 0000000..00082e7
--- /dev/null
@@ -0,0 +1,78 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+    include/pal/environ.h
+
+Abstract:
+    Header file for functions manipulating environment variables
+
+
+--*/
+
+#ifndef __ENVIRON_H_
+#define __ENVIRON_H_
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif // __cplusplus
+
+/*++
+Variables :
+
+    palEnvironment: a global variable equivalent to environ on systems on 
+                    which that exists, and a pointer to an array of environment 
+                    strings on systems without environ.
+    gcsEnvironment: critical section to synchronize access to palEnvironment
+--*/
+extern char **palEnvironment;
+extern CRITICAL_SECTION gcsEnvironment;
+
+/*++
+
+Function:
+  EnvironInitialize
+
+--*/
+BOOL EnvironInitialize();//////////////
+
+/*++
+Function:
+  EnvironGetenv
+
+Gets an environment variable's value.
+--*/
+char *EnvironGetenv(const char *name);
+
+/*++
+Function:
+  EnvironPutenv
+
+Sets an environment variable's value.
+Returns TRUE if the variable was set, or FALSE if malloc or realloc
+failed or if the given string is malformed.
+--*/
+BOOL EnvironPutenv(const char *string, BOOL deleteIfEmpty);
+
+/*++
+Function:
+  EnvironUnsetenv
+
+Removes a variable from the environment. Does nothing if the variable
+does not exist in the environment.
+--*/
+void EnvironUnsetenv(const char *name);
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif /* __ENVIRON_H_ */
+
index 2be2cc0..65d59ae 100644 (file)
@@ -27,17 +27,6 @@ extern "C"
 #endif // __cplusplus
 
 /*++
-Variables :
-
-    palEnvironment: a global variable equivalent to environ on systems on 
-                    which that exists, and a pointer to an array of environment 
-                    strings on systems without environ.
-    gcsEnvironment: critical section to synchronize access to palEnvironment
---*/
-extern char **palEnvironment;
-extern CRITICAL_SECTION gcsEnvironment;
-
-/*++
 Function :
 
     PAL_rand
@@ -87,49 +76,6 @@ Function :
 --*/
 void MsgBoxCleanup( void );
 
-/*++
-
-Function:
-  MiscInitialize
-
---*/
-BOOL MiscInitialize();
-
-/*++
-Function:
-  MiscCleanup
-
---*/
-VOID MiscCleanup();
-
-/*++
-Function:
-  MiscGetenv
-
-Gets an environment variable's value from environ. The returned buffer
-must not be modified or freed.
---*/
-char *MiscGetenv(const char *name);
-
-/*++
-Function:
-  MiscPutenv
-
-Sets an environment variable's value by directly modifying environ.
-Returns TRUE if the variable was set, or FALSE if malloc or realloc
-failed or if the given string is malformed.
---*/
-BOOL MiscPutenv(const char *string, BOOL deleteIfEmpty);
-
-/*++
-Function:
-  MiscUnsetenv
-
-Removes a variable from the environment. Does nothing if the variable
-does not exist in the environment.
---*/
-void MiscUnsetenv(const char *name);
-
 #ifdef __cplusplus
 }
 #endif // __cplusplus
index b2efdf2..95c6e59 100644 (file)
@@ -34,6 +34,7 @@ Abstract:
 #include "pal/module.h"
 #include "pal/virtual.h"
 #include "pal/misc.h"
+#include "pal/environ.h"
 #include "pal/utils.h"
 #include "pal/debug.h"
 #include "pal/locale.h"
@@ -240,14 +241,14 @@ Initialize(
         }
 
         // Initialize the environment.
-        if (FALSE == MiscInitialize())
+        if (FALSE == EnvironInitialize())
         {
             goto CLEANUP0;
         }
 
         // Initialize debug channel settings before anything else.
         // This depends on the environment, so it must come after
-        // MiscInitialize.
+        // EnvironInitialize.
         if (FALSE == DBG_init_channels())
         {
             goto CLEANUP0;
@@ -1182,7 +1183,7 @@ static LPWSTR INIT_FindEXEPath(LPCSTR exe_name)
 
     /* no path was specified : search $PATH */
 
-    env_path = MiscGetenv("PATH");
+    env_path = EnvironGetenv("PATH");
     if (!env_path || *env_path=='\0')
     {
         WARN("$PATH isn't set.\n");
@@ -1327,7 +1328,7 @@ static LPWSTR INIT_FindEXEPath(LPCSTR exe_name)
     }
 
     InternalFree(env_path);
-    TRACE("No %s found in $PATH (%s)\n", exe_name, MiscGetenv("PATH"));
+    TRACE("No %s found in $PATH (%s)\n", exe_name, EnvironGetenv("PATH"));
 
 last_resort:
     /* last resort : see if the executable is in the current directory. This is
index f03db0a..7ff0f26 100644 (file)
@@ -29,7 +29,7 @@ Abstract:
 #include "pal/cruntime.h"
 #include "pal/critsect.h"
 #include "pal/file.h"
-#include "pal/misc.h"
+#include "pal/environ.h"
 
 /* standard headers */
 
@@ -168,7 +168,7 @@ BOOL DBG_init_channels(void)
 
     /* parse PAL_DBG_CHANNELS environment variable */
 
-    if (!(env_string = MiscGetenv(ENV_CHANNELS))) 
+    if (!(env_string = EnvironGetenv(ENV_CHANNELS))) 
     {
         env_pcache = env_workstring = NULL;
     }
@@ -316,7 +316,7 @@ BOOL DBG_init_channels(void)
     PAL_free(env_pcache);
 
     /* select output file */
-    env_string=MiscGetenv(ENV_FILE);
+    env_string = EnvironGetenv(ENV_FILE);
     if(env_string && *env_string!='\0')
     {
         if(!strcmp(env_string, "stderr"))
@@ -347,7 +347,7 @@ BOOL DBG_init_channels(void)
     }
 
     /* see if we need to disable assertions */
-    env_string = MiscGetenv(ENV_ASSERTS);
+    env_string = EnvironGetenv(ENV_ASSERTS);
     if(env_string && 0 == strcmp(env_string,"1"))
     {
         g_Dbg_asserts_enabled = FALSE;
@@ -358,7 +358,7 @@ BOOL DBG_init_channels(void)
     }
 
     /* select ENTRY level limitation */
-    env_string = MiscGetenv(ENV_ENTRY_LEVELS);    
+    env_string = EnvironGetenv(ENV_ENTRY_LEVELS);    
     if(env_string)
     {
         max_entry_level = atoi(env_string);
index e715db0..4cab464 100644 (file)
@@ -8,7 +8,7 @@
 
 Module Name:
 
-    environ.c
+    environ.cpp
 
 Abstract:
 
@@ -23,12 +23,18 @@ Revision History:
 #include "pal/palinternal.h"
 #include "pal/critsect.h"
 #include "pal/dbgmsg.h"
-#include "pal/misc.h"
+#include "pal/environ.h"
+#include "pal/malloc.hpp"
 
 #include <stdlib.h>
 
+using namespace CorUnix;
+
 SET_DEFAULT_DEBUG_CHANNEL(MISC);
 
+char **palEnvironment = nullptr;
+CRITICAL_SECTION gcsEnvironment;
+
 /*++
 Function:
   GetEnvironmentVariableA
@@ -73,34 +79,34 @@ GetEnvironmentVariableA(
 
     PERF_ENTRY(GetEnvironmentVariableA);
     ENTRY("GetEnvironmentVariableA(lpName=%p (%s), lpBuffer=%p, nSize=%u)\n",
-        lpName?lpName:"NULL",
-        lpName?lpName:"NULL", lpBuffer, nSize);
+        lpName ? lpName : "NULL",
+        lpName ? lpName : "NULL", lpBuffer, nSize);
     
-    if (lpName == NULL)
+    if (lpName == nullptr)
     {
-        ERROR("lpName is NULL\n");
+        ERROR("lpName is null\n");
         SetLastError(ERROR_INVALID_PARAMETER);
         goto done;
     }
 
     if (lpName[0] == 0)
     {
-        TRACE("lpName is empty string\n", lpName);
+        TRACE("lpName is an empty string\n", lpName);
         SetLastError(ERROR_ENVVAR_NOT_FOUND);
         goto done;
     }
-    
-    if (strchr(lpName, '=') != NULL)
+
+    if (strchr(lpName, '=') != nullptr)
     {
         // GetEnvironmentVariable doesn't permit '=' in variable names.
-        value = NULL;
+        value = nullptr;
     }
     else
     {
-        value = MiscGetenv(lpName);
+        value = EnvironGetenv(lpName); ///////// make this not return a copy, or have it fill out the buffer
     }
-    
-    if (value == NULL)
+
+    if (value == nullptr)
     {
         TRACE("%s is not found\n", lpName);
         SetLastError(ERROR_ENVVAR_NOT_FOUND);
@@ -111,11 +117,12 @@ GetEnvironmentVariableA(
     {
         strcpy_s(lpBuffer, nSize, value);
         dwRet = strlen(value);
-    } 
+    }
     else 
     {
         dwRet = strlen(value)+1;
     }
+
     SetLastError(ERROR_SUCCESS);
 
 done:
@@ -138,36 +145,37 @@ GetEnvironmentVariableW(
             OUT LPWSTR lpBuffer,
             IN DWORD nSize)
 {
-    CHAR *inBuff = NULL;
-    CHAR *outBuff = NULL;
+    CHAR *inBuff = nullptr;
+    CHAR *outBuff = nullptr;
     INT inBuffSize;
     DWORD size = 0;
 
     PERF_ENTRY(GetEnvironmentVariableW);
     ENTRY("GetEnvironmentVariableW(lpName=%p (%S), lpBuffer=%p, nSize=%u)\n",
-          lpName?lpName:W16_NULLSTRING,
-          lpName?lpName:W16_NULLSTRING, lpBuffer, nSize);
+          lpName ? lpName : W16_NULLSTRING,
+          lpName ? lpName : W16_NULLSTRING, lpBuffer, nSize);
 
-    inBuffSize = WideCharToMultiByte( CP_ACP, 0, lpName, -1, 
-                                      inBuff, 0, NULL, NULL);
-    if ( 0 == inBuffSize )
+    inBuffSize = WideCharToMultiByte(CP_ACP, 0, lpName, -1,
+                                     inBuff, 0, nullptr, nullptr);
+    if (0 == inBuffSize)
     {
-        ERROR( "lpName has to be a valid parameter\n" );
-        SetLastError( ERROR_INVALID_PARAMETER );
+        ERROR("lpName has to be a valid parameter\n");
+        SetLastError(ERROR_INVALID_PARAMETER);
         goto done;
     }
 
     inBuff = (CHAR *)PAL_malloc(inBuffSize);
-    if (inBuff == NULL)
+    if (inBuff == nullptr)
     {
         ERROR("malloc failed\n");
         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
         goto done;
     }
-    
-    if (nSize) {
+
+    if (nSize)
+    {
         outBuff = (CHAR *)PAL_malloc(nSize*2);
-        if (outBuff == NULL)
+        if (outBuff == nullptr)
         {
             ERROR("malloc failed\n");
             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
@@ -175,34 +183,35 @@ GetEnvironmentVariableW(
         }
     }
 
-    if ( 0 == WideCharToMultiByte( CP_ACP, 0, lpName, -1, inBuff, 
-                                   inBuffSize, NULL, NULL ) )
+    if (0 == WideCharToMultiByte(CP_ACP, 0, lpName, -1, inBuff,
+                                   inBuffSize, NULL, NULL))
     {
-        ASSERT( "WideCharToMultiByte failed!\n" );
-        SetLastError( ERROR_INTERNAL_ERROR );
+        ASSERT("WideCharToMultiByte failed!\n");
+        SetLastError(ERROR_INTERNAL_ERROR);
         goto done;
     }
+
     size = GetEnvironmentVariableA(inBuff, outBuff, nSize);
     if (size > nSize)
     {
         TRACE("Insufficient buffer\n");
     }
-    else if ( size == 0 )
+    else if (size == 0)
     {
         /* error handle in GetEnvironmentVariableA */
     }
     else
     {
         size = MultiByteToWideChar(CP_ACP, 0, outBuff, -1, lpBuffer, nSize);
-        if ( 0 != size )
+        if (0 != size)
         {
             /* Not including the NULL. */
             size--;
         }
         else
         {
-            ASSERT( "MultiByteToWideChar failed!\n" );
-            SetLastError( ERROR_INTERNAL_ERROR );
+            ASSERT("MultiByteToWideChar failed!\n");
+            SetLastError(ERROR_INTERNAL_ERROR);
             size = 0;
             *lpBuffer = '\0';
         }
@@ -214,6 +223,7 @@ done:
 
     LOGEXIT("GetEnvironmentVariableW returns DWORD 0x%x\n", size);
     PERF_EXIT(GetEnvironmentVariableW);
+
     return size;
 }
 
@@ -257,8 +267,8 @@ SetEnvironmentVariableW(
             IN LPCWSTR lpName,
             IN LPCWSTR lpValue)
 {
-    PCHAR name = NULL;
-    PCHAR value = NULL;
+    PCHAR name = nullptr;
+    PCHAR value = nullptr;
     INT nameSize = 0;
     INT valueSize = 0;
     BOOL bRet = FALSE;
@@ -269,7 +279,7 @@ SetEnvironmentVariableW(
         lpName?lpName:W16_NULLSTRING, lpValue?lpValue:W16_NULLSTRING, lpValue?lpValue:W16_NULLSTRING);
 
     if ((nameSize = WideCharToMultiByte(CP_ACP, 0, lpName, -1, name, 0, 
-                                        NULL, NULL)) == 0)
+                                        nullptr, nullptr)) == 0)
     {
         ERROR("WideCharToMultiByte failed\n");
         SetLastError(ERROR_INVALID_PARAMETER);
@@ -277,22 +287,22 @@ SetEnvironmentVariableW(
     }
 
     name = (PCHAR)PAL_malloc(sizeof(CHAR)* nameSize);
-    if (name == NULL)
+    if (name == nullptr)
     {
         ERROR("malloc failed\n");
         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
         goto done;
     }
     
-    if ( 0 == WideCharToMultiByte(CP_ACP, 0, lpName,  -1, 
-                                  name,  nameSize, NULL, NULL ) )
+    if (0 == WideCharToMultiByte(CP_ACP, 0, lpName,  -1, 
+                                 name,  nameSize, nullptr, nullptr))
     {
-        ASSERT( "WideCharToMultiByte returned 0\n" );
-        SetLastError( ERROR_INTERNAL_ERROR );
+        ASSERT("WideCharToMultiByte returned 0\n");
+        SetLastError(ERROR_INTERNAL_ERROR);
         goto done;
     }
 
-    if ( NULL != lpValue )
+    if (lpValue != nullptr)
     {
         if ((valueSize = WideCharToMultiByte(CP_ACP, 0, lpValue, -1, value, 
                                              0, NULL, NULL)) == 0)
@@ -303,29 +313,28 @@ SetEnvironmentVariableW(
         }
 
         value = (PCHAR)PAL_malloc(sizeof(CHAR)*valueSize);
-        
-        if ( NULL == value )
+
+        if (value == nullptr)
         {
             ERROR("malloc failed\n");
             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
             goto done;
         }
-        
-        if ( 0 == WideCharToMultiByte( CP_ACP, 0, lpValue, -1, 
-                                       value, valueSize, NULL, NULL ) )
+
+        if (0 == WideCharToMultiByte(CP_ACP, 0, lpValue, -1,
+                                     value, valueSize, NULL, NULL))
         {
             ASSERT("WideCharToMultiByte failed\n");
             SetLastError( ERROR_INTERNAL_ERROR );
             goto done;
         }
     }
-    
 
     bRet = SetEnvironmentVariableA(name, value);
 done:
     PAL_free(value);
     PAL_free(name);
-    
+
     LOGEXIT("SetEnvironmentVariableW returning BOOL %d\n", bRet);
     PERF_EXIT(SetEnvironmentVariableW);
     return bRet;
@@ -363,13 +372,13 @@ PALAPI
 GetEnvironmentStringsW(
                VOID)
 {
-    WCHAR *wenviron = NULL, *tempEnviron;
+    WCHAR *wenviron = nullptr, *tempEnviron;
     int i, len, envNum;
 
     PERF_ENTRY(GetEnvironmentStringsW);
     ENTRY("GetEnvironmentStringsW()\n");
 
-    PALCEnterCriticalSection(&gcsEnvironment);    
+    PALCEnterCriticalSection(&gcsEnvironment);
 
     envNum = 0;
     len    = 0;
@@ -427,7 +436,7 @@ GetEnvironmentStringsA(
     PERF_ENTRY(GetEnvironmentStringsA);
     ENTRY("GetEnvironmentStringsA()\n");
 
-    PALCEnterCriticalSection(&gcsEnvironment);    
+    PALCEnterCriticalSection(&gcsEnvironment);
 
     envNum = 0;
     len    = 0;
@@ -574,59 +583,60 @@ environment variables of other processes.
 BOOL
 PALAPI
 SetEnvironmentVariableA(
-                       IN LPCSTR lpName,
-                       IN LPCSTR lpValue)
+            IN LPCSTR lpName,
+            IN LPCSTR lpValue)
 {
 
     BOOL bRet = FALSE;
     int nResult =0;
     PERF_ENTRY(SetEnvironmentVariableA);
     ENTRY("SetEnvironmentVariableA(lpName=%p (%s), lpValue=%p (%s))\n",
-        lpName?lpName:"NULL",
-        lpName?lpName:"NULL", lpValue?lpValue:"NULL", lpValue?lpValue:"NULL");
+        lpName ? lpName : "NULL", lpName ? lpName : "NULL",
+        lpValue ? lpValue : "NULL", lpValue ? lpValue : "NULL");
 
-    /*check if the input variable name is null
-     * and if so exit*/
-    if ((lpName == NULL) || (lpName[0] == 0))
+    // exit if the input variable name is null
+    if ((lpName == nullptr) || (lpName[0] == 0))
     {
         ERROR("lpName is NULL\n");
         goto done;
     }
-    /*check if the input value is null and if so
+
+    /* check if the input value is null and if so
      * check if the input name is valid and delete
-     * the variable name from process environment*/
-    if (lpValue == NULL)
+     * the variable name from process environment */
+    if (lpValue == nullptr)
     {
-        if ((lpValue = MiscGetenv(lpName)) == NULL)
+        if ((lpValue = EnvironGetenv(lpName)) == nullptr)
         {
             ERROR("Couldn't find environment variable (%s)\n", lpName);
             SetLastError(ERROR_ENVVAR_NOT_FOUND);
             goto done;
         }
-        MiscUnsetenv(lpName);
+
+        EnvironUnsetenv(lpName);
     }
-    /*All the conditions are met. Set the variable*/
     else
     {
+        // All the conditions are met. Set the variable.
         int iLen = strlen(lpName) + strlen(lpValue) + 2;
         LPSTR string = (LPSTR) PAL_malloc(iLen);
-        if (string == NULL)
+        if (string == nullptr)
         {
             bRet = FALSE;
             ERROR("Unable to allocate memory\n");
             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
             goto done;
         }
-        
+
         sprintf_s(string, iLen, "%s=%s", lpName, lpValue);
-        nResult = MiscPutenv(string, FALSE) ? 0 : -1;
+        nResult = EnvironPutenv(string, FALSE) ? 0 : -1;
 
         PAL_free(string);
         string = NULL;
-        
-        // If MiscPutenv returns FALSE, it almost certainly failed to
-        // allocate memory.        
-        if(nResult == -1)
+
+        // If EnvironPutenv returns FALSE, it almost certainly failed to
+        // allocate memory.          ////////////////////////////still true?
+        if (nResult == -1)
         {
             bRet = FALSE;
             ERROR("Unable to allocate memory\n");
@@ -634,11 +644,357 @@ SetEnvironmentVariableA(
             goto done;
         }
     }
+
     bRet = TRUE;
+
 done:
-    LOGEXIT("SetEnvironmentVariableA returning BOOL %d\n", bRet);    
+    LOGEXIT("SetEnvironmentVariableA returning BOOL %d\n", bRet);
     PERF_EXIT(SetEnvironmentVariableA);
     return bRet;
 }
 
 
+/*++
+Function:
+  MiscGetEnvArray
+
+Get a reference to the process's environ array into palEnvironment
+
+NOTE: This function MUST be called while holding the gcsEnvironment 
+      critical section (except if the caller is the initialization 
+      routine)
+--*/
+void
+MiscGetEnvArray(void)
+{
+#if HAVE__NSGETENVIRON
+    palEnvironment = *(_NSGetEnviron());
+#else   // HAVE__NSGETENVIRON
+    extern char **environ;
+    palEnvironment = environ;
+#endif  // HAVE__NSGETENVIRON
+}
+
+/*++
+Function:
+  MiscSetEnvArray
+
+Make sure the process's environ array is in sync with palEnvironment variable
+
+NOTE: This function MUST be called while holding the gcsEnvironment 
+      critical section (except if the caller is the initialization 
+      routine)
+--*/
+void
+MiscSetEnvArray(void)
+{
+#if HAVE__NSGETENVIRON
+    *(_NSGetEnviron()) = palEnvironment;
+#else   // HAVE__NSGETENVIRON
+    extern char **environ;
+    environ = palEnvironment;
+#endif  // HAVE__NSGETENVIRON
+}
+
+
+/*++
+Function:
+  EnvironInitialize
+
+Initialization function called from PAL_Initialize.
+
+Note: This is called before debug channels are initialized, so it
+      cannot use debug tracing calls.
+--*/
+BOOL
+EnvironInitialize(void)
+{
+    InternalInitializeCriticalSection(&gcsEnvironment);
+    MiscGetEnvArray();
+
+    return TRUE;
+}
+
+/*++
+
+Function : _putenv.
+    
+See MSDN for more details.
+
+Note:   The BSD implementation can cause
+        memory leaks. See man pages for more details.
+--*/
+int
+__cdecl 
+_putenv( const char * envstring )
+{
+    int ret = -1;
+
+    PERF_ENTRY(_putenv);
+    ENTRY( "_putenv( %p (%s) )\n", envstring ? envstring : "NULL", envstring ? envstring : "NULL") ;
+    
+    if (!envstring)
+    {
+        ERROR( "_putenv() called with NULL envstring!\n");
+        goto EXIT;
+    }
+
+    ret = EnvironPutenv(envstring, TRUE) ? 0 : -1;
+
+EXIT:
+    LOGEXIT( "_putenv returning %d\n", ret);
+    PERF_EXIT(_putenv);
+    return ret;
+}
+
+/*++
+
+Function : PAL_getenv
+    
+See MSDN for more details.
+--*/
+char * __cdecl PAL_getenv(const char *varname)
+{
+    char *retval;
+
+    PERF_ENTRY(getenv);
+    ENTRY("getenv (%p (%s))\n", varname ? varname : "NULL", varname ? varname : "NULL");
+
+    if (strcmp(varname, "") == 0)
+    {
+        ERROR("getenv called with a empty variable name\n");
+        LOGEXIT("getenv returning NULL\n");
+        PERF_EXIT(getenv);
+        return(NULL);
+    }
+    retval = EnvironGetenv(varname);
+
+    LOGEXIT("getenv returning %p\n", retval);
+    PERF_EXIT(getenv);
+    return(retval);
+}
+
+
+/*++
+Function:
+  EnvironGetenv
+
+Gets an environment variable's value from environ. The returned buffer
+must not be modified or freed.
+--*/
+char *EnvironGetenv(const char *name)
+{
+    int i, length;
+    char *equals;
+    char *pRet = NULL;
+    CPalThread * pthrCurrent = InternalGetCurrentThread();
+
+    InternalEnterCriticalSection(pthrCurrent, &gcsEnvironment);
+
+    length = strlen(name);
+    for(i = 0; palEnvironment[i] != NULL; i++)
+    {
+        if (memcmp(palEnvironment[i], name, length) == 0)
+        {
+            equals = palEnvironment[i] + length;
+            if (*equals == '\0')
+            {
+                pRet = (char *) "";
+                goto done;
+            } 
+            else if (*equals == '=') 
+            {
+                pRet = equals + 1;
+                goto done;
+            }
+        }
+    }
+
+done:
+    InternalLeaveCriticalSection(pthrCurrent, &gcsEnvironment);
+    return pRet;
+}
+
+/*++
+Function:
+  EnvironPutenv
+
+Sets an environment variable's value by directly modifying palEnvironment.
+Returns TRUE if the variable was set, or FALSE if PAL_malloc or realloc
+failed or if the given string is malformed.
+--*/
+BOOL EnvironPutenv(const char *string, BOOL deleteIfEmpty)
+{
+    const char *equals, *existingEquals;
+    char *copy = NULL;
+    int length;
+    int i, j;
+    bool fOwningCS = false;
+    BOOL result = FALSE;
+    CPalThread * pthrCurrent = InternalGetCurrentThread();
+    
+    equals = strchr(string, '=');
+    if (equals == string || equals == NULL)
+    {
+        // "=foo" and "foo" have no meaning
+        goto done;
+    }
+    if (equals[1] == '\0' && deleteIfEmpty)
+    {
+        // "foo=" removes foo from the environment in _putenv() on Windows.
+        // The same string can result from a call to SetEnvironmentVariable()
+        // with the empty string as the value, but in that case we want to
+        // set the variable's value to "". deleteIfEmpty will be FALSE in
+        // that case.
+        length = strlen(string);
+        copy = (char *) InternalMalloc(length);
+        if (copy == NULL)
+        {
+            goto done;
+        }
+        memcpy(copy, string, length - 1);
+        copy[length - 1] = '\0';    // Change '=' to '\0'
+        EnvironUnsetenv(copy);
+        result = TRUE;
+    }
+    else
+    {
+        // See if we are replacing an item or adding one.
+        
+        // Make our copy up front, since we'll use it either way.
+        copy = strdup(string);
+        if (copy == NULL)
+        {
+            goto done;
+        }
+        
+        length = equals - string;
+
+        InternalEnterCriticalSection(pthrCurrent, &gcsEnvironment);
+        fOwningCS = true;
+        
+        for(i = 0; palEnvironment[i] != NULL; i++)
+        {
+            existingEquals = strchr(palEnvironment[i], '=');
+            if (existingEquals == NULL)
+            {
+                // The PAL screens out malformed strings, but
+                // environ comes from the system, so it might
+                // have strings without '='. We treat the entire
+                // string as a name in that case.
+                existingEquals = palEnvironment[i] + strlen(palEnvironment[i]);
+            }
+            if (existingEquals - palEnvironment[i] == length)
+            {
+                if (memcmp(string, palEnvironment[i], length) == 0)
+                {
+                    // Replace this one. Don't free the original,
+                    // though, because there may be outstanding
+                    // references to it that were acquired via
+                    // getenv. This is an unavoidable memory leak.
+                    palEnvironment[i] = copy;
+                    
+                    // Set 'copy' to NULL so it won't be freed
+                    copy = NULL;
+                    
+                    result = TRUE;
+                    break;
+                }
+            }
+        }
+        if (palEnvironment[i] == NULL)
+        {            
+            static BOOL sAllocatedEnviron = FALSE;
+            // Add a new environment variable.
+            // We'd like to realloc palEnvironment, but we can't do that the
+            // first time through.
+            char **newEnviron = NULL;
+            
+            if (sAllocatedEnviron) {
+                if (NULL == (newEnviron = 
+                        (char **)InternalRealloc(palEnvironment, (i + 2) * sizeof(char *))))
+                {
+                    goto done;
+                }
+            }
+            else
+            {
+                // Allocate palEnvironment ourselves so we can realloc it later.
+                newEnviron = (char **)InternalMalloc((i + 2) * sizeof(char *));
+                if (newEnviron == NULL)
+                {
+                    goto done;
+                }
+                for(j = 0; palEnvironment[j] != NULL; j++)
+                {
+                    newEnviron[j] = palEnvironment[j];
+                }
+                sAllocatedEnviron = TRUE;
+            }
+            palEnvironment = newEnviron;
+            MiscSetEnvArray();
+            palEnvironment[i] = copy;
+            palEnvironment[i + 1] = NULL;
+
+            // Set 'copy' to NULL so it won't be freed
+            copy = NULL;
+            
+            result = TRUE;
+        }
+    }
+done:
+
+    if (fOwningCS)
+    {
+        InternalLeaveCriticalSection(pthrCurrent, &gcsEnvironment);
+    }
+    if (NULL != copy)
+    {
+        InternalFree(copy);
+    }
+    return result;
+}
+
+/*++
+Function:
+  EnvironUnsetenv
+
+Removes a variable from the environment. Does nothing if the variable
+does not exist in the environment.
+--*/
+void EnvironUnsetenv(const char *name)
+{
+    const char *equals;
+    int length;
+    int i, j;
+    CPalThread * pthrCurrent = InternalGetCurrentThread();
+    
+    length = strlen(name);
+
+    InternalEnterCriticalSection(pthrCurrent, &gcsEnvironment);
+    for(i = 0; palEnvironment[i] != NULL; i++)
+    {
+        equals = strchr(palEnvironment[i], '=');
+        if (equals == NULL)
+        {
+            equals = palEnvironment[i] + strlen(palEnvironment[i]);
+        }
+        if (equals - palEnvironment[i] == length)
+        {
+            if (memcmp(name, palEnvironment[i], length) == 0)
+            {
+                // Remove this one. Don't free it, though, since
+                // there might be oustanding references to it that
+                // were acquired via getenv. This is an
+                // unavoidable memory leak.
+                for(j = i + 1; palEnvironment[j] != NULL; j++) { }
+                // i is now the one we want to remove. j is the
+                // last index in palEnvironment, which is NULL.
+
+                // Shift palEnvironment down by the difference between i and j.
+                memmove(palEnvironment + i, palEnvironment + i + 1, (j - i) * sizeof(char *));
+            }
+        }
+    }
+    InternalLeaveCriticalSection(pthrCurrent, &gcsEnvironment);
+}
index 4d40781..84d1b11 100644 (file)
@@ -30,7 +30,7 @@ Abstract:
 #include "pal/critsect.h"
 #include "pal/dbgmsg.h"
 #include "pal/utils.h"
-#include "pal/misc.h"
+#include "pal/environ.h"
 #include "pal/virtual.h"
 #include "pal/stackstring.hpp"
 
@@ -4358,7 +4358,7 @@ getPath(
 
     pThread = InternalGetCurrentThread();
     /* Then try to look in the path */
-    int iLen2 = strlen(MiscGetenv("PATH"))+1;
+    int iLen2 = strlen(EnvironGetenv("PATH"))+1;
     lpPath = (LPSTR) InternalMalloc(iLen2);
 
     if (!lpPath)
@@ -4367,7 +4367,7 @@ getPath(
         return FALSE;
     }
 
-    if (strcpy_s(lpPath, iLen2, MiscGetenv("PATH")) != SAFECRT_SUCCESS)
+    if (strcpy_s(lpPath, iLen2, EnvironGetenv("PATH")) != SAFECRT_SUCCESS)
     {
         ERROR("strcpy_s failed!");
         return FALSE;
index 07f6c8b..3ba97ad 100644 (file)
@@ -30,7 +30,7 @@ Abstract:
 #include "pal/process.h"
 #include "pal/module.h"
 #include "pal/dbgmsg.h"
-#include "pal/misc.h"
+#include "pal/environ.h"
 #include "pal/init.h"
 
 #include <signal.h>
@@ -1680,7 +1680,7 @@ CorUnix::InitializeGlobalThreadData(
     // Read in the environment to see whether we need to change the default
     // thread stack size.
     //
-    pszStackSize = MiscGetenv(PAL_THREAD_DEFAULT_STACK_SIZE);
+    pszStackSize = EnvironGetenv(PAL_THREAD_DEFAULT_STACK_SIZE);
     if (NULL != pszStackSize)
     {
         // Environment variable exists