Add __analysis_assume support to CHECK macros to reduce warnings with /analyze.
Due to bugs and quirks in the analysis engine this is a very delicate dance.
The __analysis_assume invocation has to evaluate !!(condition) instead
of just condition because otherwise it fails on overloaded operators
such as with smart pointers. See this post for details:
http://randomascii.wordpress.com/2011/09/13/analyze-for-visual-studio-the-ugly-part-5/
The evaluation of condition in the 'regular' part of the macro has to
be removed during the /analyze phase in order to avoid confusing the
analysis engine which thinks that branching on the condition implies
uncertainty about the condition.
None of this is documented -- thinking like a compiler is required.
Wrapping this with #ifdef _PREFAST_ makes it easy to guarantee that this
will not affect regular builds.
To build add win_debug_extra_cflags="/analyze" to GYP_DEFINES, rebuild
the project files and then build.
Review URL: https://codereview.chromium.org/674643002
Cr-Commit-Position: refs/heads/master@{#300937}
CrOS-Libchrome-Original-Commit: 9d1602515adc3e797d71c3a0e29cc175432eb8fe
diff --git a/base/logging.h b/base/logging.h
index 88d5eff..54ff579 100644
--- a/base/logging.h
+++ b/base/logging.h
@@ -450,14 +450,36 @@
#else
+#if defined(_PREFAST_) && defined(OS_WIN)
+// Use __analysis_assume to tell the VC++ static analysis engine that
+// assert conditions are true, to suppress warnings. The LAZY_STREAM
+// parameter doesn't reference 'condition' in /analyze builds because
+// this evaluation confuses /analyze. The !! before condition is because
+// __analysis_assume gets confused on some conditions:
+// http://randomascii.wordpress.com/2011/09/13/analyze-for-visual-studio-the-ugly-part-5/
+
+#define CHECK(condition) \
+ __analysis_assume(!!(condition)), \
+ LAZY_STREAM(LOG_STREAM(FATAL), false) \
+ << "Check failed: " #condition ". "
+
+#define PCHECK(condition) \
+ __analysis_assume(!!(condition)), \
+ LAZY_STREAM(PLOG_STREAM(FATAL), false) \
+ << "Check failed: " #condition ". "
+
+#else // _PREFAST_
+
#define CHECK(condition) \
LAZY_STREAM(LOG_STREAM(FATAL), !(condition)) \
<< "Check failed: " #condition ". "
-#define PCHECK(condition) \
+#define PCHECK(condition) \
LAZY_STREAM(PLOG_STREAM(FATAL), !(condition)) \
<< "Check failed: " #condition ". "
+#endif // _PREFAST_
+
// Helper macro for binary operators.
// Don't use this macro directly in your code, use CHECK_EQ et al below.
//
@@ -616,6 +638,21 @@
// variable warnings if the only use of a variable is in a DCHECK.
// This behavior is different from DLOG_IF et al.
+#if defined(_PREFAST_) && defined(OS_WIN)
+// See comments on the previous use of __analysis_assume.
+
+#define DCHECK(condition) \
+ __analysis_assume(!!(condition)), \
+ LAZY_STREAM(LOG_STREAM(DCHECK), false) \
+ << "Check failed: " #condition ". "
+
+#define DPCHECK(condition) \
+ __analysis_assume(!!(condition)), \
+ LAZY_STREAM(PLOG_STREAM(DCHECK), false) \
+ << "Check failed: " #condition ". "
+
+#else // _PREFAST_
+
#define DCHECK(condition) \
LAZY_STREAM(LOG_STREAM(DCHECK), DCHECK_IS_ON ? !(condition) : false) \
<< "Check failed: " #condition ". "
@@ -624,6 +661,8 @@
LAZY_STREAM(PLOG_STREAM(DCHECK), DCHECK_IS_ON ? !(condition) : false) \
<< "Check failed: " #condition ". "
+#endif // _PREFAST_
+
// Helper macro for binary operators.
// Don't use this macro directly in your code, use DCHECK_EQ et al below.
#define DCHECK_OP(name, op, val1, val2) \