Repository: dotnet/roslyn
File: src/Compilers/Shared/BuildServerConnection.cs (C#)

Code before:

            // Convert to Unicode and allocate unmanaged memory
            return Marshal.StringToHGlobalUni(envBlock.ToString());
        }

        /// <summary>
        /// Gets the environment variables that should be passed to the server process.
        /// </summary>
        /// <param name="currentEnvironment">Current environment variables to use as a base</param>
        /// <param name="logger">Optional logger for logging environment variable setup</param>
        /// <returns>Dictionary of environment variables to set, or null if no custom environment is needed</returns>
        internal static Dictionary<string, string>? GetServerEnvironmentVariables(System.Collections.IDictionary currentEnvironment, ICompilerServerLogger? logger = null)
        {
            if (RuntimeHostInfo.GetToolDotNetRoot() is not { } dotNetRoot)
            {
                return null;
            }

            // Start with current environment
            var environmentVariables = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
            foreach (System.Collections.DictionaryEntry entry in currentEnvironment)
            {
                var key = (string)entry.Key;
                var value = (string?)entry.Value;

                // Skip DOTNET_ROOT* variables as we want to set our own
                if (!key.StartsWith(RuntimeHostInfo.DotNetRootEnvironmentName, StringComparison.OrdinalIgnoreCase))
                {
                    environmentVariables[key] = value ?? string.Empty;
                }
            }

            // Set our DOTNET_ROOT
            environmentVariables[RuntimeHostInfo.DotNetRootEnvironmentName] = dotNetRoot;

            logger?.Log("Setting {0} to '{1}'", RuntimeHostInfo.DotNetRootEnvironmentName, dotNetRoot);

            return environmentVariables;
        }

        /// <summary>
        /// This will attempt to start a compiler server process using the executable inside the 
        /// directory <paramref name="clientDirectory"/>. This returns "true" if starting the 
        /// compiler server process was successful, it does not state whether the server successfully
        /// started or not (it could crash on startup).
        /// </summary>
        internal static bool TryCreateServer(string clientDirectory, string pipeName, ICompilerServerLogger logger, out int processId)
        {
            processId = 0;
            var serverInfo = GetServerProcessInfo(clientDirectory, pipeName);


Review comment (suggestion):
```suggestion
                // Skip DOTNET_ROOT* variables such as DOTNET_ROOT_X64 as we want to set our own
```

Code after:
            envBlock.Append('\0');

            // Convert to Unicode and allocate unmanaged memory
            return Marshal.StringToHGlobalUni(envBlock.ToString());
        }

        /// <summary>
        /// Gets the environment variables that should be passed to the server process.
        /// </summary>
        /// <param name="currentEnvironment">Current environment variables to use as a base</param>
        /// <param name="logger">Optional logger for logging environment variable setup</param>
        /// <returns>Dictionary of environment variables to set, or null if no custom environment is needed</returns>
        internal static Dictionary<string, string>? GetServerEnvironmentVariables(System.Collections.IDictionary currentEnvironment, ICompilerServerLogger? logger = null)
        {
            if (RuntimeHostInfo.GetToolDotNetRoot() is not { } dotNetRoot)
            {
                return null;
            }

            // Start with current environment
            var environmentVariables = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
            foreach (System.Collections.DictionaryEntry entry in currentEnvironment)
            {
                var key = (string)entry.Key;
                var value = (string?)entry.Value;

                // Clear DOTNET_ROOT* variables such as DOTNET_ROOT_X64 by setting them to empty,
                // as we want to set our own DOTNET_ROOT and avoid conflicts
                if (key.StartsWith(RuntimeHostInfo.DotNetRootEnvironmentName, StringComparison.OrdinalIgnoreCase))
                {
                    environmentVariables[key] = string.Empty;
                }
                else
                {
                    environmentVariables[key] = value ?? string.Empty;
                }
            }

            // Set our DOTNET_ROOT
            environmentVariables[RuntimeHostInfo.DotNetRootEnvironmentName] = dotNetRoot;

            logger?.Log("Setting {0} to '{1}'", RuntimeHostInfo.DotNetRootEnvironmentName, dotNetRoot);

            return environmentVariables;
        }

        /// <summary>
        /// This will attempt to start a compiler server process using the executable inside the 
        /// directory <paramref name="clientDirectory"/>. This returns "true" if starting the 
        /// compiler server process was successful, it does not state whether the server successfully
        /// started or not (it could crash on startup).