Index: base/logging.h |
diff --git a/base/logging.h b/base/logging.h |
index 1dcb0f71f12ed6b9854524161e7555ea3ac609e1..f9ff4dbd7cfc4c20905d7a71b3d8efba195a3468 100644 |
--- a/base/logging.h |
+++ b/base/logging.h |
@@ -289,6 +289,30 @@ typedef bool (*LogMessageHandlerFunction)(int severity, |
BASE_EXPORT void SetLogMessageHandler(LogMessageHandlerFunction handler); |
BASE_EXPORT LogMessageHandlerFunction GetLogMessageHandler(); |
+// The ANALYZER_ASSUME_TRUE(bool arg) macro adds compiler-specific hints |
+// to Clang which control what code paths are statically analyzed, |
+// and is meant to be used in conjunction with assert & assert-like functions. |
+// The expression is passed straight through if analysis isn't enabled. |
+#if defined(__clang_analyzer__) |
+ |
+inline constexpr bool AnalyzerNoReturn() __attribute__((analyzer_noreturn)) { |
+ return false; |
+} |
+ |
+inline constexpr bool AnalyzerAssumeTrue(bool arg) { |
+ // AnalyzerNoReturn() is invoked and analysis is terminated if |arg| is |
+ // false. |
+ return arg || AnalyzerNoReturn(); |
+} |
+ |
+#define ANALYZER_ASSUME_TRUE(arg) ::logging::AnalyzerAssumeTrue(!!(arg)) |
+ |
+#else // !defined(__clang_analyzer__) |
+ |
+#define ANALYZER_ASSUME_TRUE(arg) (arg) |
+ |
+#endif // defined(__clang_analyzer__) |
+ |
typedef int LogSeverity; |
const LogSeverity LOG_VERBOSE = -1; // This is level 1 verbosity |
// Note: the log severities are used to index into the array of names, |
@@ -408,8 +432,9 @@ const LogSeverity LOG_0 = LOG_ERROR; |
// TODO(akalin): Add more VLOG variants, e.g. VPLOG. |
-#define LOG_ASSERT(condition) \ |
- LOG_IF(FATAL, !(condition)) << "Assert failed: " #condition ". " |
+#define LOG_ASSERT(condition) \ |
+ LOG_IF(FATAL, !(ANALYZER_ASSUME_TRUE(condition))) \ |
+ << "Assert failed: " #condition ". " |
#if defined(OS_WIN) |
#define PLOG_STREAM(severity) \ |
@@ -585,10 +610,10 @@ class CheckOpResult { |
// Do as much work as possible out of line to reduce inline code size. |
#define CHECK(condition) \ |
LAZY_STREAM(::logging::LogMessage(__FILE__, __LINE__, #condition).stream(), \ |
- !(condition)) |
+ !ANALYZER_ASSUME_TRUE(condition)) |
-#define PCHECK(condition) \ |
- LAZY_STREAM(PLOG_STREAM(FATAL), !(condition)) \ |
+#define PCHECK(condition) \ |
+ LAZY_STREAM(PLOG_STREAM(FATAL), !ANALYZER_ASSUME_TRUE(condition)) \ |
<< "Check failed: " #condition ". " |
#endif // _PREFAST_ |
@@ -685,17 +710,21 @@ std::string* MakeCheckOpString<std::string, std::string>( |
// The (int, int) specialization works around the issue that the compiler |
// will not instantiate the template version of the function on values of |
// unnamed enum type - see comment below. |
+// |
+// The checked condition is wrapped with ANALYZER_ASSUME_TRUE, which under |
+// static analysis builds, blocks analysis of the current path if the |
+// condition is false. |
#define DEFINE_CHECK_OP_IMPL(name, op) \ |
template <class t1, class t2> \ |
inline std::string* Check##name##Impl(const t1& v1, const t2& v2, \ |
const char* names) { \ |
- if (v1 op v2) \ |
+ if (ANALYZER_ASSUME_TRUE(v1 op v2)) \ |
return NULL; \ |
else \ |
return ::logging::MakeCheckOpString(v1, v2, names); \ |
} \ |
inline std::string* Check##name##Impl(int v1, int v2, const char* names) { \ |
- if (v1 op v2) \ |
+ if (ANALYZER_ASSUME_TRUE(v1 op v2)) \ |
return NULL; \ |
else \ |
return ::logging::MakeCheckOpString(v1, v2, names); \ |
@@ -798,35 +827,15 @@ const LogSeverity LOG_DCHECK = LOG_INFO; |
LAZY_STREAM(PLOG_STREAM(DCHECK), false) \ |
<< "Check failed: " #condition ". " |
-#elif defined(__clang_analyzer__) |
- |
-// Keeps the static analyzer from proceeding along the current codepath, |
-// otherwise false positive errors may be generated by null pointer checks. |
-inline constexpr bool AnalyzerNoReturn() __attribute__((analyzer_noreturn)) { |
- return false; |
-} |
- |
-#define DCHECK(condition) \ |
- LAZY_STREAM( \ |
- LOG_STREAM(DCHECK), \ |
- DCHECK_IS_ON() ? (logging::AnalyzerNoReturn() || !(condition)) : false) \ |
- << "Check failed: " #condition ". " |
- |
-#define DPCHECK(condition) \ |
- LAZY_STREAM( \ |
- PLOG_STREAM(DCHECK), \ |
- DCHECK_IS_ON() ? (logging::AnalyzerNoReturn() || !(condition)) : false) \ |
- << "Check failed: " #condition ". " |
- |
-#else |
+#else // !(defined(_PREFAST_) && defined(OS_WIN)) |
#if DCHECK_IS_ON() |
-#define DCHECK(condition) \ |
- LAZY_STREAM(LOG_STREAM(DCHECK), !(condition)) \ |
+#define DCHECK(condition) \ |
+ LAZY_STREAM(LOG_STREAM(DCHECK), !ANALYZER_ASSUME_TRUE(condition)) \ |
<< "Check failed: " #condition ". " |
-#define DPCHECK(condition) \ |
- LAZY_STREAM(PLOG_STREAM(DCHECK), !(condition)) \ |
+#define DPCHECK(condition) \ |
+ LAZY_STREAM(PLOG_STREAM(DCHECK), !ANALYZER_ASSUME_TRUE(condition)) \ |
<< "Check failed: " #condition ". " |
#else // DCHECK_IS_ON() |
@@ -836,7 +845,7 @@ inline constexpr bool AnalyzerNoReturn() __attribute__((analyzer_noreturn)) { |
#endif // DCHECK_IS_ON() |
-#endif |
+#endif // defined(_PREFAST_) && defined(OS_WIN) |
// Helper macro for binary operators. |
// Don't use this macro directly in your code, use DCHECK_EQ et al below. |