1 //
2 // get_environment_from_os.cpp
3 //
4 //      Copyright (c) Microsoft Corporation. All rights reserved.
5 //
6 // Defines a pair of functions to get the environment strings from the operating
7 // system.  These functions copy the environment strings into a CRT-allocated
8 // buffer and return a pointer to that buffer.  The caller is responsible for
9 // freeing the returned buffer (via _crt_free).
10 //
11 #include <corecrt_internal.h>
12 #include <corecrt_internal_traits.h>
13 #include <stdlib.h>
14 
15 
16 
17 namespace
18 {
19     struct environment_strings_traits
20     {
21         typedef wchar_t* type;
22 
23         static bool close(_In_ type p) throw()
24         {
25             FreeEnvironmentStringsW(p);
26             return true;
27         }
28 
29         static type get_invalid_value() throw()
30         {
31             return nullptr;
32         }
33     };
34 
35     typedef __crt_unique_handle_t<environment_strings_traits> environment_strings_handle;
36 }
37 
38 
39 
40 static wchar_t const* __cdecl find_end_of_double_null_terminated_sequence(wchar_t const* const first) throw()
41 {
42     wchar_t const* last = first;
43     for (; *last != '\0'; last += wcslen(last) + 1)
44     {
45     }
46 
47     return last + 1; // Return the pointer one-past-the-end of the double null terminator
48 }
49 
50 
51 
52 extern "C" wchar_t* __cdecl __dcrt_get_wide_environment_from_os() throw()
53 {
54     environment_strings_handle const environment(GetEnvironmentStringsW());
55     if (!environment)
56         return nullptr;
57 
58     // Find the
59     wchar_t const* const first = environment.get();
60     wchar_t const* const last = find_end_of_double_null_terminated_sequence(first);
61 
62     size_t const required_count = last - first;
63 
64     __crt_unique_heap_ptr<wchar_t> buffer(_malloc_crt_t(wchar_t, required_count));
65     if (!buffer)
66         return nullptr;
67 
68     // Note that the multiplication here cannot overflow:
69     memcpy(buffer.get(), environment.get(), required_count * sizeof(wchar_t));
70     return buffer.detach();
71 }
72 
73 
74 
75 extern "C" char* __cdecl __dcrt_get_narrow_environment_from_os() throw()
76 {
77     // Note that we call GetEnvironmentStringsW and convert to multibyte.  The
78     // GetEnvironmentStringsA function returns the environment in the OEM code
79     // page, but we need the strings in ANSI.
80     environment_strings_handle const environment(GetEnvironmentStringsW());
81     if (!environment.is_valid())
82         return nullptr;
83 
84     wchar_t const* const first = environment.get();
85     wchar_t const* const last = find_end_of_double_null_terminated_sequence(first);
86 
87     size_t const required_wide_count = last - first;
88 #pragma warning(suppress:__WARNING_W2A_BEST_FIT) // 38021 Prefast recommends WC_NO_BEST_FIT_CHARS.
89     size_t const required_narrow_count = static_cast<size_t>(__acrt_WideCharToMultiByte(
90         CP_ACP,
91         0,
92         environment.get(),
93         static_cast<int>(required_wide_count),
94         nullptr,
95         0,
96         nullptr,
97         nullptr));
98 
99     if (required_narrow_count == 0)
100         return nullptr;
101 
102     __crt_unique_heap_ptr<char> buffer(_malloc_crt_t(char, required_narrow_count));
103     if (!buffer)
104         return nullptr;
105 
106 #pragma warning(suppress:__WARNING_W2A_BEST_FIT) // 38021 Prefast recommends WC_NO_BEST_FIT_CHARS.
107     int const conversion_result = __acrt_WideCharToMultiByte(
108         CP_ACP,
109         0,
110         environment.get(),
111         static_cast<int>(required_wide_count),
112         buffer.get(),
113         static_cast<int>(required_narrow_count),
114         nullptr,
115         nullptr);
116 
117     if (conversion_result == 0)
118         return nullptr;
119 
120     return buffer.detach();
121 }
122