From: Joel Rosdahl Date: Fri, 18 Sep 2020 06:36:08 +0000 (+0200) Subject: Add ASSERT and DEBUG_ASSERT macros X-Git-Tag: v4.0~82 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=706f74430064463dcbea8104be2eed93c563e0fc;p=thirdparty%2Fccache.git Add ASSERT and DEBUG_ASSERT macros CMake always defines NDEBUG in release builds, so assertions are only enabled in debug builds. Assertions were however always enabled before switching to CMake. I prefer keeping assertions enabled in release builds as well unless they are part of a tight loop. Fix this by introducing two custom assertion macors: - ASSERT(condition): Like assert(condition) but always enabled. - DEBUG_ASSERT(condition): Like assert(condition), i.e. only enabled in debug builds. All usage of assert(condition) is converted to ASSERT(condition) since none of the assertions are made in performance-critical code. --- diff --git a/src/AtomicFile.cpp b/src/AtomicFile.cpp index 8c7d6c7b4..d02679b40 100644 --- a/src/AtomicFile.cpp +++ b/src/AtomicFile.cpp @@ -20,6 +20,7 @@ #include "TemporaryFile.hpp" #include "Util.hpp" +#include "assertions.hpp" #include "exceptions.hpp" AtomicFile::AtomicFile(const std::string& path, Mode mode) : m_path(path) @@ -57,7 +58,7 @@ AtomicFile::write(const std::vector& data) void AtomicFile::commit() { - assert(m_stream); + ASSERT(m_stream); int result = fclose(m_stream); m_stream = nullptr; if (result == EOF) { diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 775472c7b..122588703 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -32,6 +32,7 @@ set( ZstdCompressor.cpp ZstdDecompressor.cpp argprocessing.cpp + assertions.cpp ccache.cpp cleanup.cpp compopt.cpp diff --git a/src/Compression.cpp b/src/Compression.cpp index abe56ab2c..aa2a18271 100644 --- a/src/Compression.cpp +++ b/src/Compression.cpp @@ -20,6 +20,7 @@ #include "Config.hpp" #include "Context.hpp" +#include "assertions.hpp" #include "exceptions.hpp" namespace Compression { @@ -61,8 +62,7 @@ type_to_string(Type type) return "zstd"; } - assert(false); - return {}; + ASSERT(false); } } // namespace Compression diff --git a/src/Compressor.cpp b/src/Compressor.cpp index 8ccc418c7..efb12573e 100644 --- a/src/Compressor.cpp +++ b/src/Compressor.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2019 Joel Rosdahl and other contributors +// Copyright (C) 2019-2020 Joel Rosdahl and other contributors // // See doc/AUTHORS.adoc for a complete list of contributors. // @@ -21,6 +21,7 @@ #include "NullCompressor.hpp" #include "StdMakeUnique.hpp" #include "ZstdCompressor.hpp" +#include "assertions.hpp" std::unique_ptr Compressor::create_from_type(Compression::Type type, @@ -35,6 +36,5 @@ Compressor::create_from_type(Compression::Type type, return std::make_unique(stream, compression_level); } - assert(false); - return {}; + ASSERT(false); } diff --git a/src/Config.cpp b/src/Config.cpp index b09764280..bcfa9b960 100644 --- a/src/Config.cpp +++ b/src/Config.cpp @@ -21,6 +21,7 @@ #include "AtomicFile.hpp" #include "Compression.hpp" #include "Util.hpp" +#include "assertions.hpp" #include "ccache.hpp" #include "exceptions.hpp" @@ -577,8 +578,7 @@ Config::get_string_value(const std::string& key) const return format_umask(m_umask); } - assert(false); - return {}; // Never reached + ASSERT(false); // Never reached } void diff --git a/src/Counters.cpp b/src/Counters.cpp index 986aacfab..2e1b0e282 100644 --- a/src/Counters.cpp +++ b/src/Counters.cpp @@ -19,6 +19,7 @@ #include "Counters.hpp" #include "Statistics.hpp" +#include "assertions.hpp" #include @@ -30,7 +31,7 @@ uint64_t Counters::get(Statistic statistic) const { const auto index = static_cast(statistic); - assert(index < static_cast(Statistic::END)); + ASSERT(index < static_cast(Statistic::END)); return index < m_counters.size() ? m_counters[index] : 0; } @@ -38,14 +39,14 @@ void Counters::set(Statistic statistic, uint64_t value) { const auto index = static_cast(statistic); - assert(index < static_cast(Statistic::END)); + ASSERT(index < static_cast(Statistic::END)); m_counters[index] = value; } uint64_t Counters::get_raw(size_t index) const { - assert(index < size()); + ASSERT(index < size()); return m_counters[index]; } diff --git a/src/Decompressor.cpp b/src/Decompressor.cpp index f41caf64b..b53cd952a 100644 --- a/src/Decompressor.cpp +++ b/src/Decompressor.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2019 Joel Rosdahl and other contributors +// Copyright (C) 2019-2020 Joel Rosdahl and other contributors // // See doc/AUTHORS.adoc for a complete list of contributors. // @@ -21,6 +21,7 @@ #include "NullDecompressor.hpp" #include "StdMakeUnique.hpp" #include "ZstdDecompressor.hpp" +#include "assertions.hpp" std::unique_ptr Decompressor::create_from_type(Compression::Type type, FILE* stream) @@ -33,6 +34,5 @@ Decompressor::create_from_type(Compression::Type type, FILE* stream) return std::make_unique(stream); } - assert(false); - return {}; + ASSERT(false); } diff --git a/src/Fd.hpp b/src/Fd.hpp index e9d139c13..80bc77eae 100644 --- a/src/Fd.hpp +++ b/src/Fd.hpp @@ -21,6 +21,7 @@ #include "system.hpp" #include "NonCopyable.hpp" +#include "assertions.hpp" class Fd : NonCopyable { @@ -76,7 +77,7 @@ inline int Fd::operator*() const // clang-format on { - assert(m_fd != -1); + ASSERT(m_fd != -1); return m_fd; } diff --git a/src/Result.cpp b/src/Result.cpp index 7c1af27f6..979fe5041 100644 --- a/src/Result.cpp +++ b/src/Result.cpp @@ -260,7 +260,7 @@ Reader::read_entry(CacheEntryReader& cache_entry_reader, remain -= n; } } else { - assert(marker == k_raw_file_marker); + ASSERT(marker == k_raw_file_marker); auto raw_path = get_raw_file_path(m_result_path, entry_number); auto st = Stat::stat(raw_path, Stat::OnError::throw_error); diff --git a/src/ResultExtractor.cpp b/src/ResultExtractor.cpp index fe3ed2393..10b8189c8 100644 --- a/src/ResultExtractor.cpp +++ b/src/ResultExtractor.cpp @@ -66,7 +66,7 @@ ResultExtractor::on_entry_start(uint32_t /*entry_number*/, void ResultExtractor::on_entry_data(const uint8_t* data, size_t size) { - assert(m_dest_fd); + ASSERT(m_dest_fd); try { Util::write_fd(*m_dest_fd, data, size); diff --git a/src/ResultRetriever.cpp b/src/ResultRetriever.cpp index 09090e2ec..dd4374f38 100644 --- a/src/ResultRetriever.cpp +++ b/src/ResultRetriever.cpp @@ -119,7 +119,7 @@ ResultRetriever::on_entry_start(uint32_t entry_number, void ResultRetriever::on_entry_data(const uint8_t* data, size_t size) { - assert((m_dest_file_type == FileType::stderr_output && !m_dest_fd) + ASSERT((m_dest_file_type == FileType::stderr_output && !m_dest_fd) || (m_dest_file_type != FileType::stderr_output && m_dest_fd)); if (m_dest_file_type == FileType::stderr_output diff --git a/src/SignalHandler.cpp b/src/SignalHandler.cpp index 23521dca9..37604c269 100644 --- a/src/SignalHandler.cpp +++ b/src/SignalHandler.cpp @@ -18,6 +18,8 @@ #include "SignalHandler.hpp" +#include "assertions.hpp" + #ifndef _WIN32 # include "Context.hpp" @@ -44,7 +46,7 @@ register_signal_handler(int signum) SignalHandler::SignalHandler(Context& ctx) : m_ctx(ctx) { - assert(!g_the_signal_handler); + ASSERT(!g_the_signal_handler); g_the_signal_handler = this; sigemptyset(&g_fatal_signal_set); @@ -69,14 +71,14 @@ SignalHandler::SignalHandler(Context& ctx) : m_ctx(ctx) SignalHandler::~SignalHandler() { - assert(g_the_signal_handler); + ASSERT(g_the_signal_handler); g_the_signal_handler = nullptr; } void SignalHandler::on_signal(int signum) { - assert(g_the_signal_handler); + ASSERT(g_the_signal_handler); Context& ctx = g_the_signal_handler->m_ctx; // Unregister handler for this signal so that we can send the signal to diff --git a/src/Util.cpp b/src/Util.cpp index d233480a5..7b4d8b7e5 100644 --- a/src/Util.cpp +++ b/src/Util.cpp @@ -132,7 +132,7 @@ template std::vector split_at(string_view input, const char* separators) { - assert(separators != nullptr && separators[0] != '\0'); + ASSERT(separators != nullptr && separators[0] != '\0'); std::vector result; @@ -307,8 +307,8 @@ common_dir_prefix_length(string_view dir, string_view path) return 0; } - assert(dir[0] == '/'); - assert(path[0] == '/'); + ASSERT(dir[0] == '/'); + ASSERT(path[0] == '/'); const size_t limit = std::min(dir.length(), path.length()); size_t i = 0; @@ -697,8 +697,8 @@ get_hostname() std::string get_relative_path(string_view dir, string_view path) { - assert(Util::is_absolute_path(dir)); - assert(Util::is_absolute_path(path)); + ASSERT(Util::is_absolute_path(dir)); + ASSERT(Util::is_absolute_path(path)); #ifdef _WIN32 // Paths can be escaped by a slash for use with e.g. -isystem. @@ -741,8 +741,8 @@ get_relative_path(string_view dir, string_view path) std::string get_path_in_cache(string_view cache_dir, uint8_t level, string_view name) { - assert(level >= 1 && level <= 8); - assert(name.length() >= level); + ASSERT(level >= 1 && level <= 8); + ASSERT(name.length() >= level); std::string path(cache_dir); path.reserve(path.size() + level * 2 + 1 + name.length() - level); diff --git a/src/ZstdCompressor.cpp b/src/ZstdCompressor.cpp index c50df840d..8b2c518b9 100644 --- a/src/ZstdCompressor.cpp +++ b/src/ZstdCompressor.cpp @@ -19,6 +19,7 @@ #include "ZstdCompressor.hpp" #include "Logging.hpp" +#include "assertions.hpp" #include "exceptions.hpp" #include @@ -85,7 +86,7 @@ ZstdCompressor::write(const void* data, size_t count) m_zstd_out.size = sizeof(buffer); m_zstd_out.pos = 0; ret = ZSTD_compressStream(m_zstd_stream, &m_zstd_out, &m_zstd_in); - assert(!(ZSTD_isError(ret))); + ASSERT(!(ZSTD_isError(ret))); size_t compressed_bytes = m_zstd_out.pos; if (fwrite(buffer, 1, compressed_bytes, m_stream) != compressed_bytes || ferror(m_stream)) { diff --git a/src/ZstdDecompressor.cpp b/src/ZstdDecompressor.cpp index 75a8b1661..c08d0f90b 100644 --- a/src/ZstdDecompressor.cpp +++ b/src/ZstdDecompressor.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2019 Joel Rosdahl and other contributors +// Copyright (C) 2019-2020 Joel Rosdahl and other contributors // // See doc/AUTHORS.adoc for a complete list of contributors. // @@ -18,6 +18,7 @@ #include "ZstdDecompressor.hpp" +#include "assertions.hpp" #include "exceptions.hpp" ZstdDecompressor::ZstdDecompressor(FILE* stream) @@ -44,7 +45,7 @@ ZstdDecompressor::read(void* data, size_t count) { size_t bytes_read = 0; while (bytes_read < count) { - assert(m_input_size >= m_input_consumed); + ASSERT(m_input_size >= m_input_consumed); if (m_input_size == m_input_consumed) { m_input_size = fread(m_input_buffer, 1, sizeof(m_input_buffer), m_stream); if (m_input_size == 0) { diff --git a/src/argprocessing.cpp b/src/argprocessing.cpp index dfdd94837..4805df3c3 100644 --- a/src/argprocessing.cpp +++ b/src/argprocessing.cpp @@ -21,6 +21,7 @@ #include "Context.hpp" #include "FormatNonstdStringView.hpp" #include "Logging.hpp" +#include "assertions.hpp" #include "compopt.hpp" #include "language.hpp" @@ -95,7 +96,7 @@ detect_pch(Context& ctx, bool is_cc1_option, bool* found_pch) { - assert(found_pch); + ASSERT(found_pch); // Try to be smart about detecting precompiled headers. // If the option is an option for Clang (is_cc1_option), don't accept @@ -923,7 +924,7 @@ handle_dependency_environment_variables(Context& ctx, ProcessArgsResult process_args(Context& ctx) { - assert(!ctx.orig_args.empty()); + ASSERT(!ctx.orig_args.empty()); ArgsInfo& args_info = ctx.args_info; Config& config = ctx.config; diff --git a/src/assertions.cpp b/src/assertions.cpp new file mode 100644 index 000000000..3c5a5633e --- /dev/null +++ b/src/assertions.cpp @@ -0,0 +1,38 @@ +// Copyright (C) 2020 Joel Rosdahl and other contributors +// +// See doc/AUTHORS.adoc for a complete list of contributors. +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 3 of the License, or (at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +// more details. +// +// You should have received a copy of the GNU General Public License along with +// this program; if not, write to the Free Software Foundation, Inc., 51 +// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +#include "assertions.hpp" + +#include "Util.hpp" + +#include "third_party/fmt/core.h" + +void +handle_failed_assertion(const char* file, + size_t line, + const char* function, + const char* condition) +{ + fmt::print(stderr, + "ccache: {}:{}: {}: failed assertion: {}\n", + Util::base_name(file), + line, + function, + condition); + abort(); +} diff --git a/src/assertions.hpp b/src/assertions.hpp new file mode 100644 index 000000000..040c3a5f6 --- /dev/null +++ b/src/assertions.hpp @@ -0,0 +1,50 @@ +// Copyright (C) 2020 Joel Rosdahl and other contributors +// +// See doc/AUTHORS.adoc for a complete list of contributors. +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 3 of the License, or (at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +// more details. +// +// You should have received a copy of the GNU General Public License along with +// this program; if not, write to the Free Software Foundation, Inc., 51 +// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +#pragma once + +#include "system.hpp" + +#ifdef _MSC_VER +# define CCACHE_FUNCTION __func__ +#else +# define CCACHE_FUNCTION __PRETTY_FUNCTION__ +#endif + +// ASSERT is like the standard C `assert` macro but enabled in both debug and +// release builds. +#define ASSERT(condition) \ + do { \ + if (!(condition)) { \ + handle_failed_assertion( \ + __FILE__, __LINE__, CCACHE_FUNCTION, #condition); \ + } \ + } while (false) + +// DEBUG_ASSERT is like the standard C `assert` macro, i.e. only enabled in +// debug builds. +#ifdef NDEBUG +# define DEBUG_ASSERT(condition) ((void)0) +#else +# define DEBUG_ASSERT(condition) ASSERT(condition) +#endif + +[[noreturn]] void handle_failed_assertion(const char* file, + size_t line, + const char* function, + const char* condition); diff --git a/src/ccache.cpp b/src/ccache.cpp index 441ab2fb7..de78cd178 100644 --- a/src/ccache.cpp +++ b/src/ccache.cpp @@ -903,7 +903,7 @@ to_cache(Context& ctx, } if (ctx.config.depend_mode()) { - assert(depend_mode_hash); + ASSERT(depend_mode_hash); auto result_name = result_name_from_depfile(ctx, *depend_mode_hash); if (!result_name) { throw Failure(Statistic::internal_error); @@ -1541,7 +1541,7 @@ calculate_result_name(Context& ctx, // -fprofile-dir=. if (ctx.args_info.profile_generate) { - assert(!ctx.args_info.profile_path.empty()); + ASSERT(!ctx.args_info.profile_path.empty()); log("Adding profile directory {} to our hash", ctx.args_info.profile_path); hash.hash_delimiter("-fprofile-dir"); hash.hash(ctx.args_info.profile_path); @@ -1999,7 +1999,7 @@ cache_compilation(int argc, const char* const* argv) umask(*ctx.original_umask); } - assert(!ctx.orig_args.empty()); + ASSERT(!ctx.orig_args.empty()); ctx.orig_args.erase_with_prefix("--ccache-"); add_prefix(ctx, ctx.orig_args, ctx.config.prefix_command()); @@ -2190,7 +2190,7 @@ do_cache_compilation(Context& ctx, const char* const* argv) // calculate_result_name does not return nullopt if the last (direct_mode) // argument is false. - assert(result_name); + ASSERT(result_name); ctx.set_result_name(*result_name); if (result_name_from_manifest && result_name_from_manifest != result_name) { diff --git a/src/compress.cpp b/src/compress.cpp index bf7816619..1e0982fb4 100644 --- a/src/compress.cpp +++ b/src/compress.cpp @@ -30,6 +30,7 @@ #include "StdMakeUnique.hpp" #include "ThreadPool.hpp" #include "ZstdCompressor.hpp" +#include "assertions.hpp" #include "third_party/fmt/core.h" @@ -129,12 +130,10 @@ create_reader(const CacheFile& cache_file, FILE* stream) stream, Manifest::k_magic, Manifest::k_version); case CacheFile::Type::unknown: - assert(false); // Handled at function entry. - return {}; + ASSERT(false); // Handled at function entry. } - assert(false); - return {}; + ASSERT(false); } std::unique_ptr diff --git a/src/execute.cpp b/src/execute.cpp index 0d628b7fb..211d4ba53 100644 --- a/src/execute.cpp +++ b/src/execute.cpp @@ -255,7 +255,7 @@ find_executable_in_path(const std::string& name, return namebuf; } #else - assert(!exclude_name.empty()); + ASSERT(!exclude_name.empty()); std::string fname = fmt::format("{}/{}", dir, name); auto st1 = Stat::lstat(fname); auto st2 = Stat::stat(fname);