From 6abd78b5ec7cdfeedff36454b07a8dbff312b554 Mon Sep 17 00:00:00 2001 From: Joel Rosdahl Date: Thu, 1 Oct 2020 13:00:30 +0200 Subject: [PATCH] Handle missing .gcno file gracefully MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit GCC ≥9 has changed behavior for -ftest-coverage and --coverage in combination with -fprofile-dir=dir: - Without -fprofile-dir=dir the file is placed next to the object file but with a “.gcno” extension. - With -fprofile-dir=dir the file is also place next to the object file (i.e. not in the specified profile directory) but the same style of name as used for “.gcda” files (full pathname with slashes replaced with hash characters). Fix this by: - Checking if the expected (GCC <9) .gcno file is present. If not, fall back to running the compiler and increment the “unsupported option” counter. - Making sure to perform the above check before copying the object file to the cache so that a later ccache invocation won’t believe that there is a result in the cache. - Improving the copy_file routine to not create the destination file until it knows that there is a source file to copy from. Fixes #674. --- src/ccache.c | 15 +++++++++++++-- src/util.c | 20 ++++++++++---------- 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/src/ccache.c b/src/ccache.c index 5fb7b05dc..c0d2a4f72 100644 --- a/src/ccache.c +++ b/src/ccache.c @@ -1645,12 +1645,22 @@ to_cache(struct args *args, struct hash *depend_mode_hash) MTR_BEGIN("file", "file_put"); - put_file_in_cache(output_obj, cached_obj); if (produce_dep_file) { copy_file_to_cache(output_dep, cached_dep); } if (generating_coverage) { - copy_file_to_cache(output_cov, cached_cov); + if (stat(output_cov, &st) == 0) { + copy_file_to_cache(output_cov, cached_cov); + } else { + // The .gcno file is missing. This is likely due to compiling with GCC 9+, + // which uses another name for the .gcno file when using -ftest-coverage + // or --coverage when -fprofile-dir=dir is given. The .gcno file is still + // placed next to the object file, not in the specified profile directory, + // though. + cc_log("%s is missing", output_cov); + stats_update(STATS_UNSUPPORTED_OPTION); + failed(); + } } if (generating_stackusage) { copy_file_to_cache(output_su, cached_su); @@ -1661,6 +1671,7 @@ to_cache(struct args *args, struct hash *depend_mode_hash) if (using_split_dwarf) { copy_file_to_cache(output_dwo, cached_dwo); } + put_file_in_cache(output_obj, cached_obj); MTR_END("file", "file_put"); diff --git a/src/util.c b/src/util.c index 9f014bdc2..57660947d 100644 --- a/src/util.c +++ b/src/util.c @@ -320,12 +320,20 @@ copy_file(const char *src, int compress_level, bool via_tmp_file) { - int fd_out; + int fd_out = -1; char *tmp_name = NULL; gzFile gz_in = NULL; gzFile gz_out = NULL; int saved_errno = 0; + // Open source file. + int fd_in = open(src, O_RDONLY | O_BINARY); + if (fd_in == -1) { + saved_errno = errno; + cc_log("open error: %s", strerror(saved_errno)); + goto error; + } + // Open destination file. if (via_tmp_file) { tmp_name = x_strdup(dest); @@ -344,14 +352,6 @@ copy_file(const char *src, src, dest, compress_level > 0 ? "" : "un"); } - // Open source file. - int fd_in = open(src, O_RDONLY | O_BINARY); - if (fd_in == -1) { - saved_errno = errno; - cc_log("open error: %s", strerror(saved_errno)); - goto error; - } - gz_in = gzdopen(fd_in, "rb"); if (!gz_in) { saved_errno = errno; @@ -473,7 +473,7 @@ error: if (fd_out != -1) { close(fd_out); } - if (via_tmp_file) { + if (via_tmp_file && tmp_name) { tmp_unlink(tmp_name); free(tmp_name); } -- 2.47.2