Re: [PATCH] D24507: Add attribute for return values that shouldn't be cast to bool

2016-09-19 Thread Anton Urusov via cfe-commits
urusant updated this revision to Diff 71807.
urusant added a comment.

Made some changes based on the comments. Please refer to the replies below.


Repository:
  rL LLVM

https://reviews.llvm.org/D24507

Files:
  include/clang/Basic/Attr.td
  include/clang/Basic/AttrDocs.td
  include/clang/Basic/DiagnosticSemaKinds.td
  include/clang/StaticAnalyzer/Checkers/Checkers.td
  lib/Sema/SemaChecking.cpp
  lib/Sema/SemaDeclAttr.cpp
  lib/StaticAnalyzer/Checkers/CMakeLists.txt
  lib/StaticAnalyzer/Checkers/ReturnNonBoolChecker.cpp
  test/ReturnNonBoolTest.c
  test/ReturnNonBoolTest.cpp
  test/ReturnNonBoolTestCompileTime.cpp

Index: test/ReturnNonBoolTestCompileTime.cpp
===
--- /dev/null
+++ test/ReturnNonBoolTestCompileTime.cpp
@@ -0,0 +1,37 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -Wbool-conversion -verify %s
+#ifdef __clang__
+#define RETURNS_NON_BOOL __attribute__((warn_impcast_to_bool))
+#else
+#define RETURNS_NON_BOOL
+#endif
+
+int NoAttributes() { return 2; }
+
+int NonBool(int x) RETURNS_NON_BOOL;
+int NonBool(int x) {  // expected-note{{'NonBool' declared here}}
+  return x * 2;
+}
+
+int good(int x) { return x * 2; }
+
+void test1() {
+  if (NonBool(2)) {  // expected-warning{{implicit conversion turns non-bool into bool: 'int' to 'bool'}}
+return;
+  }
+}
+
+void test3() {
+  if ((bool)NonBool(2)) {  // no warning, explicit cast
+return;
+  }
+}
+
+void test5() {
+  if (good(2)) {  // no warning, return value isn't marked as dangerous
+return;
+  }
+}
+
+double InvalidReturnType() RETURNS_NON_BOOL;  // expected-warning{{'warn_impcast_to_bool' attribute only applies to integer return types}}
+
+int AttributeWithArguments() __attribute__((warn_impcast_to_bool(2)));  // expected-error {{'warn_impcast_to_bool' attribute takes no arguments}}
Index: test/ReturnNonBoolTest.cpp
===
--- /dev/null
+++ test/ReturnNonBoolTest.cpp
@@ -0,0 +1,87 @@
+// RUN: %clang_cc1 -std=c++11 -analyze -analyzer-checker=alpha.core.ReturnNonBool -Wno-bool-conversion -verify %s
+#ifdef __clang__
+#define RETURNS_NON_BOOL __attribute__((warn_impcast_to_bool))
+#else
+#define RETURNS_NON_BOOL
+#endif
+
+int NoAttributes() { return 2; }
+
+int NonBool(int x) RETURNS_NON_BOOL;
+
+int good(int x);
+
+int wrap(int x) {
+  int r = NonBool(x);
+  return r;
+}
+
+void test1() {
+  if (NonBool(1)) {  // expected-warning{{implicit cast to bool is dangerous for this value}}
+return;
+  }
+}
+
+void test2() {
+  if (wrap(2)) {  // expected-warning{{implicit cast to bool is dangerous for this value}}
+return;
+  }
+}
+
+void test3() {
+  if ((bool)NonBool(3)) {  // no warning, explicit cast
+return;
+  }
+}
+
+void test4(int x) {
+  if (bool(wrap(2 * x))) {  // no warning, explicit cast
+return;
+  }
+}
+
+void test5() {
+  if (good(5)) {  // no warning, return value isn't marked as dangerous
+return;
+  }
+}
+
+void test6() {
+  if (good(wrap(2))) {  // no warning, wrap is treated as int, not as bool
+return;
+  }
+}
+
+double InvalidAttributeUsage()
+RETURNS_NON_BOOL;  // expected-warning{{'warn_impcast_to_bool' attribute only applies to integer return types}}
+
+void test_function_pointer(void (*f)()) {
+  // This is to test the case when Call.getDecl() returns NULL, because f()
+  // doesn't have a declaration
+  f();
+}
+
+bool universal_bool_wrapper(int (*f)(int), int x) {
+  // When we call universal_bool_wrapper from test_universal_bool_wrapper, the
+  // analyzer follows the path and detects that in this line we are doing
+  // something wrong (assuming that f is actually NonBool). So if we didn't call
+  // universal_bool_wrapper with any dangerous function, there would be no
+  // warning.
+  return f(x);  // expected-warning {{implicit cast to bool is dangerous for this value}}
+}
+
+int universal_int_wrapper(int (*f)(int), int x) { return f(x); }
+
+void test_universal_bool_wrapper(int x) {
+  if (universal_bool_wrapper(NonBool, x)) return;
+}
+
+void test_universal_int_wrapper(int x) {
+  if (universal_int_wrapper(NonBool, x))  // expected-warning{{implicit cast to bool is dangerous for this value}}
+return;
+}
+
+void test_lambdas(int x) {
+  if ([](int a) __attribute__((warn_impcast_to_bool))-> int{ return a; }(x)) { // expected-warning{{implicit cast to bool is dangerous for this value}}
+  }
+}
Index: test/ReturnNonBoolTest.c
===
--- /dev/null
+++ test/ReturnNonBoolTest.c
@@ -0,0 +1,79 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.core.ReturnNonBool -Wno-bool-conversion -verify %s
+
+/// C is checked slightly differently than C++, in particular, C doesn't have
+/// implicit casts to bool, so we need to test different branching situations,
+/// like if, for, while, etc.
+
+#ifdef __clang__
+#define RETURNS_NON_BOOL __attribute__((warn_impcast_to_bool))
+#else
+#define RETURNS_NON_B

