]> git.ipfire.org Git - thirdparty/ccache.git/commitdiff
Add preprocessed file extension to cpp stdout early
authorJoel Rosdahl <joel@rosdahl.net>
Mon, 21 Dec 2020 18:02:19 +0000 (19:02 +0100)
committerJoel Rosdahl <joel@rosdahl.net>
Sat, 26 Dec 2020 15:22:39 +0000 (16:22 +0100)
Unless when compiling a preprocessed file directly, ccache creates a
temporary file to store the output of the preprocessor, registers the
file for removal at program exit, renames the file to one with a .i/.ii
extension and then registers that file for removal as well. This works
by chance in practice as long as mkstemp() returns something with low
probability of being reused, but as discussed in #736 it risks failing
when mkstemp() doesn’t behave that way.

Fix this by creating the new name (with the needed extension) using a
hard link so that the original file will outlive the new file, thus
blocking another ccache process from creating a file with the same name
again. To make the new temporary file outlive the old file, also delete
pending temporary files in LIFO order.

src/Context.cpp
src/ccache.cpp

index 7706b7d947a0a603d88476ac43c78b5363c09244..a7ce450c5235fc6afbe5602d000c89e82775f48c 100644 (file)
@@ -56,9 +56,10 @@ Context::register_pending_tmp_file(const std::string& path)
 void
 Context::unlink_pending_tmp_files_signal_safe()
 {
-  for (const std::string& path : m_pending_tmp_files) {
+  for (auto it = m_pending_tmp_files.rbegin(); it != m_pending_tmp_files.rend();
+       ++it) {
     // Don't call Util::unlink_tmp since its log calls aren't signal safe.
-    unlink(path.c_str());
+    unlink(it->c_str());
   }
   // Don't clear m_pending_tmp_files since this method must be signal safe.
 }
@@ -68,8 +69,9 @@ Context::unlink_pending_tmp_files()
 {
   SignalHandlerBlocker signal_handler_blocker;
 
-  for (const std::string& path : m_pending_tmp_files) {
-    Util::unlink_tmp(path, Util::UnlinkLog::ignore_failure);
+  for (auto it = m_pending_tmp_files.rbegin(); it != m_pending_tmp_files.rend();
+       ++it) {
+    Util::unlink_tmp(*it, Util::UnlinkLog::ignore_failure);
   }
   m_pending_tmp_files.clear();
 }
index 654af6f878331a5934c137eb0e234a69ee7e2fde..11d6164498adec7d511df0336b32d8a0125904aa 100644 (file)
@@ -1081,7 +1081,12 @@ get_result_name_from_cpp(Context& ctx, Args& args, Hash& hash)
 
     TemporaryFile tmp_stdout(
       FMT("{}/tmp.cpp_stdout", ctx.config.temporary_dir()));
-    stdout_path = tmp_stdout.path;
+    ctx.register_pending_tmp_file(tmp_stdout.path);
+
+    // stdout_path needs the proper cpp_extension for the compiler to do its
+    // thing correctly.
+    stdout_path = FMT("{}.{}", tmp_stdout.path, ctx.config.cpp_extension());
+    Util::hard_link(tmp_stdout.path, stdout_path);
     ctx.register_pending_tmp_file(stdout_path);
 
     TemporaryFile tmp_stderr(
@@ -1131,11 +1136,7 @@ get_result_name_from_cpp(Context& ctx, Args& args, Hash& hash)
   if (ctx.args_info.direct_i_file) {
     ctx.i_tmpfile = ctx.args_info.input_file;
   } else {
-    // i_tmpfile needs the proper cpp_extension for the compiler to do its
-    // thing correctly
-    ctx.i_tmpfile = FMT("{}.{}", stdout_path, ctx.config.cpp_extension());
-    Util::rename(stdout_path, ctx.i_tmpfile);
-    ctx.register_pending_tmp_file(ctx.i_tmpfile);
+    ctx.i_tmpfile = stdout_path;
   }
 
   if (!ctx.config.run_second_cpp()) {