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