Re: [PATCH] D24507: Add attribute for return values that shouldn't be cast to bool

2016-09-19 Thread Anton Urusov via cfe-commits
urusant added a comment.

Thank you for the feedback.

> The patch is missing Sema tests for the attribute (that it only applies to 
> declarations you expect, accepts no args, etc).


There is one test case for that in test/ReturnNonBoolTestCompileTime.cpp. I've 
added another one for attribute accepting no args, so now the last two test 
cases in this file are those you were asking about. Can you think of any other 
cases of invalid attribute usage?

> Have you considered making this a type attribute on the return type of the 
> function rather than a declaration attribute on the function declaration?


No, I hadn't. On a quick look though, I couldn't find a way to simplify my 
solution using this idea, because as far as I understand, the type attribute 
isn't inherited, so, for example, if I have something like `int r = 
X509_verify_cert(...)` and the function `X509_verify_cert` has a return type 
with attribute, `r` won't have the attribute. If that is correct, we still need 
to backtrace the value to the function declaration. Is there something I am 
missing?



Comment at: include/clang/Basic/Attr.td:1138
@@ +1137,3 @@
+def WarnImpcastToBool : InheritableAttr {
+  let Spellings = [GCC<"warn_impcast_to_bool">];
+  let Subjects = SubjectList<[ObjCMethod, Function], WarnDiag,

aaron.ballman wrote:
> This should not use a GCC spelling because it's not an attribute that GCC 
> supports. You should probably use GNU instead, since I suspect this attribute 
> will be useful in C as well as C++.
Yeah, makes sense.


Comment at: include/clang/Basic/Attr.td:1140
@@ +1139,3 @@
+  let Subjects = SubjectList<[ObjCMethod, Function], WarnDiag,
+ "ExpectedFunctionOrMethod">;
+  let Documentation = [WarnImpcastToBoolDocs];

aaron.ballman wrote:
> No need to specify the WarnDiag or ExpectedFunctionOrMethod arguments; they 
> will be handled automatically.
I didn't know that, thanks.


Comment at: include/clang/Basic/AttrDocs.td:2055
@@ -2054,1 +2054,3 @@
 }
+def WarnImpcastToBoolDocs : Documentation {
+  let Category = DocCatFunction;

zaks.anna wrote:
> You probably need to "propose" the attribute to the clang community. I'd send 
> an email to the cfe-dev as it might not have enough attention if it's just 
> the patch.  
OK, will do.


Comment at: include/clang/Basic/AttrDocs.td:2058
@@ +2057,3 @@
+  let Content = [{
+The ``warn_impcast_to_bool`` attribute is used to indicate that the return 
value of a function with integral return type cannot be used as a boolean 
value. For example, if a function returns -1 if it couldn't efficiently read 
the data, 0 if the data is invalid and 1 for success, it might be dangerous to 
implicitly cast the return value to bool, e.g. to indicate success. Therefore, 
it is a good idea to trigger a warning about such cases. However, in case a 
programmer uses an explicit cast to bool, that probably means that he knows 
what he is doing, therefore a warning should be triggered only for implicit 
casts.
+

aaron.ballman wrote:
> You should manually wrap this to roughly the 80 col limit.
> 
> Instead of "he", can you use "they" please?
OK, I did that. However, 80 col limit in this case feels a bit inconsistent 
with the rest of the file to me because most of other similar descriptions 
don't follow it.


Comment at: include/clang/Basic/DiagnosticGroups.td:57
@@ -56,2 +56,3 @@
 def DoublePromotion : DiagGroup<"double-promotion">;
+def UnsafeBoolConversion : DiagGroup<"unsafe-bool-conversion">;
 def EnumTooLarge : DiagGroup<"enum-too-large">;

aaron.ballman wrote:
> I'm not certain this requires its own diagnostic group. This can probably be 
> handled under `BoolConversion`
OK.


Comment at: include/clang/Basic/DiagnosticSemaKinds.td:2259
@@ +2258,3 @@
+def warn_attribute_return_int_only : Warning<
+  "%0 attribute only applies to return values that are integers">,
+  InGroup;

aaron.ballman wrote:
> How about: ...only applies to integer return types?
Yeah, that sounds better.


Comment at: include/clang/Basic/DiagnosticSemaKinds.td:2883
@@ +2882,3 @@
+  "implicit conversion turns non-bool into bool: %0 to %1">,
+  InGroup, DefaultIgnore;
+

aaron.ballman wrote:
> I don't think this should be a DefaultIgnore diagnostic -- if the user wrote 
> the attribute, they should get the diagnostic when appropriate.
Makes sense.


Comment at: lib/Sema/SemaChecking.cpp:8262
@@ +8261,3 @@
+/// e.g. (x ? f : g)(y)
+if (isa(E)) {
+  FunctionDecl* fn = cast(E)->getDirectCallee();

aaron.ballman wrote:
> Should use `if (const auto *CE = dyn_cast(E)) {`
Done.


Comment at: lib/Sema/SemaChecking.cpp:8263-8264
@@ +8262,4 @@
+if (isa(E)) {
+  FunctionDecl* fn = cast(E)->getDirectCallee();
+  

Re: [PATCH] D24507: Add attribute for return values that shouldn't be cast to bool

2016-09-20 Thread Anton Urusov via cfe-commits
urusant updated this revision to Diff 71921.
urusant added a comment.

In https://reviews.llvm.org/D24507#546380, @aaron.ballman wrote:

> We try to keep our tests segregated by functionality. e.g., tests relating to 
> the way the attribute is handled (what it appertains to, args, etc) should 
> live in Sema, tests relating to the static analyzer behavior should live in 
> test/Analysis, etc.
>
> Tests that are still missing are: applying to a non-function type, applying 
> to a member function, applying to an Obj-C method. For member functions, what 
> should happen if the function is virtual? What if the overriders do not 
> specify the attribute? What if an override specifies the attribute but the 
> base does not?


I have added the test cases about member functions.
As for ObjC methods, I didn't pay much attention to them while developing the 
check as ObjC wasn't the primary target. I tried to make a test case for it, 
and it turned out that it is OK to put an attribute on ObjC method, but you 
wouldn't get neither compiler warning nor StaticAnalyzer report. That is why I 
removed ObjC methods from the attribute subjects and replaced the ObjC test 
case with another one that shows that you cannot apply the attribute to ObjC 
methods (not sure if it is still necessary, because it seems not very different 
from applying the attribute to a non-function variable - in both cases we get 
the same warning). Do you think it's worth digging into how to make it work 
with ObjC? In this case I might need some help because I don't really speak 
Objective C.

> > > Have you considered making this a type attribute on the return type of 
> > > the function rather than a declaration attribute on the function 
> > > declaration?

> 

> > 

> 

> > 

> 

> > No, I hadn't. On a quick look though, I couldn't find a way to simplify my 
> > solution using this idea, because as far as I understand, the type 
> > attribute isn't inherited, so, for example, if I have something like `int r 
> > = X509_verify_cert(...)` and the function `X509_verify_cert` has a return 
> > type with attribute, `r` won't have the attribute. If that is correct, we 
> > still need to backtrace the value to the function declaration. Is there 
> > something I am missing?

> 

> 

> I was thinking it would be diagnosed if you attempted to assign from your 
> attributed type to a type that is not compatible. However, that may still be 
> problematic because it raises other questions (can you SFINAE on it? 
> Overload? etc).


This might also make the check itself easier (as we don't need path-sensitive 
analysis), however, it would make the use more complicated as all the users of 
the dangerous function would have to change their code (even if they are using 
it correctly). For example, if we refer to the original motivation, annotating 
dangerous OpenSSL functions would allow us to protect dozens of codebases using 
them without changing every one of them.


Repository:
  rL LLVM

https://reviews.llvm.org/D24507

Files:
  include/clang/Basic/Attr.td
  include/clang/Basic/AttrDocs.td
  include/clang/Basic/DiagnosticSemaKinds.td
  include/clang/StaticAnalyzer/Checkers/Checkers.td
  lib/Sema/SemaChecking.cpp
  lib/Sema/SemaDeclAttr.cpp
  lib/StaticAnalyzer/Checkers/CMakeLists.txt
  lib/StaticAnalyzer/Checkers/ReturnNonBoolChecker.cpp
  test/Analysis/ReturnNonBoolTest.c
  test/Analysis/ReturnNonBoolTest.cpp
  test/SemaCXX/ReturnNonBoolTestCompileTime.cpp
  test/SemaObjC/ReturnNonBoolTestCompileTime.m

Index: test/SemaObjC/ReturnNonBoolTestCompileTime.m
===
--- /dev/null
+++ test/SemaObjC/ReturnNonBoolTestCompileTime.m
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1  -fsyntax-only -verify %s
+
+@interface INTF
+- (int) fee __attribute__((warn_impcast_to_bool)); // expected-warning{{'warn_impcast_to_bool' attribute only applies to functions}}
++ (int) c __attribute__((warn_impcast_to_bool)); // expected-warning{{'warn_impcast_to_bool' attribute only applies to functions}}
+@end
Index: test/SemaCXX/ReturnNonBoolTestCompileTime.cpp
===
--- /dev/null
+++ test/SemaCXX/ReturnNonBoolTestCompileTime.cpp
@@ -0,0 +1,70 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -Wbool-conversion -verify %s
+#ifdef __clang__
+#define RETURNS_NON_BOOL __attribute__((warn_impcast_to_bool))
+#else
+#define RETURNS_NON_BOOL
+#endif
+
+int NoAttributes() { return 2; }
+
+int NonBool(int x) RETURNS_NON_BOOL;
+int NonBool(int x) {  // expected-note{{'NonBool' declared here}}
+  return x * 2;
+}
+
+int good(int x) { return x * 2; }
+
+void test1() {
+  if (NonBool(2)) {  // expected-warning{{implicit conversion turns non-bool into bool: 'int' to 'bool'}}
+return;
+  }
+}
+
+void test3() {
+  if ((bool)NonBool(2)) {  // no warning, explicit cast
+return;
+  }
+}
+
+void test5() {
+  if (good(2)) {  // no warning, return value isn't marked as dangerous
+retur

Re: [PATCH] D24507: Add attribute for return values that shouldn't be cast to bool

2016-09-20 Thread Anton Urusov via cfe-commits
urusant updated this revision to Diff 71927.

Repository:
  rL LLVM

https://reviews.llvm.org/D24507

Files:
  include/clang/Basic/Attr.td
  include/clang/Basic/AttrDocs.td
  include/clang/Basic/DiagnosticSemaKinds.td
  include/clang/StaticAnalyzer/Checkers/Checkers.td
  lib/Sema/SemaChecking.cpp
  lib/Sema/SemaDeclAttr.cpp
  lib/StaticAnalyzer/Checkers/CMakeLists.txt
  lib/StaticAnalyzer/Checkers/ReturnNonBoolChecker.cpp
  test/Analysis/ReturnNonBoolTest.c
  test/Analysis/ReturnNonBoolTest.cpp
  test/SemaCXX/ReturnNonBoolTestCompileTime.cpp
  test/SemaObjC/ReturnNonBoolTestCompileTime.m

Index: test/SemaObjC/ReturnNonBoolTestCompileTime.m
===
--- /dev/null
+++ test/SemaObjC/ReturnNonBoolTestCompileTime.m
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1  -fsyntax-only -verify %s
+
+@interface INTF
+- (int) fee __attribute__((warn_impcast_to_bool)); // expected-warning{{'warn_impcast_to_bool' attribute only applies to functions}}
++ (int) c __attribute__((warn_impcast_to_bool)); // expected-warning{{'warn_impcast_to_bool' attribute only applies to functions}}
+@end
Index: test/SemaCXX/ReturnNonBoolTestCompileTime.cpp
===
--- /dev/null
+++ test/SemaCXX/ReturnNonBoolTestCompileTime.cpp
@@ -0,0 +1,70 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -Wbool-conversion -verify %s
+#ifdef __clang__
+#define RETURNS_NON_BOOL __attribute__((warn_impcast_to_bool))
+#else
+#define RETURNS_NON_BOOL
+#endif
+
+int NoAttributes() { return 2; }
+
+int NonBool(int x) RETURNS_NON_BOOL;
+int NonBool(int x) {  // expected-note{{'NonBool' declared here}}
+  return x * 2;
+}
+
+int good(int x) { return x * 2; }
+
+void test1() {
+  if (NonBool(2)) {  // expected-warning{{implicit conversion turns non-bool into bool: 'int' to 'bool'}}
+return;
+  }
+}
+
+void test3() {
+  if ((bool)NonBool(2)) {  // no warning, explicit cast
+return;
+  }
+}
+
+void test5() {
+  if (good(2)) {  // no warning, return value isn't marked as dangerous
+return;
+  }
+}
+
+double InvalidReturnType() RETURNS_NON_BOOL;  // expected-warning{{'warn_impcast_to_bool' attribute only applies to integer return types}}
+
+int AttributeWithArguments() __attribute__((warn_impcast_to_bool(2)));  // expected-error {{'warn_impcast_to_bool' attribute takes no arguments}}
+
+int NonFunction RETURNS_NON_BOOL; // expected-warning{{'warn_impcast_to_bool' attribute only applies to functions}}
+
+class Base {
+  int data;
+ public:
+  virtual int SafeMember();
+  virtual int NonBoolMember() RETURNS_NON_BOOL;
+};
+
+class DerivedCorrect : public Base {
+ public:
+  int SafeMember();
+  int NonBoolMember() RETURNS_NON_BOOL; // expected-note{{'NonBoolMember' declared here}}
+};
+
+class DerivedIncorrect : public Base {
+ public:
+  int SafeMember() RETURNS_NON_BOOL; // expected-note {{'SafeMember' declared here}}
+  int NonBoolMember();
+};
+
+void TestMemberFunctions() {
+  DerivedCorrect DC;
+  DerivedIncorrect DI;
+  if (DC.SafeMember()) {}
+  if (DI.SafeMember()) {} // expected-warning{{implicit conversion turns non-bool into bool: 'int' to 'bool'}}
+  if (DC.NonBoolMember()) {} // expected-warning{{implicit conversion turns non-bool into bool: 'int' to 'bool'}}
+  if (DI.NonBoolMember()) {}
+}
+
+
+
Index: test/Analysis/ReturnNonBoolTest.cpp
===
--- /dev/null
+++ test/Analysis/ReturnNonBoolTest.cpp
@@ -0,0 +1,88 @@
+// RUN: %clang_cc1 -std=c++11 -analyze -analyzer-checker=alpha.core.ReturnNonBool -Wno-bool-conversion -verify %s
+#ifdef __clang__
+#define RETURNS_NON_BOOL __attribute__((warn_impcast_to_bool))
+#else
+#define RETURNS_NON_BOOL
+#endif
+
+int NoAttributes() { return 2; }
+
+int NonBool(int x) RETURNS_NON_BOOL;
+
+int good(int x);
+
+int wrap(int x) {
+  int r = NonBool(x);
+  return r;
+}
+
+void test1() {
+  if (NonBool(1)) {  // expected-warning{{implicit cast to bool is dangerous for this value}}
+return;
+  }
+}
+
+void test2() {
+  if (wrap(2)) {  // expected-warning{{implicit cast to bool is dangerous for this value}}
+return;
+  }
+}
+
+void test3() {
+  if ((bool)NonBool(3)) {  // no warning, explicit cast
+return;
+  }
+}
+
+void test4(int x) {
+  if (bool(wrap(2 * x))) {  // no warning, explicit cast
+return;
+  }
+}
+
+void test5() {
+  if (good(5)) {  // no warning, return value isn't marked as dangerous
+return;
+  }
+}
+
+void test6() {
+  if (good(wrap(2))) {  // no warning, wrap is treated as int, not as bool
+return;
+  }
+}
+
+double InvalidAttributeUsage()
+RETURNS_NON_BOOL;  // expected-warning{{'warn_impcast_to_bool' attribute only applies to integer return types}}
+
+void test_function_pointer(void (*f)()) {
+  // This is to test the case when Call.getDecl() returns NULL, because f()
+  // doesn't have a declaration
+  f();
+}
+
+bool universal_bool_wrapper(int (*f)(int), int x) {
+  // When we call universal_bool_wrapper 

Re: [PATCH] D24507: Add attribute for return values that shouldn't be cast to bool

2016-09-20 Thread Anton Urusov via cfe-commits
urusant added inline comments.


Comment at: lib/StaticAnalyzer/Checkers/ReturnNonBoolChecker.cpp:50
@@ +49,3 @@
+  if (!State->contains(SR)) return;
+
+  ExplodedNode *N = C.generateErrorNode(C.getState());

I have just noticed that I didn't specify the style option when I ran it the 
first time. Now it should be fine.


Comment at: test/ReturnNonBoolTest.c:7
@@ +6,3 @@
+
+#ifdef __clang__
+#define RETURNS_NON_BOOL __attribute__((warn_impcast_to_bool))

danielmarjamaki wrote:
> sorry but why do you have a #ifdef __clang__ isn't it always defined?
If I were to add the attribute to a function in some real codebase, I would 
probably want to save different compilers compatibility. However, it might not 
be necessary for the testcases.


Repository:
  rL LLVM

https://reviews.llvm.org/D24507



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D24507: Add attribute for return values that shouldn't be cast to bool

2016-09-13 Thread Anton Urusov via cfe-commits
urusant created this revision.
urusant added reviewers: zaks.anna, dcoughlin, jordan_rose, NoQ.
urusant added subscribers: cfe-commits, daviddrysdale.
urusant set the repository for this revision to rL LLVM.
Herald added subscribers: mgorny, beanz.

Hi,

I am interested in feedback on a patch I was working on that adds a new 
attribute (warn_impcast_to_bool) to indicate that the return value of a 
function shouldn't be used as a boolean, as well as a compile warning and a 
StaticAnalyzer checker to warn about misusing functions with this attribute. 
I'd also appreciate any suggestions for how to deal with a class of false 
positives that the static analysis checker produces.

The change was originally inspired by CVE-2008-5077 [1], which was the result 
of an odd design choice in OpenSSL: having an API that returns 1 for success, 0 
for failure... and -1 for catastrophic failure. Various API users fell into the 
trap of treating the return value as a boolean, so the patch adds an attribute 
to allow this to trigger a warning.

As well as generating a compile-time warning, the patch also includes a new 
static analyzer checker to catch more indirect uses, where the non-boolean 
integer value gets propagated via function wrappers or local variables. 
However, it gives a false positive for cases when the code using the return 
value actually checks the value in a non-boolean way (because the SVal doesn't 
reflect the fact that the value has been further constrained). I couldn't see 
an obvious way to get anything relevant from the RangeConstraintManager; any 
suggestions?

To test the check (beyond the included unit tests), I annotated dangerous 
OpenSSL functions and tried building 8 OpenSSL-using codebases with it. So far, 
this didn't give many results for them: the only possible problem was found in 
ruby2.1, which was already fixed a few months ago. However, this change is 
still potentially useful - even 7 years after the original CVE, there are still 
codebases that fall into OpenSSL's API trap.

[1] https://www.openssl.org/news/secadv/20090107.txt

Repository:
  rL LLVM

https://reviews.llvm.org/D24507

Files:
  include/clang/Basic/Attr.td
  include/clang/Basic/AttrDocs.td
  include/clang/Basic/DiagnosticGroups.td
  include/clang/Basic/DiagnosticSemaKinds.td
  include/clang/StaticAnalyzer/Checkers/Checkers.td
  lib/Sema/SemaChecking.cpp
  lib/Sema/SemaDeclAttr.cpp
  lib/StaticAnalyzer/Checkers/CMakeLists.txt
  lib/StaticAnalyzer/Checkers/ReturnNonBoolChecker.cpp
  test/ReturnNonBoolTest.c
  test/ReturnNonBoolTest.cpp
  test/ReturnNonBoolTestCompileTime.cpp

Index: test/ReturnNonBoolTestCompileTime.cpp
===
--- /dev/null
+++ test/ReturnNonBoolTestCompileTime.cpp
@@ -0,0 +1,39 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -Wunsafe-bool-conversion -verify %s
+#ifdef __clang__
+#define RETURNS_NON_BOOL __attribute__((warn_impcast_to_bool))
+#else
+#define RETURNS_NON_BOOL
+#endif
+
+int NoAttributes() {
+  return 2;
+}
+
+int NonBool(int x) RETURNS_NON_BOOL;
+int NonBool(int x) { // expected-note{{'NonBool' declared here}}
+  return x * 2;
+}
+
+int good(int x) {
+  return x * 2;
+}
+
+void test1() {
+  if (NonBool(2)) { // expected-warning{{implicit conversion turns non-bool into bool: 'int' to 'bool'}}
+return;
+  }
+}
+
+void test3() {
+  if ((bool)NonBool(2)) { // no warning, explicit cast
+return;
+  }
+}
+
+void test5() {
+  if (good(2)) { // no warning, return value isn't marked as dangerous
+return;
+  }
+}
+
+double InvalidAttributeUsage() RETURNS_NON_BOOL; // expected-warning{{'warn_impcast_to_bool' attribute only applies to return values that are integers}}
\ No newline at end of file
Index: test/ReturnNonBoolTest.cpp
===
--- /dev/null
+++ test/ReturnNonBoolTest.cpp
@@ -0,0 +1,90 @@
+// RUN: %clang_cc1 -std=c++11 -analyze -analyzer-checker=alpha.core.ReturnNonBool -verify %s
+#ifdef __clang__
+#define RETURNS_NON_BOOL __attribute__((warn_impcast_to_bool))
+#else
+#define RETURNS_NON_BOOL
+#endif
+
+int NoAttributes() {
+  return 2;
+}
+
+int NonBool(int x) RETURNS_NON_BOOL;
+
+int good(int x);
+
+int wrap(int x) {
+  int r = NonBool(x);
+  return r;
+}
+
+void test1() {
+  if (NonBool(1)) { // expected-warning{{implicit cast to bool is dangerous for this value}}
+return;
+  }
+}
+
+void test2() {
+  if (wrap(2)) { // expected-warning{{implicit cast to bool is dangerous for this value}}
+return;
+  }
+}
+
+void test3() {
+  if ((bool)NonBool(3)) { // no warning, explicit cast
+return;
+  }
+}
+
+void test4(int x) {
+  if (bool(wrap(2 * x))) { // no warning, explicit cast
+return;
+  }
+}
+
+void test5() {
+  if (good(5)) { // no warning, return value isn't marked as dangerous
+return;
+  }
+}
+
+void test6() {
+  if (good(wrap(2))) { // no warning, wrap is treated as int, not as bool
+return;
+  }
+}
+
+double InvalidAttributeUsage()