From 7d4167430c411ba1441260be9243d3401695ea7a Mon Sep 17 00:00:00 2001 From: KAWASHIMA Takahiro Date: Thu, 7 May 2020 16:40:06 +0900 Subject: [PATCH] [gcov] Fix simultaneous .gcda creation/lock Fixes PR45673 The commit 9180c14fe4d (D76206) resolved only a part of the problem of concurrent .gcda file creation. It ensured that only one process creates the file but did not ensure that the process locks the file first. If not, the process which created the file may clobber the contents written by a process which locked the file first. This is the cause of PR45673. This commit prevents the clobbering by revising the assumption that a process which creates the file locks the file first. Regardless of file creation, a process which locked the file first uses fwrite (new_file==1) and other processes use mmap (new_file==0). I also tried to keep the creation/first-lock process same by using mkstemp/link/unlink but the code gets long. This commit is more simple. Note: You may be confused with other changes which try to resolve concurrent file access. My understanding is (may not be correct): D76206: Resolve race of .gcda file creation (but not lock) This one: Resolve race of .gcda file creation and lock D54599: Same as D76206 but abandoned? D70910: Resolve race of multi-threaded counter flushing D74953: Resolve counter sharing between parent/children processes D78477: Revision of D74953 Differential Revision: https://reviews.llvm.org/D79556 --- compiler-rt/lib/profile/GCDAProfiling.c | 23 ++++++++-------------- .../profile/Posix/instrprof-gcov-parallel.test | 2 -- 2 files changed, 8 insertions(+), 17 deletions(-) diff --git a/compiler-rt/lib/profile/GCDAProfiling.c b/compiler-rt/lib/profile/GCDAProfiling.c index 0463e97..ccbd180 100644 --- a/compiler-rt/lib/profile/GCDAProfiling.c +++ b/compiler-rt/lib/profile/GCDAProfiling.c @@ -265,8 +265,8 @@ static int map_file() { fseek(output_file, 0L, SEEK_END); file_size = ftell(output_file); - /* A size of 0 is invalid to `mmap'. Return a fail here, but don't issue an - * error message because it should "just work" for the user. */ + /* A size of 0 means the file has been created just now (possibly by another + * process in lock-after-open race condition). No need to mmap. */ if (file_size == 0) return -1; @@ -355,21 +355,18 @@ void llvm_gcda_start_file(const char *orig_filename, const char version[4], filename = mangle_filename(orig_filename); /* Try just opening the file. */ - new_file = 0; fd = open(filename, O_RDWR | O_BINARY); if (fd == -1) { /* Try creating the file. */ fd = open(filename, O_RDWR | O_CREAT | O_EXCL | O_BINARY, 0644); if (fd != -1) { - new_file = 1; mode = "w+b"; } else { /* Try creating the directories first then opening the file. */ __llvm_profile_recursive_mkdir(filename); fd = open(filename, O_RDWR | O_CREAT | O_EXCL | O_BINARY, 0644); if (fd != -1) { - new_file = 1; mode = "w+b"; } else { /* Another process may have created the file just now. @@ -394,22 +391,18 @@ void llvm_gcda_start_file(const char *orig_filename, const char version[4], output_file = fdopen(fd, mode); /* Initialize the write buffer. */ + new_file = 0; write_buffer = NULL; cur_buffer_size = 0; cur_pos = 0; - if (new_file) { + if (map_file() == -1) { + /* The file has been created just now (file_size == 0) or mmap failed + * unexpectedly. In the latter case, try to recover by clobbering. */ + new_file = 1; + write_buffer = NULL; resize_write_buffer(WRITE_BUFFER_SIZE); memset(write_buffer, 0, WRITE_BUFFER_SIZE); - } else { - if (map_file() == -1) { - /* mmap failed, try to recover by clobbering */ - new_file = 1; - write_buffer = NULL; - cur_buffer_size = 0; - resize_write_buffer(WRITE_BUFFER_SIZE); - memset(write_buffer, 0, WRITE_BUFFER_SIZE); - } } /* gcda file, version, stamp checksum. */ diff --git a/compiler-rt/test/profile/Posix/instrprof-gcov-parallel.test b/compiler-rt/test/profile/Posix/instrprof-gcov-parallel.test index fe0bf59..e700d2d 100644 --- a/compiler-rt/test/profile/Posix/instrprof-gcov-parallel.test +++ b/compiler-rt/test/profile/Posix/instrprof-gcov-parallel.test @@ -1,6 +1,4 @@ UNSUPPORTED: host-byteorder-big-endian -# Work around PR45673 until the test code is fixed -# ALLOW_RETRIES: 2 RUN: mkdir -p %t.d RUN: cd %t.d -- 2.7.4