Fix uninitialized message_buffer in GetLastErrorString on Windows. When FormatMessageA fails (such as for unmapped error codes without system message table entries), message_buffer remains uninitialized. Check the return value of FormatMessageA and initialize message_buffer to nullptr so that on failure we avoid dereferencing garbage stack memory or passing it to LocalFree. PiperOrigin-RevId: 995170634 Change-Id: I6c76d60b63909ced02dfb5ea450be6b2c31d8c80
diff --git a/src/main/cpp/util/errors_windows.cc b/src/main/cpp/util/errors_windows.cc index dae7640..f10a4eb 100644 --- a/src/main/cpp/util/errors_windows.cc +++ b/src/main/cpp/util/errors_windows.cc
@@ -33,14 +33,22 @@ return "success"; } - char* message_buffer; - FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - nullptr, last_error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - (LPSTR)&message_buffer, 0, nullptr); + char* message_buffer = nullptr; + DWORD size = FormatMessageA( + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + nullptr, last_error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPSTR)&message_buffer, 0, nullptr); + + DWORD format_message_error = ::GetLastError(); stringstream result; - result << "(error: " << last_error << "): " << message_buffer; + if (size == 0 || message_buffer == nullptr) { + result << "(error: 0x" << std::hex << last_error + << "): <FormatMessageA failed: 0x" << format_message_error << ">"; + } else { + result << "(error: " << last_error << "): " << message_buffer; + } LocalFree(message_buffer); return result.str(); }
diff --git a/src/tools/launcher/util/launcher_util.cc b/src/tools/launcher/util/launcher_util.cc index b3cb5e0..ab1a8e4 100644 --- a/src/tools/launcher/util/launcher_util.cc +++ b/src/tools/launcher/util/launcher_util.cc
@@ -48,14 +48,22 @@ return string(); } - char* message_buffer; - FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - nullptr, last_error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - (LPSTR)&message_buffer, 0, nullptr); + char* message_buffer = nullptr; + DWORD size = FormatMessageA( + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + nullptr, last_error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPSTR)&message_buffer, 0, nullptr); + + DWORD format_message_error = GetLastError(); stringstream result; - result << "(error: " << last_error << "): " << message_buffer; + if (size == 0 || message_buffer == nullptr) { + result << "(error: 0x" << std::hex << last_error + << "): <FormatMessageA failed: 0x" << format_message_error << ">"; + } else { + result << "(error: " << last_error << "): " << message_buffer; + } LocalFree(message_buffer); return result.str(); }
diff --git a/src/tools/launcher/util/launcher_util_test.cc b/src/tools/launcher/util/launcher_util_test.cc index 8a8a100..a8d3a63 100644 --- a/src/tools/launcher/util/launcher_util_test.cc +++ b/src/tools/launcher/util/launcher_util_test.cc
@@ -211,5 +211,17 @@ ASSERT_FALSE(RelativeTo(L"c:\\foo\\bar1", L"d:\\foo\\bar2", &value)); } +TEST_F(LaunchUtilTest, GetLastErrorStringTest) { + SetLastError(0); + ASSERT_EQ("", GetLastErrorString()); + + // Use a customer-bit error code (bit 29 set) which is guaranteed to have no + // system message table entry, exercising the FormatMessageA failure fallback. + SetLastError(0x20000001); + string result = GetLastErrorString(); + ASSERT_NE(result.find("0x20000001"), string::npos); + ASSERT_NE(result.find("<FormatMessageA failed: 0x"), string::npos); +} + } // namespace launcher } // namespace bazel