Protect Q_UNREACHABLE and Q_ASSUME by Q_ASSERT.

Both Q_UNREACHABLE and Q_ASSUME with an invalid condition can produce
really weird side effects and crashes.

Change-Id: I4d808c705ae98388ef5853e6539b70bd5e5ad34b
Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
Jędrzej Nowacki 2013-01-10 10:05:02 +01:00 committed by The Qt Project
parent 7ff47c7bfa
commit 3b0ed62435
2 changed files with 29 additions and 12 deletions

View File

@ -94,8 +94,8 @@
# define Q_FUNC_INFO __FUNCSIG__
# define Q_ALIGNOF(type) __alignof(type)
# define Q_DECL_ALIGN(n) __declspec(align(n))
# define Q_ASSUME(expr) __assume(expr)
# define Q_UNREACHABLE() __assume(0)
# define Q_ASSUME_IMPL(expr) __assume(expr)
# define Q_UNREACHABLE_IMPL() __assume(0)
# define Q_NORETURN __declspec(noreturn)
# define Q_DECL_DEPRECATED __declspec(deprecated)
# define Q_DECL_EXPORT __declspec(dllexport)
@ -150,18 +150,18 @@
# if defined(__INTEL_COMPILER)
/* Intel C++ also masquerades as GCC */
# define Q_CC_INTEL
# define Q_ASSUME(expr) __assume(expr)
# define Q_UNREACHABLE() __assume(0)
# define Q_ASSUME_IMPL(expr) __assume(expr)
# define Q_UNREACHABLE_IMPL() __assume(0)
# elif defined(__clang__)
/* Clang also masquerades as GCC */
# define Q_CC_CLANG
# define Q_ASSUME(expr) if (expr){} else __builtin_unreachable()
# define Q_UNREACHABLE() __builtin_unreachable()
# define Q_ASSUME_IMPL(expr) if (expr){} else __builtin_unreachable()
# define Q_UNREACHABLE_IMPL() __builtin_unreachable()
# else
/* Plain GCC */
# if (__GNUC__ * 100 + __GNUC_MINOR__) >= 405
# define Q_ASSUME(expr) if (expr){} else __builtin_unreachable()
# define Q_UNREACHABLE() __builtin_unreachable()
# define Q_ASSUME_IMPL(expr) if (expr){} else __builtin_unreachable()
# define Q_UNREACHABLE_IMPL() __builtin_unreachable()
# endif
# endif
@ -789,11 +789,11 @@
#ifndef Q_UNLIKELY
# define Q_UNLIKELY(x) (x)
#endif
#ifndef Q_ASSUME
# define Q_ASSUME(expr) qt_noop()
#ifndef Q_ASSUME_IMPL
# define Q_ASSUME_IMPL(expr) qt_noop()
#endif
#ifndef Q_UNREACHABLE
# define Q_UNREACHABLE() qt_noop()
#ifndef Q_UNREACHABLE_IMPL
# define Q_UNREACHABLE_IMPL() qt_noop()
#endif
#ifndef Q_ALLOC_SIZE
# define Q_ALLOC_SIZE(x)
@ -851,4 +851,17 @@
#define qMove(x) (x)
#endif
#define Q_UNREACHABLE() \
do {\
Q_ASSERT_X(false, "Q_UNREACHABLE()", "Q_UNREACHABLE was reached");\
Q_UNREACHABLE_IMPL();\
} while (0)
#define Q_ASSUME(Expr) \
do {\
const bool valueOfExpression = Expr;\
Q_ASSERT_X(valueOfExpression, "Q_ASSUME()", "Assumption in Q_ASSUME(\"" #Expr "\") was not correct");\
Q_ASSUME_IMPL(valueOfExpression);\
} while (0)
#endif // QCOMPILERDETECTION_H

View File

@ -1829,6 +1829,8 @@ const QSysInfo::WinVersion QSysInfo::WindowsVersion = QSysInfo::windowsVersion()
that the current code execution cannot be reached. That is, Q_ASSUME(false)
is equivalent to Q_UNREACHABLE().
In debug builds the condition is enforced by an assert to facilitate debugging.
\note Q_LIKELY() tells the compiler that the expression is likely, but not
the only possibility. Q_ASSUME tells the compiler that it is the only
possibility.
@ -1863,6 +1865,8 @@ const QSysInfo::WinVersion QSysInfo::WindowsVersion = QSysInfo::windowsVersion()
By using this macro in impossible conditions, code coverage may be improved
as dead code paths may be eliminated.
In debug builds the condition is enforced by an assert to facilitate debugging.
\sa Q_ASSERT(), Q_ASSUME(), qFatal()
*/