Skip to content

Commit

Permalink
Improve UX for unreachable/unimplemented errors (#4094)
Browse files Browse the repository at this point in the history
This should replace several "segfaults" and "illegal instruction" errors
with messages that contain a bit more context. I also put in a link to
the bug tracker to make users' lives a bit easier.

For context, `__builtin_unreachable`'s behavior is undefined and is
intended only as a mechanism to help the compiler see that code will not
return. I do still include it in the new code because if I don't,
compilation produces a lot more warnings as it can't see that
`NOT_IMPLEMENTED_YET` and `UNREACHABLE` cannot return.
  • Loading branch information
copumpkin committed Apr 29, 2020
1 parent a11dc5d commit 7e34925
Show file tree
Hide file tree
Showing 4 changed files with 23 additions and 9 deletions.
5 changes: 5 additions & 0 deletions src/util/debug.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ Revision History:
#include<iostream>
#include "util/str_hashtable.h"
#include "util/z3_exception.h"
#include "util/z3_version.h"

static volatile bool g_enable_assertions = true;

Expand All @@ -39,6 +40,10 @@ void notify_assertion_violation(const char * fileName, int line, const char * co
std::cerr << "File: " << fileName << "\n";
std::cerr << "Line: " << line << "\n";
std::cerr << condition << "\n";
#ifndef Z3DEBUG
std::cerr << Z3_FULL_VERSION << "\n";
std::cerr << "Please file an issue with this message and more detail about how you encountered it at https://github.com/Z3Prover/z3/issues/new\n";
#endif
}

static str_hashtable* g_enabled_debug_tags = nullptr;
Expand Down
25 changes: 16 additions & 9 deletions src/util/debug.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,20 +75,27 @@ bool is_debug_enabled(const char * tag);
#define CASSERT(TAG, COND) DEBUG_CODE(if (assertions_enabled() && is_debug_enabled(TAG) && !(COND)) { notify_assertion_violation(__FILE__, __LINE__, #COND); INVOKE_DEBUGGER(); })
#define XASSERT(COND, EXTRA_CODE) DEBUG_CODE(if (assertions_enabled() && !(COND)) { notify_assertion_violation(__FILE__, __LINE__, #COND); { EXTRA_CODE } INVOKE_DEBUGGER(); })

#ifdef Z3DEBUG
# define UNREACHABLE() DEBUG_CODE(notify_assertion_violation(__FILE__, __LINE__, "UNREACHABLE CODE WAS REACHED."); INVOKE_DEBUGGER();)
#else
/**
We use __builtin_unreachable where possible to suppress control flow compilation warnings, but it should
not be called because its behavior is undefined, so we do need to exit before "calling" it.
*/
#if (defined(__GNUC__) && ((__GNUC__ * 100 + __GNUC_MINOR__) >= 405)) || __has_builtin(__builtin_unreachable)
// only available in gcc >= 4.5 and in newer versions of clang
# define UNREACHABLE() __builtin_unreachable()
#elif defined(_MSC_VER)
# define UNREACHABLE() __assume(0)
# define EXIT_WITH(ERR_CODE) { exit(ERR_CODE); __builtin_unreachable(); } ((void) 0)
#else
#define UNREACHABLE() DEBUG_CODE(notify_assertion_violation(__FILE__, __LINE__, "UNREACHABLE CODE WAS REACHED."); INVOKE_DEBUGGER();)
# define EXIT_WITH(ERR_CODE) { exit(ERR_CODE); } ((void) 0)
#endif

#ifdef Z3DEBUG
# define UNREACHABLE() DEBUG_CODE(notify_assertion_violation(__FILE__, __LINE__, "UNREACHABLE CODE WAS REACHED."); INVOKE_DEBUGGER();)
#else
# define UNREACHABLE() { notify_assertion_violation(__FILE__, __LINE__, "UNREACHABLE CODE WAS REACHED."); EXIT_WITH(ERR_UNREACHABLE); } ((void) 0)
#endif

#define NOT_IMPLEMENTED_YET() { std::cerr << "NOT IMPLEMENTED YET!\n"; UNREACHABLE(); exit(ERR_NOT_IMPLEMENTED_YET); } ((void) 0)
#ifdef Z3DEBUG
# define NOT_IMPLEMENTED_YET() DEBUG_CODE(notify_assertion_violation(__FILE__, __LINE__, "NOT IMPLEMENTED YET!"); INVOKE_DEBUGGER();)
#else
# define NOT_IMPLEMENTED_YET() { notify_assertion_violation(__FILE__, __LINE__, "NOT IMPLEMENTED YET!"); EXIT_WITH(ERR_NOT_IMPLEMENTED_YET); } ((void) 0)
#endif

#define VERIFY(_x_) if (!(_x_)) { \
std::cerr << "Failed to verify: " << #_x_ << "\n"; \
Expand Down
1 change: 1 addition & 0 deletions src/util/error_codes.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ Revision History:
#define ERR_TYPE_CHECK 111
#define ERR_UNKNOWN_RESULT 112
#define ERR_ALLOC_EXCEEDED 113
#define ERR_UNREACHABLE 114

#endif /* ERROR_CODES_H_ */

1 change: 1 addition & 0 deletions src/util/z3_exception.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ char const * z3_error::msg() const {
case ERR_INTERNAL_FATAL: return "internal error";
case ERR_TYPE_CHECK: return "type error";
case ERR_ALLOC_EXCEEDED: return "number of configured allocations exceeded";
case ERR_UNREACHABLE: return "unreachable code was reached";
default: return "unknown error";
}
}
Expand Down

0 comments on commit 7e34925

Please sign in to comment.