Fix race when extracting the install base when Bazel runs in a PID namespace.
The PID is not a unique identifier in that case and if multiple instances of Bazel tried to extract itself to a shared location at the same time, they occasionally corrupted their temporary extraction directories. This is sometimes the case on CI systems (most notably Bazel's own CI), because a shared install base reduces the overhead of running the integration test suite a lot, as otherwise every test will extract its individual copy of Bazel.
RELNOTES: None.
PiperOrigin-RevId: 291685865
diff --git a/src/main/cpp/blaze.cc b/src/main/cpp/blaze.cc
index 5eb0048..49aecff 100644
--- a/src/main/cpp/blaze.cc
+++ b/src/main/cpp/blaze.cc
@@ -54,6 +54,11 @@
#include <utility>
#include <vector>
+#if !defined(_WIN32)
+#include <sys/stat.h>
+#include <unistd.h>
+#endif
+
#include "src/main/cpp/archive_utils.h"
#include "src/main/cpp/blaze_util.h"
#include "src/main/cpp/blaze_util_platform.h"
@@ -955,7 +960,29 @@
if (!blaze_util::PathExists(install_base)) {
uint64_t st = GetMillisecondsMonotonic();
// Work in a temp dir to avoid races.
+#if defined(_WIN32)
string tmp_install = install_base + ".tmp." + blaze::GetProcessIdAsString();
+#else
+ // On Linux, we can't use the PID as a unique identifier, because Bazel
+ // might run in a PID namespace and then all Bazel clients have the same
+ // PID, so we use mkdtemp instead.
+ std::vector<char> tmp_path(install_base.size() + strlen(".tmp.XXXXXX") + 1);
+ strcpy(tmp_path.data(), install_base.c_str());
+ strcat(tmp_path.data(), ".tmp.XXXXXX");
+ if (!blaze_util::MakeDirectories(blaze_util::Dirname(install_base), 0777)) {
+ BAZEL_DIE(blaze_exit_code::INTERNAL_ERROR)
+ << "couldn't create '" << blaze_util::Dirname(install_base)
+ << "': " << blaze_util::GetLastErrorString();
+ }
+ if (mkdtemp(tmp_path.data()) == nullptr) {
+ char *err = strerror(errno);
+ BAZEL_DIE(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR)
+ << "could not create temporary directory to extract install base"
+ << " (" << err << ")";
+ }
+ string tmp_install = tmp_path.data();
+ chmod(tmp_install.c_str(), 0777);
+#endif
ExtractArchiveOrDie(self_path, startup_options.product_name,
expected_install_md5, tmp_install);
BlessFiles(tmp_install);