]> git.ipfire.org Git - thirdparty/ccache.git/commitdiff
Add ASSERT and DEBUG_ASSERT macros
authorJoel Rosdahl <joel@rosdahl.net>
Fri, 18 Sep 2020 06:36:08 +0000 (08:36 +0200)
committerJoel Rosdahl <joel@rosdahl.net>
Mon, 21 Sep 2020 18:43:15 +0000 (20:43 +0200)
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.

21 files changed:
src/AtomicFile.cpp
src/CMakeLists.txt
src/Compression.cpp
src/Compressor.cpp
src/Config.cpp
src/Counters.cpp
src/Decompressor.cpp
src/Fd.hpp
src/Result.cpp
src/ResultExtractor.cpp
src/ResultRetriever.cpp
src/SignalHandler.cpp
src/Util.cpp
src/ZstdCompressor.cpp
src/ZstdDecompressor.cpp
src/argprocessing.cpp
src/assertions.cpp [new file with mode: 0644]
src/assertions.hpp [new file with mode: 0644]
src/ccache.cpp
src/compress.cpp
src/execute.cpp

index 8c7d6c7b484c22a9f0294afe2b9828a0d2fe8b0f..d02679b40f5c3585a845999f086280948822fdaa 100644 (file)
@@ -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<uint8_t>& data)
 void
 AtomicFile::commit()
 {
-  assert(m_stream);
+  ASSERT(m_stream);
   int result = fclose(m_stream);
   m_stream = nullptr;
   if (result == EOF) {
index 775472c7b62b3b3fff1d94beb4f194c89653710a..12258870329f340588789ff408681ca5af73b801 100644 (file)
@@ -32,6 +32,7 @@ set(
   ZstdCompressor.cpp
   ZstdDecompressor.cpp
   argprocessing.cpp
+  assertions.cpp
   ccache.cpp
   cleanup.cpp
   compopt.cpp
index abe56ab2c2684d605b04c3c753e86c352766ad3c..aa2a182719545932d0ca12c4e0f7b95fd15e0528 100644 (file)
@@ -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
index 8ccc418c73eedccbb712ba3aff5d21db2906eeb4..efb12573ece2242c70224fc2f772bb92d6c78d34 100644 (file)
@@ -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>
 Compressor::create_from_type(Compression::Type type,
@@ -35,6 +36,5 @@ Compressor::create_from_type(Compression::Type type,
     return std::make_unique<ZstdCompressor>(stream, compression_level);
   }
 
-  assert(false);
-  return {};
+  ASSERT(false);
 }
index b09764280ea8bd0918f4916e6cea90c876404302..bcfa9b960587d66fa0c6c71f9ba3a2e7b7c54065 100644 (file)
@@ -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
index 986aacfabd76f6ece0f01ad88e62c3a3adec1946..2e1b0e282e6da2c59ba9c91627e6a0af9ba505e4 100644 (file)
@@ -19,6 +19,7 @@
 #include "Counters.hpp"
 
 #include "Statistics.hpp"
+#include "assertions.hpp"
 
 #include <algorithm>
 
@@ -30,7 +31,7 @@ uint64_t
 Counters::get(Statistic statistic) const
 {
   const auto index = static_cast<size_t>(statistic);
-  assert(index < static_cast<size_t>(Statistic::END));
+  ASSERT(index < static_cast<size_t>(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<size_t>(statistic);
-  assert(index < static_cast<size_t>(Statistic::END));
+  ASSERT(index < static_cast<size_t>(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];
 }
 
index f41caf64bf460f5cab0baa5b186915df43b1b7df..b53cd952ad37389308b99a7a005853bc4d72fe3e 100644 (file)
@@ -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>
 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<ZstdDecompressor>(stream);
   }
 
-  assert(false);
-  return {};
+  ASSERT(false);
 }
index e9d139c138a8a9086fcb51d89a18d941a1089438..80bc77eae9026976ee16e6aea11ecfb348e7f136 100644 (file)
@@ -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;
 }
 
index 7c1af27f62207bd2fb97d681dd92c6aaebf4778f..979fe50418cfec3f38a4ce3f7d740848ab367f92 100644 (file)
@@ -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);
index fe3ed2393b239dbea4ec0eddade8016852fd0d09..10b8189c82b5c84442d783cce827d660233ecb30 100644 (file)
@@ -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);
index 09090e2ec0c11ac13ca63f398469d9a8f5f94503..dd4374f3864f9cf98fb6d136ccf8ca2a08d243fb 100644 (file)
@@ -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
index 23521dca95821db924f4f0f4ac107c0930f49744..37604c269228a018d26f2f4f6c8701c138ffc334 100644 (file)
@@ -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
index d233480a5b66ca448a41075535ff0d587e08d0a6..7b4d8b7e58bd7ed03b8531b5e78baafec2eaa292 100644 (file)
@@ -132,7 +132,7 @@ template<typename T>
 std::vector<T>
 split_at(string_view input, const char* separators)
 {
-  assert(separators != nullptr && separators[0] != '\0');
+  ASSERT(separators != nullptr && separators[0] != '\0');
 
   std::vector<T> 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);
index c50df840d7fa24eea152b7a05c21401f31ebdbe5..8b2c518b93a8598124e23af8ecbb0bb2076135b1 100644 (file)
@@ -19,6 +19,7 @@
 #include "ZstdCompressor.hpp"
 
 #include "Logging.hpp"
+#include "assertions.hpp"
 #include "exceptions.hpp"
 
 #include <algorithm>
@@ -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)) {
index 75a8b16617f86d0f3b318c07fe0df3c582cb4104..c08d0f90b9aefdd7bb7d822f8feb396b3f6d301e 100644 (file)
@@ -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) {
index dfdd94837ef6d22ca12a1daef70c9af407bd9ff8..4805df3c3a63a325aa4c4e4493a738847056f38f 100644 (file)
@@ -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 (file)
index 0000000..3c5a563
--- /dev/null
@@ -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 (file)
index 0000000..040c3a5
--- /dev/null
@@ -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);
index 441ab2fb7bf10a048842b92ffdc8b7f6eb624f4d..de78cd178a515dc15d474bbfb89a6cf773ef440b 100644 (file)
@@ -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) {
index bf78166195bbb38839b09c9453bea50e3fde19a6..1e0982fb46d4d086dd88a34554a6e77f9c997792 100644 (file)
@@ -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<CacheEntryWriter>
index 0d628b7fb934386491025faef71b3afb5b498c5e..211d4ba53ff605c012c586187dab145ece980dc4 100644 (file)
@@ -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);