blob: f77579553b41ac0387c5856245d9ed49b32e2011 [file] [log] [blame]
Avi Drissmane4622aa2022-09-08 20:36:061// Copyright 2019 The Chromium Authors
David Benjamin76ee79eb2019-03-15 17:02:092// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "base/process/environment_internal.h"
6
7#include <stddef.h>
8
Lei Zhangfb2722b2023-10-31 22:41:539#include <vector>
10
Tom Sepez288f20732025-02-19 00:10:0411#include "base/compiler_specific.h"
Xiaohan Wang37e81612022-01-15 18:27:0012#include "build/build_config.h"
13
14#if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
Hidehiko Abeb63733e2020-04-17 18:35:3915#include <string.h>
16#endif
17
Lei Zhangfb2722b2023-10-31 22:41:5318#if BUILDFLAG(IS_WIN)
19#include "base/check_op.h"
20#endif
David Benjamin76ee79eb2019-03-15 17:02:0921
Peter Kasting811504a72025-01-09 03:18:5022namespace base::internal {
David Benjamin76ee79eb2019-03-15 17:02:0923
24namespace {
25
Xiaohan Wang37e81612022-01-15 18:27:0026#if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA) || BUILDFLAG(IS_WIN)
David Benjamin76ee79eb2019-03-15 17:02:0927// Parses a null-terminated input string of an environment block. The key is
28// placed into the given string, and the total length of the line, including
29// the terminating null, is returned.
30size_t ParseEnvLine(const NativeEnvironmentString::value_type* input,
31 NativeEnvironmentString* key) {
32 // Skip to the equals or end of the string, this is the key.
33 size_t cur = 0;
Tom Sepez288f20732025-02-19 00:10:0434 while (UNSAFE_TODO(input[cur] && input[cur] != '=')) {
David Benjamin76ee79eb2019-03-15 17:02:0935 cur++;
Peter Kasting134ef9af2024-12-28 02:30:0936 }
David Benjamin76ee79eb2019-03-15 17:02:0937 *key = NativeEnvironmentString(&input[0], cur);
38
39 // Now just skip to the end of the string.
Tom Sepez288f20732025-02-19 00:10:0440 while (UNSAFE_TODO(input[cur])) {
David Benjamin76ee79eb2019-03-15 17:02:0941 cur++;
Peter Kasting134ef9af2024-12-28 02:30:0942 }
David Benjamin76ee79eb2019-03-15 17:02:0943 return cur + 1;
44}
45#endif
46
47} // namespace
48
Xiaohan Wang37e81612022-01-15 18:27:0049#if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
David Benjamin76ee79eb2019-03-15 17:02:0950
Maria Kazinova112e7882024-06-10 16:04:3651base::HeapArray<char*> AlterEnvironment(const char* const* const env,
52 const EnvironmentMap& changes) {
David Benjamin76ee79eb2019-03-15 17:02:0953 std::string value_storage; // Holds concatenated null-terminated strings.
54 std::vector<size_t> result_indices; // Line indices into value_storage.
55
56 // First build up all of the unchanged environment strings. These are
57 // null-terminated of the form "key=value".
58 std::string key;
Tom Sepez288f20732025-02-19 00:10:0459 for (size_t i = 0; UNSAFE_TODO(env[i]); i++) {
60 size_t line_length = ParseEnvLine(UNSAFE_TODO(env[i]), &key);
David Benjamin76ee79eb2019-03-15 17:02:0961
62 // Keep only values not specified in the change vector.
63 auto found_change = changes.find(key);
64 if (found_change == changes.end()) {
65 result_indices.push_back(value_storage.size());
Tom Sepez288f20732025-02-19 00:10:0466 value_storage.append(UNSAFE_TODO(env[i]), line_length);
David Benjamin76ee79eb2019-03-15 17:02:0967 }
68 }
69
70 // Now append all modified and new values.
71 for (const auto& i : changes) {
72 if (!i.second.empty()) {
73 result_indices.push_back(value_storage.size());
74 value_storage.append(i.first);
75 value_storage.push_back('=');
76 value_storage.append(i.second);
77 value_storage.push_back(0);
78 }
79 }
80
81 size_t pointer_count_required =
82 result_indices.size() + 1 + // Null-terminated array of pointers.
83 (value_storage.size() + sizeof(char*) - 1) / sizeof(char*); // Buffer.
Maria Kazinova112e7882024-06-10 16:04:3684 auto result = base::HeapArray<char*>::WithSize(pointer_count_required);
David Benjamin76ee79eb2019-03-15 17:02:0985
Maria Kazinova112e7882024-06-10 16:04:3686 if (!value_storage.empty()) {
87 // The string storage goes after the array of pointers.
88 char* storage_data =
89 reinterpret_cast<char*>(&result[result_indices.size() + 1]);
Tom Sepezdbfc4952025-03-17 18:52:0490 UNSAFE_TODO(
91 memcpy(storage_data, value_storage.data(), value_storage.size()));
David Benjamin76ee79eb2019-03-15 17:02:0992
Maria Kazinova112e7882024-06-10 16:04:3693 // Fill array of pointers at the beginning of the result.
94 for (size_t i = 0; i < result_indices.size(); i++) {
Tom Sepez288f20732025-02-19 00:10:0495 result[i] = UNSAFE_TODO(&storage_data[result_indices[i]]);
Maria Kazinova112e7882024-06-10 16:04:3696 }
97 }
David Benjamin76ee79eb2019-03-15 17:02:0998 result[result_indices.size()] = 0; // Null terminator.
99
100 return result;
101}
102
Xiaohan Wang37e81612022-01-15 18:27:00103#elif BUILDFLAG(IS_WIN)
David Benjamin76ee79eb2019-03-15 17:02:09104
Jan Wilken Dörrie6bdce492019-11-05 11:36:50105NativeEnvironmentString AlterEnvironment(const wchar_t* env,
David Benjamin76ee79eb2019-03-15 17:02:09106 const EnvironmentMap& changes) {
107 NativeEnvironmentString result;
108
109 // First build up all of the unchanged environment strings.
Jan Wilken Dörrie6bdce492019-11-05 11:36:50110 const wchar_t* ptr = env;
David Benjamin76ee79eb2019-03-15 17:02:09111 while (*ptr) {
Jan Wilken Dörrie6bdce492019-11-05 11:36:50112 std::wstring key;
David Benjamin76ee79eb2019-03-15 17:02:09113 size_t line_length = ParseEnvLine(ptr, &key);
114
115 // Keep only values not specified in the change vector.
116 if (changes.find(key) == changes.end()) {
117 result.append(ptr, line_length);
118 }
Tom Sepez288f20732025-02-19 00:10:04119 UNSAFE_TODO(ptr += line_length);
David Benjamin76ee79eb2019-03-15 17:02:09120 }
121
122 // Now append all modified and new values.
123 for (const auto& i : changes) {
124 // Windows environment blocks cannot handle keys or values with NULs.
Jan Wilken Dörrie6bdce492019-11-05 11:36:50125 CHECK_EQ(std::wstring::npos, i.first.find(L'\0'));
126 CHECK_EQ(std::wstring::npos, i.second.find(L'\0'));
David Benjamin76ee79eb2019-03-15 17:02:09127 if (!i.second.empty()) {
128 result += i.first;
129 result.push_back('=');
130 result += i.second;
131 result.push_back('\0');
132 }
133 }
134
135 // Add the terminating NUL.
136 result.push_back('\0');
137 return result;
138}
139
Xiaohan Wang37e81612022-01-15 18:27:00140#endif // BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
David Benjamin76ee79eb2019-03-15 17:02:09141
Peter Kasting811504a72025-01-09 03:18:50142} // namespace base::internal