summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim King <taking@cs.nyu.edu>2018-02-07 10:19:04 -0800
committerAina Niemetz <aina.niemetz@gmail.com>2018-02-07 10:19:04 -0800
commita5c952d63bca9f94d3886db4d9c09d08d7a23033 (patch)
tree9b3748cf9d7ec36e12df9a5b361862ae6ec0fabb
parent0533b9009d23a39bcc78ef85d6e98b62ef304351 (diff)
Adds a new CHECK macro that abort()s on failure. (#1532)
-rw-r--r--src/base/Makefile.am2
-rw-r--r--src/base/cvc4_check.cpp44
-rw-r--r--src/base/cvc4_check.h144
-rw-r--r--src/theory/bv/aig_bitblaster.cpp6
-rw-r--r--src/util/statistics_registry.cpp33
-rw-r--r--test/unit/Makefile.am1
-rw-r--r--test/unit/util/check_white.h58
7 files changed, 260 insertions, 28 deletions
diff --git a/src/base/Makefile.am b/src/base/Makefile.am
index 5537bbbdd..7dd6f47e5 100644
--- a/src/base/Makefile.am
+++ b/src/base/Makefile.am
@@ -20,6 +20,8 @@ libbase_la_SOURCES = \
configuration_private.h \
cvc4_assert.cpp \
cvc4_assert.h \
+ cvc4_check.cpp \
+ cvc4_check.h \
exception.cpp \
exception.h \
listener.cpp \
diff --git a/src/base/cvc4_check.cpp b/src/base/cvc4_check.cpp
new file mode 100644
index 000000000..5976ac3f7
--- /dev/null
+++ b/src/base/cvc4_check.cpp
@@ -0,0 +1,44 @@
+/********************* */
+/*! \file cvc4_check.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Tim King
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2018 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Assertion utility classes, functions and macros.
+ **
+ ** Implementation of assertion utility classes, functions and macros.
+ **/
+
+#include "base/cvc4_check.h"
+
+#include <cstdlib>
+#include <iostream>
+
+namespace CVC4 {
+
+FatalStream::FatalStream(const char* function, const char* file, int line)
+{
+ stream() << "Fatal failure within " << function << " at " << file << ":"
+ << line << "\n";
+}
+
+FatalStream::~FatalStream()
+{
+ Flush();
+ abort();
+}
+
+std::ostream& FatalStream::stream() { return std::cerr; }
+
+void FatalStream::Flush()
+{
+ stream() << std::endl;
+ stream().flush();
+}
+
+} // namespace CVC4
diff --git a/src/base/cvc4_check.h b/src/base/cvc4_check.h
new file mode 100644
index 000000000..fb4ec0bba
--- /dev/null
+++ b/src/base/cvc4_check.h
@@ -0,0 +1,144 @@
+/********************* */
+/*! \file cvc4_check.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Tim King
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2018 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Assertion utility classes, functions and macros.
+ **
+ ** The CHECK utility classes, functions and macros are related to the Assert()
+ ** macros defined in base/cvc4_assert.h. The major distinguishing attribute
+ ** is the CHECK's abort() the process on failures while Assert() statements
+ ** throw C++ exceptions.
+ **
+ ** The main usage in the file is the CHECK macros. The CHECK macros assert a
+ ** condition and aborts()'s the process if the condition is not satisfied. The
+ ** macro leaves a hanging ostream for the user to specify additional
+ ** information about the failure. Example usage:
+ ** CHECK(x >= 0) << "x must be positive.";
+ **
+ ** DCHECK is a CHECK that is only enabled in debug builds.
+ ** DCHECK(pointer != nullptr);
+ **
+ ** CVC4_FATAL() can be used to indicate unreachable code.
+ **
+ ** The CHECK and DCHECK macros are not safe for use in signal-handling code.
+ ** TODO(taking): Add a signal-handling safe version of CHECK.
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__CHECK_H
+#define __CVC4__CHECK_H
+
+#include <ostream>
+
+// Define CVC4_NO_RETURN macro replacement for [[noreturn]].
+#if defined(SWIG)
+#define CVC4_NO_RETURN
+// SWIG does not yet support [[noreturn]] so emit nothing instead.
+#else
+#define CVC4_NO_RETURN [[noreturn]]
+// Not checking for whether the compiler supports [[noreturn]] using
+// __has_cpp_attribute as GCC 4.8 is too widespread and does not support this.
+// We instead assume this is C++11 (or later) and [[noreturn]] is available.
+#endif // defined(SWIG)
+
+// Define CVC4_PREDICT_FALSE(x) that helps the compiler predict that x will be
+// false (if there is compiler support).
+#ifdef __has_builtin
+#if __has_builtin(__builtin_expect)
+#define CVC4_PREDICT_FALSE(x) (__builtin_expect(x, false))
+#else
+#define CVC4_PREDICT_FALSE(x) x
+#endif
+#else
+#define CVC4_PREDICT_FALSE(x) x
+#endif
+
+namespace CVC4 {
+
+// Implementation notes:
+// To understand FatalStream and OStreamVoider, it is useful to understand
+// how a CHECK is structured. CHECK(cond) is roughly the following pattern:
+// cond ? (void)0 : OstreamVoider() & FatalStream().stream()
+// This is a carefully crafted message to achieve a hanging ostream using
+// operator precedence. The line `CHECK(cond) << foo << bar;` will bind as
+// follows:
+// `cond ? ((void)0) : (OSV() & ((FS().stream() << foo) << bar));`
+// Once the expression is evaluated, the destructor ~FatalStream() of the
+// temporary object is then run, which abort()'s the process. The role of the
+// OStreamVoider() is to match the void type of the true branch.
+
+// Class that provides an ostream and whose destructor aborts! Direct usage of
+// this class is discouraged.
+class FatalStream
+{
+ public:
+ FatalStream(const char* function, const char* file, int line);
+ CVC4_NO_RETURN ~FatalStream();
+
+ std::ostream& stream();
+
+ private:
+ void Flush();
+};
+
+// Helper class that changes the type of an std::ostream& into a void. See
+// "Implementation notes" for more information.
+class OstreamVoider
+{
+ public:
+ OstreamVoider() {}
+ // The operator precedence between operator& and operator<< is critical here.
+ void operator&(std::ostream&) {}
+};
+
+// CVC4_FATAL() always aborts a function and provides a convenient way of
+// formatting error messages. This can be used instead of a return type.
+//
+// Example function that returns a type Foo:
+// Foo bar(T t) {
+// switch(t.type()) {
+// ...
+// default:
+// CVC4_FATAL() << "Unknown T type " << t.enum();
+// }
+// }
+#define CVC4_FATAL() \
+ FatalStream(__PRETTY_FUNCTION__, __FILE__, __LINE__).stream()
+
+// If `cond` is true, log an error message and abort the process.
+// Otherwise, does nothing. This leaves a hanging std::ostream& that can be
+// inserted into.
+#define CVC4_FATAL_IF(cond, function, file, line) \
+ CVC4_PREDICT_FALSE(!(cond)) \
+ ? (void)0 : OstreamVoider() & FatalStream(function, file, line).stream()
+
+// If `cond` is false, log an error message and abort()'s the process.
+// Otherwise, does nothing. This leaves a hanging std::ostream& that can be
+// inserted into using operator<<. Example usages:
+// CHECK(x >= 0);
+// CHECK(x >= 0) << "x must be positive";
+// CHECK(x >= 0) << "expected a positive value. Got " << x << " instead";
+#define CHECK(cond) \
+ CVC4_FATAL_IF(!(cond), __PRETTY_FUNCTION__, __FILE__, __LINE__) \
+ << "Check failure\n\n " << #cond << "\n"
+
+// DCHECK is a variant of CHECK() that is only checked when CVC4_ASSERTIONS is
+// defined. We rely on the optimizer to remove the deadcode.
+#ifdef CVC4_ASSERTIONS
+#define DCHECK(cond) CHECK(cond)
+#else
+#define DCHECK(cond) \
+ CVC4_FATAL_IF(false, __PRETTY_FUNCTION__, __FILE__, __LINE__)
+#endif /* CVC4_DEBUG */
+
+} // namespace CVC4
+
+#endif /* __CVC4__CHECK_H */
diff --git a/src/theory/bv/aig_bitblaster.cpp b/src/theory/bv/aig_bitblaster.cpp
index 5459340f6..010eaf4e5 100644
--- a/src/theory/bv/aig_bitblaster.cpp
+++ b/src/theory/bv/aig_bitblaster.cpp
@@ -15,7 +15,10 @@
**/
#include "bitblaster_template.h"
+
#include "cvc4_private.h"
+
+#include "base/cvc4_check.h"
#include "options/bv_options.h"
#include "prop/cnf_stream.h"
#include "prop/sat_solver_factory.h"
@@ -155,8 +158,7 @@ AigBitblaster::AigBitblaster()
d_satSolver = prop::SatSolverFactory::createCryptoMinisat(smtStatisticsRegistry(),
"AigBitblaster");
break;
- default:
- Unreachable("Unknown SAT solver type");
+ default: CVC4_FATAL() << "Unknown SAT solver type";
}
}
diff --git a/src/util/statistics_registry.cpp b/src/util/statistics_registry.cpp
index 38113c512..2dd1eddd7 100644
--- a/src/util/statistics_registry.cpp
+++ b/src/util/statistics_registry.cpp
@@ -21,6 +21,7 @@
#include <iostream>
#include "base/cvc4_assert.h"
+#include "base/cvc4_check.h"
#include "lib/clock_gettime.h"
#include "util/ostream_util.h"
@@ -76,7 +77,7 @@ inline timespec& operator-=(timespec& a, const timespec& b) {
nsec -= nsec_per_sec;
++a.tv_sec;
}
- Assert(nsec >= 0 && nsec < nsec_per_sec);
+ DCHECK(nsec >= 0 && nsec < nsec_per_sec);
a.tv_nsec = nsec;
return a;
}
@@ -167,22 +168,11 @@ void StatisticsRegistry::registerStat(Stat* s)
void StatisticsRegistry::unregisterStat(Stat* s)
{
#ifdef CVC4_STATISTICS_ON
- try
- {
- PrettyCheckArgument(d_stats.find(s) != d_stats.end(),
- s,
- "Statistic `%s' was not registered with this registry.",
- s->getName().c_str());
- }
- catch (Exception& e)
- {
- std::cerr << "Failure in StatisticsRegistry::unregisterStat():" << e.what()
- << std::endl;
- abort();
- }
- d_stats.erase(s);
+ CHECK(s != nullptr);
+ CHECK(d_stats.erase(s) > 0) << "Statistic `" << s->getName()
+ << "' was not registered with this registry.";
#endif /* CVC4_STATISTICS_ON */
-}/* StatisticsRegistry::unregisterStat_() */
+} /* StatisticsRegistry::unregisterStat() */
void StatisticsRegistry::flushStat(std::ostream &out) const {
#ifdef CVC4_STATISTICS_ON
@@ -212,16 +202,7 @@ void TimerStat::start() {
void TimerStat::stop() {
if(__CVC4_USE_STATISTICS) {
- try
- {
- PrettyCheckArgument(d_running, *this, "timer not running");
- }
- catch (Exception& e)
- {
- std::cerr << "Fatal failure in TimerStat::stop(): " << e.what()
- << std::endl;
- abort();
- }
+ CHECK(d_running) << "timer not running";
::timespec end;
clock_gettime(CLOCK_MONOTONIC, &end);
d_data += end - d_start;
diff --git a/test/unit/Makefile.am b/test/unit/Makefile.am
index 9f61ef031..167100ff0 100644
--- a/test/unit/Makefile.am
+++ b/test/unit/Makefile.am
@@ -41,6 +41,7 @@ UNIT_TESTS += \
context/cdvector_black \
util/array_store_all_black \
util/assert_white \
+ util/check_white \
util/binary_heap_black \
util/bitvector_black \
util/datatype_black \
diff --git a/test/unit/util/check_white.h b/test/unit/util/check_white.h
new file mode 100644
index 000000000..e57afa6c7
--- /dev/null
+++ b/test/unit/util/check_white.h
@@ -0,0 +1,58 @@
+/********************* */
+/*! \file check_white.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Tim King
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief White box testing of check utilities.
+ **
+ ** White box testing of check utilities.
+ **/
+
+#include <cxxtest/TestSuite.h>
+
+#include <cstring>
+#include <string>
+
+#include "base/cvc4_check.h"
+
+using namespace std;
+using namespace CVC4;
+
+namespace {
+
+class CheckWhite : public CxxTest::TestSuite
+{
+ public:
+ const int kOne = 1;
+
+ // This test just checks that this statement compiles.
+ std::string TerminalCvc4Fatal() const
+ {
+ CVC4_FATAL() << "This is a test that confirms that CVC4_FATAL can be a "
+ "terminal statement in a function that has a non-void "
+ "return type.";
+ }
+
+ void testCheck() { CHECK(kOne >= 0) << kOne << " must be positive"; }
+ void testDCheck()
+ {
+ DCHECK(kOne == 1) << "always passes";
+#ifndef CVC4_ASSERTIONS
+ DCHECK(false) << "Will not be compiled in when CVC4_ASSERTIONS off.";
+#endif /* CVC4_ASSERTIONS */
+ }
+
+ void testPointerTypeCanBeTheCondition()
+ {
+ const int* one_pointer = &kOne;
+ CHECK(one_pointer);
+ }
+};
+
+} // namespace
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback