Skip to content

Commit 4a6b397

Browse files
refactor: Extract GetExecutablePath helper in analytics_windows.cc
I've refactored `VerifyAndLoadAnalyticsLibrary` in `analytics_windows.cc` to improve readability and modularity by extracting the logic for obtaining the executable's full path into a new static helper function `GetExecutablePath()`. - The new `GetExecutablePath()` function encapsulates the prioritized use of `_get_wpgmptr()`, fallback to `_get_pgmptr()`, and the necessary `MultiByteToWideChar` conversion, along with all associated error handling and logging. It returns `std::wstring`. - `VerifyAndLoadAnalyticsLibrary` now calls `GetExecutablePath()` and checks its return value before proceeding with path manipulation. - This change makes `VerifyAndLoadAnalyticsLibrary` shorter and easier to understand. All previous security enhancements and fixes are maintained.
1 parent df2278d commit 4a6b397

File tree

1 file changed

+83
-6
lines changed

1 file changed

+83
-6
lines changed

analytics/src/analytics_windows.cc

Lines changed: 83 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,51 @@ namespace firebase {
1212
namespace analytics {
1313
namespace internal {
1414

15+
// Helper function to retrieve the full path of the current executable.
16+
// Returns an empty string on failure.
17+
static std::wstring GetExecutablePath() {
18+
std::wstring executable_path_str;
19+
wchar_t* wpgmptr_val = nullptr;
20+
21+
// Prefer _get_wpgmptr()
22+
errno_t err_w = _get_wpgmptr(&wpgmptr_val);
23+
if (err_w == 0 && wpgmptr_val != nullptr && wpgmptr_val[0] != L'\0') {
24+
executable_path_str = wpgmptr_val;
25+
} else {
26+
// Fallback to _get_pgmptr() and convert to wide string
27+
char* pgmptr_val = nullptr;
28+
errno_t err_c = _get_pgmptr(&pgmptr_val);
29+
if (err_c == 0 && pgmptr_val != nullptr && pgmptr_val[0] != '\0') {
30+
// Convert narrow string to wide string using CP_ACP (system default ANSI code page)
31+
int wide_char_count = MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS, pgmptr_val, -1, NULL, 0);
32+
if (wide_char_count == 0) { // Failure if count is 0
33+
DWORD conversion_error = GetLastError();
34+
LogError("GetExecutablePath: MultiByteToWideChar failed to calculate size for _get_pgmptr path. Error: %u", conversion_error);
35+
return L"";
36+
}
37+
38+
std::vector<wchar_t> wide_path_buffer(wide_char_count);
39+
if (MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS, pgmptr_val, -1, wide_path_buffer.data(), wide_char_count) == 0) {
40+
DWORD conversion_error = GetLastError();
41+
LogError("GetExecutablePath: MultiByteToWideChar failed to convert _get_pgmptr path. Error: %u", conversion_error);
42+
return L"";
43+
}
44+
executable_path_str = wide_path_buffer.data();
45+
} else {
46+
// Both _get_wpgmptr and _get_pgmptr failed or returned empty/null
47+
LogError("GetExecutablePath: Failed to retrieve executable path using both _get_wpgmptr (err: %d) and _get_pgmptr (err: %d).", err_w, err_c);
48+
return L"";
49+
}
50+
}
51+
52+
// Safeguard if path somehow resolved to empty despite initial checks.
53+
if (executable_path_str.empty()) {
54+
LogError("GetExecutablePath: Executable path resolved to an empty string.");
55+
return L"";
56+
}
57+
return executable_path_str;
58+
}
59+
1560
// Helper function to calculate SHA256 hash of a file.
1661
static std::vector<BYTE> CalculateFileSha256(HANDLE hFile) {
1762
HCRYPTPROV hProv = 0;
@@ -100,17 +145,49 @@ HMODULE VerifyAndLoadAnalyticsLibrary(
100145
return nullptr;
101146
}
102147

103-
// Get full path to the executable using _wpgmptr.
104-
// This global variable is provided by the CRT and is expected to be available on Windows.
105-
if (_wpgmptr == nullptr || _wpgmptr[0] == L'\0') {
106-
LogError("VerifyAndLoadAnalyticsLibrary: _wpgmptr is null or empty, cannot determine executable path.");
148+
// Get full path to the executable.
149+
std::wstring executable_path_str;
150+
wchar_t* wpgmptr_val = nullptr;
151+
152+
// Prefer _get_wpgmptr()
153+
errno_t err_w = _get_wpgmptr(&wpgmptr_val);
154+
if (err_w == 0 && wpgmptr_val != nullptr && wpgmptr_val[0] != L'\0') {
155+
executable_path_str = wpgmptr_val;
156+
} else {
157+
// Fallback to _get_pgmptr() and convert to wide string
158+
char* pgmptr_val = nullptr;
159+
errno_t err_c = _get_pgmptr(&pgmptr_val);
160+
if (err_c == 0 && pgmptr_val != nullptr && pgmptr_val[0] != '\0') {
161+
// Convert narrow string to wide string using CP_ACP (system default ANSI code page)
162+
int wide_char_count = MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS, pgmptr_val, -1, NULL, 0);
163+
if (wide_char_count == 0) { // Failure if count is 0
164+
DWORD conversion_error = GetLastError();
165+
LogError("VerifyAndLoadAnalyticsLibrary: MultiByteToWideChar failed to calculate size for _get_pgmptr path. Error: %u", conversion_error);
166+
return nullptr;
167+
}
168+
169+
std::vector<wchar_t> wide_path_buffer(wide_char_count);
170+
if (MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS, pgmptr_val, -1, wide_path_buffer.data(), wide_char_count) == 0) {
171+
DWORD conversion_error = GetLastError();
172+
LogError("VerifyAndLoadAnalyticsLibrary: MultiByteToWideChar failed to convert _get_pgmptr path. Error: %u", conversion_error);
173+
return nullptr;
174+
}
175+
executable_path_str = wide_path_buffer.data();
176+
} else {
177+
// Both _get_wpgmptr and _get_pgmptr failed or returned empty/null
178+
LogError("VerifyAndLoadAnalyticsLibrary: Failed to retrieve executable path using both _get_wpgmptr (err: %d) and _get_pgmptr (err: %d).", err_w, err_c);
179+
return nullptr;
180+
}
181+
}
182+
183+
if (executable_path_str.empty()) {
184+
LogError("VerifyAndLoadAnalyticsLibrary: Executable path resolved to an empty string.");
107185
return nullptr;
108186
}
109-
std::wstring executable_path_str(_wpgmptr);
110187

111188
size_t last_slash_pos = executable_path_str.find_last_of(L"\\");
112189
if (last_slash_pos == std::wstring::npos) {
113-
LogError("VerifyAndLoadAnalyticsLibrary: Could not determine executable directory from _wpgmptr (no backslash found).");
190+
LogError("VerifyAndLoadAnalyticsLibrary: Could not determine executable directory from retrieved path (no backslash found).");
114191
return nullptr;
115192
}
116193

0 commit comments

Comments
 (0)