Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package ccache for openSUSE:Factory checked in at 2024-02-28 19:45:10 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/ccache (Old) and /work/SRC/openSUSE:Factory/.ccache.new.1770 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "ccache" Wed Feb 28 19:45:10 2024 rev:76 rq:1152216 version:4.9.1 Changes: -------- --- /work/SRC/openSUSE:Factory/ccache/ccache.changes 2024-01-19 23:00:19.553925187 +0100 +++ /work/SRC/openSUSE:Factory/.ccache.new.1770/ccache.changes 2024-02-28 19:45:33.486402286 +0100 @@ -1,0 +2,12 @@ +Tue Feb 27 10:33:09 UTC 2024 - ming li <m...@suse.com> + +- Update to 4.9.1: + * Improved detection of bad remote storage URLs gracefully. This also fixes + crashes seen in ccacheâs own test suite. + * Made caching completely disabled when modification of a source or include + file is detected during ccache invocation. Previously this was only done for the direct mode. + * Fixed an MSVC crash when using /Zi with many concurrent compilations. + * Fixed a crash when -arch is the last compiler option. +- Drop no longer needed fix2038.patch + +------------------------------------------------------------------- Old: ---- ccache-4.9.tar.xz ccache-4.9.tar.xz.asc fix2038.patch New: ---- ccache-4.9.1.tar.xz ccache-4.9.1.tar.xz.asc BETA DEBUG BEGIN: Old: * Fixed a crash when -arch is the last compiler option. - Drop no longer needed fix2038.patch BETA DEBUG END: ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ ccache.spec ++++++ --- /var/tmp/diff_new_pack.3sRuTC/_old 2024-02-28 19:45:34.158426544 +0100 +++ /var/tmp/diff_new_pack.3sRuTC/_new 2024-02-28 19:45:34.162426688 +0100 @@ -23,7 +23,7 @@ %bcond_with hiredis %endif Name: ccache -Version: 4.9 +Version: 4.9.1 Release: 0 Summary: A Fast C/C++ Compiler Cache License: GPL-3.0-or-later @@ -45,7 +45,6 @@ BuildRequires: rubygem(asciidoctor) Provides: distcc:%{_bindir}/ccache %ifnarch %{ix86} %{arm} -Patch0: fix2038.patch %endif %if %{with hiredis} BuildRequires: pkgconfig(hiredis) >= 0.13.3 ++++++ ccache-4.9.tar.xz -> ccache-4.9.1.tar.xz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ccache-4.9/LICENSE.adoc new/ccache-4.9.1/LICENSE.adoc --- old/ccache-4.9/LICENSE.adoc 2023-12-30 16:08:02.000000000 +0100 +++ new/ccache-4.9.1/LICENSE.adoc 2024-02-05 20:29:52.000000000 +0100 @@ -35,7 +35,7 @@ ---- Copyright (C) 2002-2007 Andrew Tridgell -Copyright (C) 2009-2023 Joel Rosdahl and other contributors +Copyright (C) 2009-2024 Joel Rosdahl and other contributors ---- diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ccache-4.9/cmake/CcacheVersion.cmake new/ccache-4.9.1/cmake/CcacheVersion.cmake --- old/ccache-4.9/cmake/CcacheVersion.cmake 2023-12-30 16:08:02.000000000 +0100 +++ new/ccache-4.9.1/cmake/CcacheVersion.cmake 2024-02-05 20:29:52.000000000 +0100 @@ -22,7 +22,7 @@ # CCACHE_VERSION_ORIGIN is set to "archive" in scenario 1 and "git" in scenario # 3. -set(version_info "d65ba0b384f1df970e573fab8f5325399d9e3900 HEAD, tag: v4.9, origin/master, origin/HEAD, master") +set(version_info "ec510e9b0f333b8e97aee98108de3e0858340d59 HEAD, tag: v4.9.1, origin/HEAD, origin/4.9-maint, 4.9-maint") set(CCACHE_VERSION "unknown") if(version_info MATCHES "^([0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f])[0-9a-f]* (.*)") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ccache-4.9/doc/MANUAL.adoc new/ccache-4.9.1/doc/MANUAL.adoc --- old/ccache-4.9/doc/MANUAL.adoc 2023-12-30 16:08:02.000000000 +0100 +++ new/ccache-4.9.1/doc/MANUAL.adoc 2024-02-05 20:29:52.000000000 +0100 @@ -1027,13 +1027,15 @@ directory in the `.gcno` file. *gcno_cwd* also disables hashing of the current working directory if `-fprofile-abs-path` is used. *include_file_ctime*:: - By default, ccache will disable the direct mode if an include file has too - new ctime. This sloppiness disables that check. See also _<<Handling of - newly created header files>>_. + By default, ccache will disable caching if a source code file has a status + change time (ctime) after the start of the ccache invocation. This + sloppiness disables that check. See also _<<Handling of newly created source + files>>_. *include_file_mtime*:: - By default, ccache will disable the direct mode if an include file has too - new mtime. This sloppiness disables that check. See also _<<Handling of - newly created header files>>_. + By default, ccache will disable caching if a source code file has a + modification time (mtime) after the start of the ccache invocation. This + sloppiness disables that check. See also _<<Handling of newly created source + files>>_. *ivfsoverlay*:: Ignore the Clang compiler option `-ivfsoverlay` and its argument. This is useful if you use Xcode, which uses a virtual file system (VFS) for things @@ -1429,6 +1431,9 @@ Preconditions for using <<Precompiled headers,precompiled headers>> were not fulfilled. +| Could not read or parse input file | +An input file could not be read or parsed (see the debug log for details). + | Could not write to output file | The output path specified with `-o` could not be written to. @@ -1457,6 +1462,9 @@ | Forced recache | <<config_recache,*CCACHE_RECACHE*>> was used to overwrite an existing result. +| Input file modified during compilation | +An input file was modified during compilation. + | Internal error | Unexpected failure, e.g. due to problems reading/writing the cache. @@ -1631,31 +1639,23 @@ `/showIncludes` is added automatically if not specified by the user). -== Handling of newly created header files +== Handling of newly created source files -If modification time (mtime) or status change time (ctime) of one of the include -files is equal to (or newer than) the time compilation is being done, ccache -disables the direct mode (or, in the case of a <<Precompiled headers,precompiled -header>>, disables caching completely). This done as a safety measure to avoid a -race condition (see below). - -To be able to use a newly created header files in direct mode (or use a newly -precompiled header), either: - -* create the include file earlier in the build process, or -* set <<config_sloppiness,*sloppiness*>> to - *include_file_ctime,include_file_mtime* if you are willing to take the risk, - for instance if you know that your build system is robust enough not to - trigger the race condition. +If modification time (mtime) or status change time (ctime) of the source file or +one of the include files is equal to (or newer than) the time that ccache was +invoked, ccache disables caching completely. This is done as a safety measure to +avoid a race condition (see below). In practice, this is only a problem when +using file systems with very low timestamp granularity. You can set +<<config_sloppiness,*sloppiness*>> to *include_file_ctime,include_file_mtime* to +opt out of the safety measure. For reference, the race condition mentioned above consists of these events: -1. The preprocessor is run. -2. An include file is modified by someone. -3. The new include file is hashed by ccache. -4. The real compiler is run on the preprocessor's output, which contains data - from the old header file. -5. The wrong object file is stored in the cache. +1. A source code file is read by ccache and added to the input hash. +2. The source code file is modified. +3. The compiler is executed and reads the modified source code. +4. Ccache stores the compiler output in the cache associated with the incorrect + key (based on the unmodified source code). == Cache debugging @@ -1767,7 +1767,7 @@ works in combination with precompiled headers. * You may also want to include *include_file_mtime,include_file_ctime* in <<config_sloppiness,*sloppiness*>>. See - _<<Handling of newly created header files>>_. + _<<Handling of newly created source files>>_. * You must either: + -- @@ -1932,9 +1932,8 @@ `-Wp,-MMD,<path>`, and `-Wp,-D<define>`) is used. ** This was the first compilation with a new value of the <<config_base_dir,base directory>>. -** A modification or status change time of one of the include files is too new - (created the same second as the compilation is being done). See - _<<Handling of newly created header files>>_. +** A modification or status change time of one of the include files is too new . + See _<<Handling of newly created source files>>_. ** The `+__TIME__+` preprocessor macro is (potentially) being used. Ccache turns off direct mode if `+__TIME__+` is present in the source code. This is done as a safety measure since the string indicates that a `+__TIME__+` macro diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ccache-4.9/doc/NEWS.adoc new/ccache-4.9.1/doc/NEWS.adoc --- old/ccache-4.9/doc/NEWS.adoc 2023-12-30 16:08:02.000000000 +0100 +++ new/ccache-4.9.1/doc/NEWS.adoc 2024-02-05 20:29:52.000000000 +0100 @@ -1,5 +1,27 @@ = Ccache news +== Ccache 4.9.1 + +Release date: 2024-02-05 + +=== Bug fixes + +- Improved detection of bad remote storage URLs gracefully. This also fixes + crashes seen in ccache's own test suite. + + [small]#_[contributed by Joel Rosdahl]_# + +- Made caching completely disabled when modification of a source or include file + is detected during ccache invocation. Previously this was only done for the + direct mode. + + [small]#_[contributed by Joel Rosdahl]_# + +- Fixed a MSVC crash when using `/Zi` with many concurrent compilations. + + [small]#_[contributed by Joel Rosdahl]_# + +- Fixed a crash when `-arch` is the last compiler option. + + [small]#_[contributed by Joel Rosdahl]_# + + == Ccache 4.9 Release date: 2023-12-30 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ccache-4.9/src/Context.cpp new/ccache-4.9.1/src/Context.cpp --- old/ccache-4.9/src/Context.cpp 2023-12-30 16:08:02.000000000 +0100 +++ new/ccache-4.9.1/src/Context.cpp 2024-02-05 20:29:52.000000000 +0100 @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Joel Rosdahl and other contributors +// Copyright (C) 2020-2024 Joel Rosdahl and other contributors // // See doc/AUTHORS.adoc for a complete list of contributors. // @@ -41,13 +41,12 @@ Context::Context() : actual_cwd(util::actual_cwd()), apparent_cwd(util::apparent_cwd(actual_cwd)), - storage(config) + storage(config), #ifdef INODE_CACHE_SUPPORTED - , - inode_cache(config) + inode_cache(config), #endif + time_of_invocation(util::TimePoint::now()) { - time_of_invocation = util::TimePoint::now(); } void diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ccache-4.9/src/Context.hpp new/ccache-4.9.1/src/Context.hpp --- old/ccache-4.9/src/Context.hpp 2023-12-30 16:08:02.000000000 +0100 +++ new/ccache-4.9.1/src/Context.hpp 2024-02-05 20:29:52.000000000 +0100 @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2023 Joel Rosdahl and other contributors +// Copyright (C) 2020-2024 Joel Rosdahl and other contributors // // See doc/AUTHORS.adoc for a complete list of contributors. // @@ -67,13 +67,6 @@ // The original argument list. Args orig_args; - // Time of ccache invocation. - util::TimePoint time_of_invocation; - - // Time of compilation. Used to see if include files have changed after - // compilation. - util::TimePoint time_of_compilation; - // Files included by the preprocessor and their hashes. std::unordered_map<std::string, Hash::Digest> included_files; @@ -100,6 +93,9 @@ mutable InodeCache inode_cache; #endif + // Time of ccache invocation. + util::TimePoint time_of_invocation; + // PID of currently executing compiler that we have started, if any. 0 means // no ongoing compilation. pid_t compiler_pid = 0; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ccache-4.9/src/argprocessing.cpp new/ccache-4.9.1/src/argprocessing.cpp --- old/ccache-4.9/src/argprocessing.cpp 2023-12-30 16:08:02.000000000 +0100 +++ new/ccache-4.9.1/src/argprocessing.cpp 2024-02-05 20:29:52.000000000 +0100 @@ -426,6 +426,10 @@ // Handle -arch options. if (arg == "-arch") { + if (i == args.size() - 1) { + LOG("Missing argument to {}", args[i]); + return Statistic::bad_compiler_arguments; + } ++i; args_info.arch_args.emplace_back(args[i]); if (args_info.arch_args.size() == 2) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ccache-4.9/src/ccache.cpp new/ccache-4.9.1/src/ccache.cpp --- old/ccache-4.9/src/ccache.cpp 2023-12-30 16:08:02.000000000 +0100 +++ new/ccache-4.9.1/src/ccache.cpp 2024-02-05 20:29:52.000000000 +0100 @@ -304,54 +304,29 @@ #endif } -static bool -include_file_too_new(const Context& ctx, - const std::string& path, - const DirEntry& dir_entry) -{ - // The comparison using >= is intentional, due to a possible race between - // starting compilation and writing the include file. See also the notes under - // "Performance" in doc/MANUAL.adoc. - if (!(ctx.config.sloppiness().contains(core::Sloppy::include_file_mtime)) - && dir_entry.mtime() >= ctx.time_of_compilation) { - LOG("Include file {} too new", path); - return true; - } - - // The same >= logic as above applies to the change time of the file. - if (!(ctx.config.sloppiness().contains(core::Sloppy::include_file_ctime)) - && dir_entry.ctime() >= ctx.time_of_compilation) { - LOG("Include file {} ctime too new", path); - return true; - } - - return false; -} - -// Returns false if the include file was "too new" and therefore should disable -// the direct mode (or, in the case of a preprocessed header, fall back to just -// running the real compiler), otherwise true. -static bool -do_remember_include_file(Context& ctx, - std::string path, - Hash& cpp_hash, - bool system, - Hash* depend_mode_hash) +// This function hashes an include file and stores the path and hash in +// ctx.included_files. If the include file is a PCH, cpp_hash is also updated. +[[nodiscard]] tl::expected<void, Failure> +remember_include_file(Context& ctx, + std::string path, + Hash& cpp_hash, + bool system, + Hash* depend_mode_hash) { if (path.length() >= 2 && path[0] == '<' && path[path.length() - 1] == '>') { // Typically <built-in> or <command-line>. - return true; + return {}; } if (path == ctx.args_info.normalized_input_file) { // Don't remember the input file. - return true; + return {}; } if (system - && (ctx.config.sloppiness().contains(core::Sloppy::system_headers))) { + && ctx.config.sloppiness().contains(core::Sloppy::system_headers)) { // Don't remember this system header. - return true; + return {}; } // Canonicalize path for comparison; Clang uses ./header.h. @@ -361,7 +336,7 @@ if (ctx.included_files.find(path) != ctx.included_files.end()) { // Already known include file. - return true; + return {}; } #ifdef _WIN32 @@ -370,52 +345,35 @@ DWORD attributes = GetFileAttributes(path.c_str()); if (attributes != INVALID_FILE_ATTRIBUTES && attributes & FILE_ATTRIBUTE_DIRECTORY) { - return true; + return {}; } } #endif DirEntry dir_entry(path, DirEntry::LogOnError::yes); if (!dir_entry.exists()) { - return false; + return tl::unexpected(Statistic::bad_input_file); } if (dir_entry.is_directory()) { // Ignore directory, typically $PWD. - return true; + return {}; } if (!dir_entry.is_regular_file()) { // Device, pipe, socket or other strange creature. LOG("Non-regular include file {}", path); - return false; + return tl::unexpected(Statistic::bad_input_file); } for (const auto& ignore_header_path : ctx.ignore_header_paths) { if (file_path_matches_dir_prefix_or_file(ignore_header_path, path)) { - return true; + return {}; } } - const bool is_pch = is_precompiled_header(path); - const bool too_new = include_file_too_new(ctx, path, dir_entry); - - if (too_new) { - // Opt out of direct mode because of a race condition. - // - // The race condition consists of these events: - // - // - the preprocessor is run - // - an include file is modified by someone - // - the new include file is hashed by ccache - // - the real compiler is run on the preprocessor's output, which contains - // data from the old header file - // - the wrong object file is stored in the cache. - - return false; - } - // Let's hash the include file content. Hash::Digest file_digest; + const bool is_pch = is_precompiled_header(path); if (is_pch) { if (ctx.args_info.included_pch_file.empty()) { LOG("Detected use of precompiled header: {}", path); @@ -433,7 +391,7 @@ } if (!hash_binary_file(ctx, file_digest, path)) { - return false; + return tl::unexpected(Statistic::bad_input_file); } cpp_hash.hash_delimiter(using_pch_sum ? "pch_sum_hash" : "pch_hash"); cpp_hash.hash(util::format_digest(file_digest)); @@ -442,45 +400,24 @@ if (ctx.config.direct_mode()) { if (!is_pch) { // else: the file has already been hashed. auto ret = hash_source_code_file(ctx, file_digest, path); - if (ret.contains(HashSourceCode::error) - || ret.contains(HashSourceCode::found_time)) { - return false; + if (ret.contains(HashSourceCode::error)) { + return tl::unexpected(Statistic::bad_input_file); + } + if (ret.contains(HashSourceCode::found_time)) { + LOG_RAW("Disabling direct mode"); + ctx.config.set_direct_mode(false); } } - ctx.included_files.emplace(path, file_digest); - if (depend_mode_hash) { depend_mode_hash->hash_delimiter("include"); depend_mode_hash->hash(util::format_digest(file_digest)); } } - return true; -} - -enum class RememberIncludeFileResult { ok, cannot_use_pch }; - -// This function hashes an include file and stores the path and hash in -// ctx.included_files. If the include file is a PCH, cpp_hash is also updated. -static RememberIncludeFileResult -remember_include_file(Context& ctx, - const std::string& path, - Hash& cpp_hash, - bool system, - Hash* depend_mode_hash) -{ - if (!do_remember_include_file( - ctx, path, cpp_hash, system, depend_mode_hash)) { - if (is_precompiled_header(path)) { - return RememberIncludeFileResult::cannot_use_pch; - } else if (ctx.config.direct_mode()) { - LOG_RAW("Disabling direct mode"); - ctx.config.set_direct_mode(false); - } - } + ctx.included_files.emplace(path, file_digest); - return RememberIncludeFileResult::ok; + return {}; } static void @@ -627,10 +564,7 @@ hash.hash(inc_path); } - if (remember_include_file(ctx, inc_path, hash, system, nullptr) - == RememberIncludeFileResult::cannot_use_pch) { - return tl::unexpected(Statistic::could_not_use_precompiled_header); - } + TRY(remember_include_file(ctx, inc_path, hash, system, nullptr)); p = q; // Everything of interest between p and q has been hashed now. } else if (strncmp(q, incbin_directive, sizeof(incbin_directive)) == 0 && ((q[7] == ' ' @@ -672,7 +606,7 @@ std::string pch_path = Util::make_relative_path(ctx, ctx.args_info.included_pch_file); hash.hash(pch_path); - remember_include_file(ctx, pch_path, hash, false, nullptr); + TRY(remember_include_file(ctx, pch_path, hash, false, nullptr)); } bool debug_included = getenv("CCACHE_DEBUG_INCLUDED"); @@ -685,7 +619,7 @@ // Extract the used includes from the dependency file. Note that we cannot // distinguish system headers from other includes here. -static std::optional<Hash::Digest> +static tl::expected<Hash::Digest, Failure> result_key_from_depfile(Context& ctx, Hash& hash) { // Make sure that result hash will always be different from the manifest hash @@ -699,7 +633,7 @@ LOG("Failed to read dependency file {}: {}", ctx.args_info.output_dep, file_content.error()); - return std::nullopt; + return tl::unexpected(Statistic::bad_input_file); } for (std::string_view token : Depfile::tokenize(*file_content)) { @@ -707,7 +641,7 @@ continue; } std::string path = Util::make_relative_path(ctx, token); - remember_include_file(ctx, path, hash, false, &hash); + TRY(remember_include_file(ctx, path, hash, false, &hash)); } // Explicitly check the .gch/.pch/.pth file as it may not be mentioned in the @@ -716,7 +650,7 @@ std::string pch_path = Util::make_relative_path(ctx, ctx.args_info.included_pch_file); hash.hash(pch_path); - remember_include_file(ctx, pch_path, hash, false, nullptr); + TRY(remember_include_file(ctx, pch_path, hash, false, nullptr)); } bool debug_included = getenv("CCACHE_DEBUG_INCLUDED"); @@ -759,14 +693,14 @@ // Extract the used includes from /showIncludes output in stdout. Note that we // cannot distinguish system headers from other includes here. -static std::optional<Hash::Digest> +static tl::expected<Hash::Digest, Failure> result_key_from_includes(Context& ctx, Hash& hash, std::string_view stdout_data) { for (std::string_view include : core::MsvcShowIncludesOutput::get_includes( stdout_data, ctx.config.msvc_dep_prefix())) { const std::string path = Util::make_relative_path( ctx, Util::normalize_abstract_absolute_path(include)); - remember_include_file(ctx, path, hash, false, &hash); + TRY(remember_include_file(ctx, path, hash, false, &hash)); } // Explicitly check the .pch file as it is not mentioned in the @@ -775,7 +709,7 @@ std::string pch_path = Util::make_relative_path(ctx, ctx.args_info.included_pch_file); hash.hash(pch_path); - remember_include_file(ctx, pch_path, hash, false, nullptr); + TRY(remember_include_file(ctx, pch_path, hash, false, nullptr)); } const bool debug_included = getenv("CCACHE_DEBUG_INCLUDED"); @@ -872,7 +806,7 @@ MTR_SCOPE("manifest", "manifest_put"); - // ctime() may be 0, so we have to check time_of_compilation against + // ctime() may be 0, so we have to check time_of_invocation against // MAX(mtime, ctime). // // ccache only reads mtime/ctime if file_stat_matches sloppiness is enabled, @@ -887,7 +821,7 @@ DirEntry de(path, DirEntry::LogOnError::yes); bool cache_time = save_timestamp - && ctx.time_of_compilation > std::max(de.mtime(), de.ctime()); + && ctx.time_of_invocation > std::max(de.mtime(), de.ctime()); return core::Manifest::FileStats{ de.size(), de.is_regular_file() && cache_time ? de.mtime() : util::TimePoint(), @@ -1072,6 +1006,59 @@ } } +static std::string +format_epoch_time(const util::TimePoint& tp) +{ + return FMT("{}.{:09}", tp.sec(), tp.nsec_decimal_part()); +} + +static bool +source_file_is_too_new(const Context& ctx, const fs::path& path) +{ + const bool sloppy_ctime = + ctx.config.sloppiness().contains(core::Sloppy::include_file_ctime); + const bool sloppy_mtime = + ctx.config.sloppiness().contains(core::Sloppy::include_file_mtime); + + if ((sloppy_mtime && sloppy_ctime) || util::is_dev_null_path(path)) { + return false; + } + + // It's not enough to check if mtime/ctime >= ctx.time_of_invocation since + // filesystem timestamps are granular. See the comment for + // InodeCache::InodeCache for details. + // + // A relatively small safety margin is used in this case to make things safe + // on common filesystems while also not bailing out when creating a source + // file reasonably close in time before the compilation. + const util::Duration min_age(0, 100'000'000); // 0.1 s + util::TimePoint deadline = ctx.time_of_invocation + min_age; + + DirEntry dir_entry(path); + + if (!sloppy_mtime && dir_entry.mtime() >= deadline) { + LOG( + "{} was modified near or after invocation (mtime {}, invocation time {})", + dir_entry.path(), + format_epoch_time(dir_entry.mtime()), + format_epoch_time(ctx.time_of_invocation)); + return true; + } + + // The same logic as above applies to the change time of the file. + if (!sloppy_ctime && dir_entry.ctime() >= deadline) { + LOG( + "{} had status change near or after invocation (ctime {}, invocation" + " time {})", + dir_entry.path(), + format_epoch_time(dir_entry.ctime()), + format_epoch_time(ctx.time_of_invocation)); + return true; + } + + return false; +} + // Run the real compiler and put the result in cache. Returns the result key. static tl::expected<Hash::Digest, Failure> to_cache(Context& ctx, @@ -1139,7 +1126,6 @@ depend_mode_args.insert(1, depend_extra_args); add_prefix(ctx, depend_mode_args, ctx.config.prefix_command()); - ctx.time_of_compilation = util::TimePoint::now(); result = do_execute(ctx, depend_mode_args); } MTR_END("execute", "compiler"); @@ -1179,22 +1165,36 @@ if (ctx.config.depend_mode()) { ASSERT(depend_mode_hash); if (ctx.args_info.generating_dependencies) { - result_key = result_key_from_depfile(ctx, *depend_mode_hash); + auto key = result_key_from_depfile(ctx, *depend_mode_hash); + if (!key) { + return tl::unexpected(key.error()); + } + result_key = *key; } else if (ctx.args_info.generating_includes) { - result_key = result_key_from_includes( + auto key = result_key_from_includes( ctx, *depend_mode_hash, util::to_string_view(result->stdout_data)); + if (!key) { + return tl::unexpected(key.error()); + } + result_key = *key; } else { ASSERT(false); } - if (!result_key) { - return tl::unexpected(Statistic::internal_error); - } LOG_RAW("Got result key from dependency file"); LOG("Result key: {}", util::format_digest(*result_key)); } ASSERT(result_key); + if (source_file_is_too_new(ctx, ctx.args_info.input_file)) { + return tl::unexpected(Statistic::modified_input_file); + } + for (const auto& [path, digest] : ctx.included_files) { + if (source_file_is_too_new(ctx, path)) { + return tl::unexpected(Statistic::modified_input_file); + } + } + if (ctx.args_info.generating_dependencies) { Depfile::make_paths_relative_in_output_dep(ctx); } @@ -1239,8 +1239,6 @@ static tl::expected<Hash::Digest, Failure> get_result_key_from_cpp(Context& ctx, Args& args, Hash& hash) { - ctx.time_of_compilation = util::TimePoint::now(); - std::string preprocessed_path; util::Bytes cpp_stderr_data; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ccache-4.9/src/core/AtomicFile.cpp new/ccache-4.9.1/src/core/AtomicFile.cpp --- old/ccache-4.9/src/core/AtomicFile.cpp 2023-12-30 16:08:02.000000000 +0100 +++ new/ccache-4.9.1/src/core/AtomicFile.cpp 2024-02-05 20:29:52.000000000 +0100 @@ -1,4 +1,4 @@ -// Copyright (C) 2019-2023 Joel Rosdahl and other contributors +// Copyright (C) 2019-2024 Joel Rosdahl and other contributors // // See doc/AUTHORS.adoc for a complete list of contributors. // @@ -32,7 +32,7 @@ AtomicFile::AtomicFile(const fs::path& path, Mode mode) : m_path(path) { auto tmp_file = - util::value_or_throw<core::Fatal>(util::TemporaryFile::create(path)); + util::value_or_throw<core::Error>(util::TemporaryFile::create(path)); m_stream = fdopen(tmp_file.fd.release(), mode == Mode::binary ? "w+b" : "w+"); m_tmp_path = std::move(tmp_file.path); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ccache-4.9/src/core/Statistic.hpp new/ccache-4.9.1/src/core/Statistic.hpp --- old/ccache-4.9/src/core/Statistic.hpp 2023-12-30 16:08:02.000000000 +0100 +++ new/ccache-4.9.1/src/core/Statistic.hpp 2024-02-05 20:29:52.000000000 +0100 @@ -1,4 +1,4 @@ -// Copyright (C) 2021-2023 Joel Rosdahl and other contributors +// Copyright (C) 2021-2024 Joel Rosdahl and other contributors // // See doc/AUTHORS.adoc for a complete list of contributors. // @@ -79,7 +79,9 @@ subdir_size_kibibyte_base = 65, disabled = 81, - END = 82 + bad_input_file = 82, + modified_input_file = 83, + END = 84 }; } // namespace core diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ccache-4.9/src/core/Statistics.cpp new/ccache-4.9.1/src/core/Statistics.cpp --- old/ccache-4.9/src/core/Statistics.cpp 2023-12-30 16:08:02.000000000 +0100 +++ new/ccache-4.9.1/src/core/Statistics.cpp 2024-02-05 20:29:52.000000000 +0100 @@ -1,4 +1,4 @@ -// Copyright (C) 2021-2023 Joel Rosdahl and other contributors +// Copyright (C) 2021-2024 Joel Rosdahl and other contributors // // See doc/AUTHORS.adoc for a complete list of contributors. // @@ -76,6 +76,9 @@ // option argument. FIELD(bad_compiler_arguments, "Bad compiler arguments", FLAG_UNCACHEABLE), + // An input file could not be read or parsed (see the debug log for details). + FIELD(bad_input_file, "Could not read or parse input file", FLAG_ERROR), + // The output path specified with -o could not be written to. FIELD(bad_output_file, "Could not write to output file", FLAG_ERROR), @@ -173,6 +176,10 @@ // cache while another instance removed the file as part of cache cleanup. FIELD(missing_cache_file, "Missing cache file", FLAG_ERROR), + // An input file was modified during compilation. + FIELD( + modified_input_file, "Input file modified during compilation", FLAG_ERROR), + // The compiler was called to compile multiple source files in one go. This is // not supported by ccache. FIELD(multiple_source_files, "Multiple source files", FLAG_UNCACHEABLE), diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ccache-4.9/src/core/mainoptions.cpp new/ccache-4.9.1/src/core/mainoptions.cpp --- old/ccache-4.9/src/core/mainoptions.cpp 2023-12-30 16:08:02.000000000 +0100 +++ new/ccache-4.9.1/src/core/mainoptions.cpp 2024-02-05 20:29:52.000000000 +0100 @@ -1,4 +1,4 @@ -// Copyright (C) 2021-2023 Joel Rosdahl and other contributors +// Copyright (C) 2021-2024 Joel Rosdahl and other contributors // // See doc/AUTHORS.adoc for a complete list of contributors. // @@ -82,7 +82,7 @@ Features: {2} Copyright (C) 2002-2007 Andrew Tridgell -Copyright (C) 2009-2023 Joel Rosdahl and other contributors +Copyright (C) 2009-2024 Joel Rosdahl and other contributors See <https://ccache.dev/credits.html> for a complete list of contributors. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ccache-4.9/src/execute.cpp new/ccache-4.9.1/src/execute.cpp --- old/ccache-4.9/src/execute.cpp 2023-12-30 16:08:02.000000000 +0100 +++ new/ccache-4.9.1/src/execute.cpp 2024-02-05 20:29:52.000000000 +0100 @@ -170,7 +170,8 @@ // process is killed. JOBOBJECT_EXTENDED_LIMIT_INFORMATION jobInfo = {}; jobInfo.BasicLimitInformation.LimitFlags = - JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; + JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE + | JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK; BOOL job_success = SetInformationJobObject( job, JobObjectExtendedLimitInformation, &jobInfo, sizeof(jobInfo)); if (!job_success) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ccache-4.9/src/storage/Storage.cpp new/ccache-4.9.1/src/storage/Storage.cpp --- old/ccache-4.9/src/storage/Storage.cpp 2023-12-30 16:08:02.000000000 +0100 +++ new/ccache-4.9.1/src/storage/Storage.cpp 2024-02-05 20:29:52.000000000 +0100 @@ -1,4 +1,4 @@ -// Copyright (C) 2021-2023 Joel Rosdahl and other contributors +// Copyright (C) 2021-2024 Joel Rosdahl and other contributors // // See doc/AUTHORS.adoc for a complete list of contributors. // @@ -132,7 +132,7 @@ // now to avoid exceptions later. Url url(url_string); try { - std::ignore = url.scheme(); + std::ignore = url.str(); } catch (const std::exception& e) { return tl::unexpected(FMT("Cannot parse URL {}: {}", url_string, e.what())); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ccache-4.9/src/util/path.hpp new/ccache-4.9.1/src/util/path.hpp --- old/ccache-4.9/src/util/path.hpp 2023-12-30 16:08:02.000000000 +0100 +++ new/ccache-4.9.1/src/util/path.hpp 2024-02-05 20:29:52.000000000 +0100 @@ -1,4 +1,4 @@ -// Copyright (C) 2021-2023 Joel Rosdahl and other contributors +// Copyright (C) 2021-2024 Joel Rosdahl and other contributors // // See doc/AUTHORS.adoc for a complete list of contributors. // @@ -45,7 +45,7 @@ const char* get_dev_null_path(); // Return whether `path` is /dev/null or (on Windows) NUL. -bool is_dev_null_path(std::string_view path); +bool is_dev_null_path(const std::filesystem::path& path); // Return whether `path` includes at least one directory separator. bool is_full_path(std::string_view path); @@ -61,11 +61,11 @@ // --- Inline implementations --- inline bool -is_dev_null_path(const std::string_view path) +is_dev_null_path(const std::filesystem::path& path) { return path == "/dev/null" #ifdef _WIN32 - || util::to_lowercase(path) == "nul" + || util::to_lowercase(path.string()) == "nul" #endif ; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ccache-4.9/test/suites/base.bash new/ccache-4.9.1/test/suites/base.bash --- old/ccache-4.9/test/suites/base.bash 2023-12-30 16:08:02.000000000 +0100 +++ new/ccache-4.9.1/test/suites/base.bash 2024-02-05 20:29:52.000000000 +0100 @@ -282,6 +282,48 @@ rm -rf src # ------------------------------------------------------------------------- + TEST "Too new source file" + + touch new.c + touch -t 203801010000 new.c + + $CCACHE_COMPILE -c new.c + expect_stat modified_input_file 1 + expect_stat cache_miss 0 + + CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS include_file_mtime" $CCACHE_COMPILE -c new.c + expect_stat modified_input_file 1 + expect_stat cache_miss 1 + + # ------------------------------------------------------------------------- + TEST "Too new include file" + + cat <<EOF >new.c +#include "new.h" +EOF + cat <<EOF >new.h +int test; +EOF + touch -t 203801010000 new.h + + $CCACHE_COMPILE -c new.c + expect_stat modified_input_file 1 + expect_stat cache_miss 0 + + CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS include_file_mtime" $CCACHE_COMPILE -c new.c + expect_stat modified_input_file 1 + expect_stat cache_miss 1 + + # ------------------------------------------------------------------------- + TEST "Too new source file ignored if sloppy" + + touch new.c + touch -t 203801010000 new.c + + CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS include_file_mtime" $CCACHE_COMPILE -c new.c + expect_stat cache_miss 1 + + # ------------------------------------------------------------------------- TEST "LANG" $CCACHE_COMPILE -c test1.c diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ccache-4.9/test/suites/direct.bash new/ccache-4.9.1/test/suites/direct.bash --- old/ccache-4.9/test/suites/direct.bash 2023-12-30 16:08:02.000000000 +0100 +++ new/ccache-4.9.1/test/suites/direct.bash 2024-02-05 20:29:52.000000000 +0100 @@ -1073,27 +1073,6 @@ expect_stat cache_miss 1 # ------------------------------------------------------------------------- - TEST "Too new include file disables direct mode" - - cat <<EOF >new.c -#include "new.h" -EOF - cat <<EOF >new.h -int test; -EOF - touch -t 203801010000 new.h - - $CCACHE_COMPILE -c new.c - expect_stat direct_cache_hit 0 - expect_stat preprocessed_cache_hit 0 - expect_stat cache_miss 1 - - $CCACHE_COMPILE -c new.c - expect_stat direct_cache_hit 0 - expect_stat preprocessed_cache_hit 1 - expect_stat cache_miss 1 - - # ------------------------------------------------------------------------- TEST "__DATE__ in header file results in direct cache hit as the date remains the same" cat <<EOF >test_date2.c @@ -1116,27 +1095,6 @@ expect_stat direct_cache_hit 1 expect_stat preprocessed_cache_hit 0 expect_stat cache_miss 1 - - # ------------------------------------------------------------------------- - TEST "New include file ignored if sloppy" - - cat <<EOF >new.c -#include "new.h" -EOF - cat <<EOF >new.h -int test; -EOF - touch -t 203801010000 new.h - - CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS include_file_mtime" $CCACHE_COMPILE -c new.c - expect_stat direct_cache_hit 0 - expect_stat preprocessed_cache_hit 0 - expect_stat cache_miss 1 - - CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS include_file_mtime" $CCACHE_COMPILE -c new.c - expect_stat direct_cache_hit 1 - expect_stat preprocessed_cache_hit 0 - expect_stat cache_miss 1 # ------------------------------------------------------------------------- TEST "Sloppy Clang index store" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ccache-4.9/test/suites/pch.bash new/ccache-4.9.1/test/suites/pch.bash --- old/ccache-4.9/test/suites/pch.bash 2023-12-30 16:08:02.000000000 +0100 +++ new/ccache-4.9.1/test/suites/pch.bash 2024-02-05 20:29:52.000000000 +0100 @@ -631,14 +631,6 @@ # ------------------------------------------------------------------------- TEST "Too new PCH file" - # If the precompiled header is too new we shouldn't cache the result at all - # since: - # - # - the precompiled header content must be included in the hash, but - # - we don't trust the precompiled header content so we can't hash it - # ourselves, and - # - the preprocessed output doesn't contain the preprocessed header content. - touch lib.h touch main.c @@ -646,10 +638,7 @@ touch -d "@$(($(date +%s) + 60))" lib.h.gch # 1 minute in the future CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS pch_defines,time_macros" $CCACHE_COMPILE -include lib.h -c main.c - expect_stat direct_cache_hit 0 - expect_stat preprocessed_cache_hit 0 - expect_stat cache_miss 0 - expect_stat could_not_use_precompiled_header 1 + expect_stat modified_input_file 1 } pch_suite_clang() {