1 // 2 // cenvarg.cpp 3 // 4 // Copyright (c) Microsoft Corporation. All rights reserved. 5 // 6 // Defines the _cenvarg() and _capture_argv functions, which transform argument 7 // vectors and environments for use by the _exec() and _spawn() functions. 8 // 9 #include <corecrt_internal.h> 10 #include <errno.h> 11 #include <corecrt_internal_traits.h> 12 #include <stdarg.h> 13 #include <stdio.h> 14 #include <stdlib.h> 15 #include <string.h> 16 17 #pragma warning(disable:__WARNING_POSTCONDITION_NULLTERMINATION_VIOLATION) // 26036 18 19 20 // Converts a main()-style argv arguments vector into a command line. On success, 21 // returns a pointer to the newly constructed arguments block; the caller is 22 // responsible for freeing the string. On failure, returns null and sets errno. 23 template <typename Character> 24 static errno_t __cdecl construct_command_line( 25 Character const* const* const argv, 26 Character** const command_line_result 27 ) throw() 28 { 29 typedef __crt_char_traits<Character> traits; 30 31 *command_line_result = nullptr; 32 33 // Compute the number of bytes required to store the arguments in argv in a 34 // command line string (including spaces between arguments and a terminator): 35 size_t const command_line_count = [&] 36 { 37 size_t n = 0; 38 for (Character const* const* it = argv; *it; n += traits::tcslen(*it++) + 1) { } 39 40 // If there were no arguments, return 1 so that we can return an empty 41 // string: 42 return __max(n, 1); 43 }(); 44 45 __crt_unique_heap_ptr<Character> command_line(_calloc_crt_t(Character, command_line_count)); 46 if (!command_line) 47 { 48 __acrt_errno_map_os_error(ERROR_NOT_ENOUGH_MEMORY); 49 return errno = ENOMEM; 50 } 51 52 Character const* const* source_it = argv; 53 Character* result_it = command_line.get(); 54 55 // If there are no arguments, just return the empty string: 56 if (*source_it == nullptr) 57 { 58 *command_line_result = command_line.detach(); 59 return 0; 60 } 61 62 // Copy the arguments, separated by spaces: 63 while (*source_it != nullptr) 64 { 65 _ERRCHECK(traits::tcscpy_s(result_it, command_line_count - (result_it - command_line.get()), *source_it)); 66 result_it += traits::tcslen(*source_it); 67 *result_it++ = ' '; 68 ++source_it; 69 } 70 71 // Replace the last space with a terminator: 72 result_it[-1] = '\0'; 73 74 *command_line_result = command_line.detach(); 75 return 0; 76 } 77 78 79 80 // Converts a main()-style envp environment vector into an environment block in 81 // the form required by the CreateProcess API. On success, returns a pointer to 82 // the newly constructed environment block; the caller is responsible for freeing 83 // the block. On failure, returns null and sets errno. 84 template <typename Character> 85 static errno_t __cdecl construct_environment_block( 86 _In_opt_z_ Character const* const* const envp, 87 _Outptr_result_maybenull_ Character** const environment_block_result 88 ) throw() 89 { 90 typedef __crt_char_traits<Character> traits; 91 92 *environment_block_result = nullptr; 93 94 // If envp is null, we will use the current environment of this process as 95 // the environment for the new process. No action is required in this case 96 // because simply passing a null environment pointer to CreateProcess will 97 // do the right thing. 98 if (envp == nullptr) 99 return 0; 100 101 // Get the value of the SystemRoot environment variable, if it is defined, 102 // and compute the number of characters required to store it in the 103 // envrionment block: 104 Character const system_root_name[] = { 'S', 'y', 's', 't', 'e', 'm', 'R', 'o', 'o', 't', '\0' }; 105 106 __crt_unique_heap_ptr<Character> system_root_value; 107 if (_ERRCHECK_EINVAL(traits::tdupenv_s_crt(system_root_value.get_address_of(), nullptr, system_root_name)) != 0) 108 return errno; 109 110 size_t const system_root_value_count = system_root_value 111 ? traits::tcslen(system_root_value.get()) + 1 112 : 0; 113 114 size_t const system_root_count = _countof(system_root_name) + system_root_value_count; 115 116 // Compute the number of characters required to hold the environment 117 // strings provided by the user: 118 size_t const envp_count = [&] 119 { 120 size_t n = 2; // Account for double null terminator 121 for (auto it = envp; *it != nullptr; n += traits::tcslen(*it++) + 1) { } 122 return n; 123 }(); 124 125 // Get the current environment from the OS so that we can get the current 126 // directory strings (those starting with '=') and append them to the user- 127 // provided environment. 128 __crt_unique_heap_ptr<Character> const os_environment(traits::get_environment_from_os()); 129 if (!os_environment) 130 return EINVAL; 131 132 // Find the first shell environment variable: 133 Character* const first_cwd = [&] 134 { 135 Character* it = os_environment.get(); 136 while (*it != '=') 137 it += traits::tcslen(it) + 1; 138 return it; 139 }(); 140 141 // Find the end of the shell environment variables (assume they are contiguous): 142 Character* const last_cwd = [&] 143 { 144 Character* it = first_cwd; 145 while (it[0] == '=' && it[1] != '\0' && it[2] == ':' && it[3] == '=') 146 it += 4 + traits::tcslen(it + 4) + 1; 147 return it; 148 }(); 149 150 size_t const cwd_count = last_cwd - first_cwd; 151 152 153 // Check to see if the SystemRoot is already defined in the environment: 154 bool const system_root_defined_in_environment = [&] 155 { 156 for (auto it = envp; *it != nullptr; ++it) 157 { 158 if (traits::tcsnicmp(*it, system_root_name, traits::tcslen(system_root_name)) == 0) 159 return true; 160 } 161 162 return false; 163 }(); 164 165 // Allocate storage for the new environment: 166 size_t const environment_block_count = system_root_defined_in_environment 167 ? envp_count + cwd_count 168 : envp_count + cwd_count + system_root_count; 169 170 __crt_unique_heap_ptr<Character> environment_block(_calloc_crt_t(Character, environment_block_count)); 171 if (!environment_block) 172 { 173 __acrt_errno_map_os_error(ERROR_OUTOFMEMORY); 174 return errno = ENOMEM; 175 } 176 177 // Build the environment block by concatenating the environment strings with 178 // null characters between them, and with a double null terminator. 179 Character* result_it = environment_block.get(); 180 size_t remaining_characters = environment_block_count; 181 182 // Copy the cwd strings into the new environment: 183 if (cwd_count != 0) 184 { 185 memcpy(result_it, first_cwd, cwd_count * sizeof(Character)); 186 result_it += cwd_count; 187 remaining_characters -= cwd_count; 188 } 189 190 // Copy the environment strings from envp into the new environment: 191 for (auto it = envp; *it != nullptr; ++it) 192 { 193 _ERRCHECK(traits::tcscpy_s(result_it, remaining_characters, *it)); 194 195 size_t const count_copied = traits::tcslen(*it) + 1; 196 result_it += count_copied; 197 remaining_characters -= count_copied; 198 } 199 200 // Copy the SystemRoot into the new environment: 201 if (!system_root_defined_in_environment) 202 { 203 static Character const equal_sign[] = { '=', '\0' }; 204 205 _ERRCHECK(traits::tcscpy_s(result_it, system_root_count, system_root_name)); 206 _ERRCHECK(traits::tcscat_s(result_it, system_root_count, equal_sign)); 207 if (system_root_value) 208 { 209 _ERRCHECK(traits::tcscat_s(result_it, system_root_count, system_root_value.get())); 210 } 211 result_it += system_root_count; 212 } 213 214 // Null-terminate the environment block and return it. If the environment 215 // block is empty, it requires two null terminators: 216 if (result_it == environment_block.get()) 217 *result_it++ = '\0'; 218 219 *result_it = '\0'; 220 221 *environment_block_result = environment_block.detach(); 222 return 0; 223 } 224 225 226 227 // Converts a main()-style argv arguments vector and envp environment vector into 228 // a command line and an environment block, for use in the _exec and _spawn 229 // functions. On success, returns 0 and sets the two result argumetns to point 230 // to the newly created command line and environment block. The caller is 231 // responsible for freeing these blocks. On failure, returns -1 and sets errno. 232 template <typename Character> 233 _Success_(return == 0) 234 _Ret_range_(-1, 0) 235 static int __cdecl common_pack_argv_and_envp( 236 _In_z_ Character const* const* const argv, 237 _In_opt_z_ Character const* const* const envp, 238 _Outptr_result_maybenull_ Character** const command_line_result, 239 _Outptr_result_maybenull_ Character** const environment_block_result 240 ) throw() 241 { 242 typedef __crt_char_traits<Character> traits; 243 244 __crt_unique_heap_ptr<Character> command_line; 245 if (construct_command_line(argv, command_line.get_address_of()) != 0) 246 return -1; 247 248 __crt_unique_heap_ptr<Character> environment_block; 249 if (construct_environment_block(envp, environment_block.get_address_of()) != 0) 250 return -1; 251 252 *command_line_result = command_line.detach(); 253 *environment_block_result = environment_block.detach(); 254 return 0; 255 } 256 257 extern "C" int __cdecl __acrt_pack_narrow_command_line_and_environment( 258 char const* const* const argv, 259 char const* const* const envp, 260 char** const command_line_result, 261 char** const environment_block_result 262 ) 263 { 264 return common_pack_argv_and_envp(argv, envp, command_line_result, environment_block_result); 265 } 266 267 extern "C" int __cdecl __acrt_pack_wide_command_line_and_environment( 268 wchar_t const* const* const argv, 269 wchar_t const* const* const envp, 270 wchar_t** const command_line_result, 271 wchar_t** const environment_block_result 272 ) 273 { 274 return common_pack_argv_and_envp(argv, envp, command_line_result, environment_block_result); 275 } 276 277 278 279 // Creates an argv array for the _exec and _spawn functions. This function walks 280 // the provided varargs list, copying the char* or wchar_t* pointers into an 281 // array. The caller_array is used first; if it is too small to fit all of the 282 // arguments, an array is dynamically allocated. A pointer to the argv array is 283 // returned to the caller. If the returned pointer is not 'caller_array', the 284 // caller must free the array. On failure, nullptr is returned and errno is set. 285 template <typename Character> 286 _Success_(return != 0) 287 static Character** __cdecl common_capture_argv( 288 _In_ va_list* const arglist, 289 _In_z_ Character const* const first_argument, 290 _When_(return == caller_array, _Post_z_) 291 _Out_writes_(caller_array_count) Character** const caller_array, 292 _In_ size_t const caller_array_count 293 ) throw() 294 { 295 Character** argv = caller_array; 296 size_t argv_count = caller_array_count; 297 298 __crt_unique_heap_ptr<Character*> local_array; 299 300 size_t i = 0; 301 Character* next_argument = const_cast<Character*>(first_argument); 302 for (;;) 303 { 304 if (i >= argv_count) 305 { 306 _VALIDATE_RETURN_NOEXC(SIZE_MAX / 2 > argv_count, ENOMEM, nullptr); 307 308 // If we have run out of room in the caller-provided array, allocate 309 // an array on the heap and copy the contents of the caller-provided 310 // array: 311 if (argv == caller_array) 312 { 313 local_array = _calloc_crt_t(Character*, argv_count * 2); 314 _VALIDATE_RETURN_NOEXC(local_array.get() != nullptr, ENOMEM, nullptr); 315 316 _ERRCHECK(memcpy_s(local_array.get(), argv_count * 2, caller_array, caller_array_count)); 317 318 argv = local_array.get(); 319 } 320 // Otherwise, we have run out of room in a dynamically allocated 321 // array. We need to reallocate: 322 else 323 { 324 __crt_unique_heap_ptr<Character*> new_array(_recalloc_crt_t(Character*, local_array.get(), argv_count * 2)); 325 _VALIDATE_RETURN_NOEXC(new_array.get() != nullptr, ENOMEM, nullptr); 326 327 local_array.detach(); 328 local_array.attach(new_array.detach()); 329 330 argv = local_array.get(); 331 } 332 333 argv_count *= 2; 334 } 335 336 argv[i++] = next_argument; 337 if (!next_argument) 338 break; 339 340 #pragma warning(suppress:__WARNING_INCORRECT_ANNOTATION) // 26007 Possibly incorrect single element annotation on arglist 341 next_argument = va_arg(*arglist, Character*); 342 } 343 344 // At this point, we have succeeded; either local_array is null, or argv is 345 // local_array. In either case, we detach so that we can transfer ownership 346 // to the caller: 347 local_array.detach(); 348 return argv; 349 } 350 351 extern "C" char** __acrt_capture_narrow_argv( 352 va_list* const arglist, 353 char const* const first_argument, 354 char** const caller_array, 355 size_t const caller_array_count 356 ) 357 { 358 return common_capture_argv(arglist, first_argument, caller_array, caller_array_count); 359 } 360 361 extern "C" wchar_t** __acrt_capture_wide_argv( 362 va_list* const arglist, 363 wchar_t const* const first_argument, 364 wchar_t** const caller_array, 365 size_t const caller_array_count 366 ) 367 { 368 return common_capture_argv(arglist, first_argument, caller_array, caller_array_count); 369 } 370