[PATCH] D25876: [analyzer] Report CFNumberGetValue API misuse

2016-10-26 Thread Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL285253: [analyzer] Report CFNumberGetValue API misuse 
(authored by zaks).

Changed prior to commit:
  https://reviews.llvm.org/D25876?vs=75488&id=75961#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D25876

Files:
  cfe/trunk/include/clang/StaticAnalyzer/Checkers/Checkers.td
  cfe/trunk/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
  cfe/trunk/test/Analysis/CFNumber.c

Index: cfe/trunk/include/clang/StaticAnalyzer/Checkers/Checkers.td
===
--- cfe/trunk/include/clang/StaticAnalyzer/Checkers/Checkers.td
+++ cfe/trunk/include/clang/StaticAnalyzer/Checkers/Checkers.td
@@ -586,8 +586,8 @@
 
 let ParentPackage = CoreFoundation in {
 
-def CFNumberCreateChecker : Checker<"CFNumber">,
-  HelpText<"Check for proper uses of CFNumberCreate">,
+def CFNumberChecker : Checker<"CFNumber">,
+  HelpText<"Check for proper uses of CFNumber APIs">,
   DescFile<"BasicObjCFoundationChecks.cpp">;
 
 def CFRetainReleaseChecker : Checker<"CFRetainRelease">,
Index: cfe/trunk/test/Analysis/CFNumber.c
===
--- cfe/trunk/test/Analysis/CFNumber.c
+++ cfe/trunk/test/Analysis/CFNumber.c
@@ -13,21 +13,35 @@
kCFNumberMaxType = 16 };
 typedef CFIndex CFNumberType;
 typedef const struct __CFNumber * CFNumberRef;
+typedef unsigned char Boolean;
 extern CFNumberRef CFNumberCreate(CFAllocatorRef allocator, CFNumberType theType, const void *valuePtr);
+Boolean CFNumberGetValue(CFNumberRef number, CFNumberType theType, void *valuePtr);
 
-CFNumberRef f1(unsigned char x) {
-  return CFNumberCreate(0, kCFNumberSInt16Type, &x);  // expected-warning{{An 8 bit integer is used to initialize a CFNumber object that represents a 16 bit integer. 8 bits of the CFNumber value will be garbage}}
+__attribute__((cf_returns_retained)) CFNumberRef f1(unsigned char x) {
+  return CFNumberCreate(0, kCFNumberSInt16Type, &x);  // expected-warning{{An 8-bit integer is used to initialize a CFNumber object that represents a 16-bit integer; 8 bits of the CFNumber value will be garbage}}
 }
 
 __attribute__((cf_returns_retained)) CFNumberRef f2(unsigned short x) {
-  return CFNumberCreate(0, kCFNumberSInt8Type, &x); // expected-warning{{A 16 bit integer is used to initialize a CFNumber object that represents an 8 bit integer. 8 bits of the input integer will be lost}}
+  return CFNumberCreate(0, kCFNumberSInt8Type, &x); // expected-warning{{A 16-bit integer is used to initialize a CFNumber object that represents an 8-bit integer; 8 bits of the integer value will be lost}}
 }
 
 // test that the attribute overrides the naming convention.
 __attribute__((cf_returns_not_retained)) CFNumberRef CreateNum(unsigned char x) {
   return CFNumberCreate(0, kCFNumberSInt8Type, &x); // expected-warning{{leak}}
 }
 
-CFNumberRef f3(unsigned i) {
-  return CFNumberCreate(0, kCFNumberLongType, &i); // expected-warning{{A 32 bit integer is used to initialize a CFNumber object that represents a 64 bit integer}}
+__attribute__((cf_returns_retained)) CFNumberRef f3(unsigned i) {
+  return CFNumberCreate(0, kCFNumberLongType, &i); // expected-warning{{A 32-bit integer is used to initialize a CFNumber object that represents a 64-bit integer}}
+}
+
+unsigned char getValueTest1(CFNumberRef x) {
+  unsigned char scalar = 0;
+  CFNumberGetValue(x, kCFNumberSInt16Type, &scalar);  // expected-warning{{A CFNumber object that represents a 16-bit integer is used to initialize an 8-bit integer; 8 bits of the CFNumber value will overwrite adjacent storage}}
+  return scalar;
+}
+
+unsigned char getValueTest2(CFNumberRef x) {
+  unsigned short scalar = 0;
+  CFNumberGetValue(x, kCFNumberSInt8Type, &scalar);  // expected-warning{{A CFNumber object that represents an 8-bit integer is used to initialize a 16-bit integer; 8 bits of the integer value will be garbage}}
+  return scalar;
 }
Index: cfe/trunk/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
===
--- cfe/trunk/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
@@ -336,15 +336,15 @@
 }
 
 //===--===//
-// Error reporting.
+// Checking for mismatched types passed to CFNumberCreate/CFNumberGetValue.
 //===--===//
 
 namespace {
-class CFNumberCreateChecker : public Checker< check::PreStmt > {
+class CFNumberChecker : public Checker< check::PreStmt > {
   mutable std::unique_ptr BT;
-  mutable IdentifierInfo* II;
+  mutable IdentifierInfo *ICreate, *IGetValue;
 public:
-  CFNumberCreateChecker() : II(nullptr) {}
+  CFNumberChecker() : ICreate(nullptr), IGetValue(nullptr) {}
 
   void checkPreStmt(const CallExpr *CE, CheckerConte

[PATCH] D25876: [analyzer] Report CFNumberGetValue API misuse

2016-10-25 Thread Anna Zaks via cfe-commits
zaks.anna added inline comments.



Comment at: test/Analysis/CFNumber.c:39
+  unsigned char scalar = 0;
+  CFNumberGetValue(x, kCFNumberSInt16Type, &scalar);  // expected-warning{{A 
CFNumber object that represents a 16-bit integer is used to initialize an 8-bit 
integer; 8 bits of the CFNumber value will overwrite adjacent storage}}
+  return scalar;

NoQ wrote:
> We're not sure from this code if the `CFNumber` object `x` actually 
> represents a 16-bit integer, or somebody just misplaced the 
> `kCFNumberSInt16Type` thing. I think the warning message could be made more 
> precise in this sence, but i'm not good at coming up with warning messages.
> 
> Hmm, there could actually be a separate check for detecting inconsistent type 
> specifiers used for accessing the same CFNumber object.
I see your point. Looks like we'd need to modify both first part of the 
sentence and the second to address this concern. We could do something like "A 
CFNumber object treated as if it represents a 16-bit integer is used to 
initialize an 8-bit integer; 8 bits of the CFNumber value or the adjacent 
storage will overwrite adjacent storage of the integer".

Though this is more correct, I do not think it's worth the new language 
complexity. Also, the warning message is already quite long.


https://reviews.llvm.org/D25876



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


[PATCH] D25876: [analyzer] Report CFNumberGetValue API misuse

2016-10-25 Thread Artem Dergachev via cfe-commits
NoQ added inline comments.



Comment at: test/Analysis/CFNumber.c:39
+  unsigned char scalar = 0;
+  CFNumberGetValue(x, kCFNumberSInt16Type, &scalar);  // expected-warning{{A 
CFNumber object that represents a 16-bit integer is used to initialize an 8-bit 
integer; 8 bits of the CFNumber value will overwrite adjacent storage}}
+  return scalar;

We're not sure from this code if the `CFNumber` object `x` actually represents 
a 16-bit integer, or somebody just misplaced the `kCFNumberSInt16Type` thing. I 
think the warning message could be made more precise in this sence, but i'm not 
good at coming up with warning messages.

Hmm, there could actually be a separate check for detecting inconsistent type 
specifiers used for accessing the same CFNumber object.


https://reviews.llvm.org/D25876



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


[PATCH] D25876: [analyzer] Report CFNumberGetValue API misuse

2016-10-21 Thread Anna Zaks via cfe-commits
zaks.anna updated this revision to Diff 75488.
zaks.anna added a comment.

Address comments from Devin.


https://reviews.llvm.org/D25876

Files:
  include/clang/StaticAnalyzer/Checkers/Checkers.td
  lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
  test/Analysis/CFNumber.c

Index: test/Analysis/CFNumber.c
===
--- test/Analysis/CFNumber.c
+++ test/Analysis/CFNumber.c
@@ -13,21 +13,35 @@
kCFNumberMaxType = 16 };
 typedef CFIndex CFNumberType;
 typedef const struct __CFNumber * CFNumberRef;
+typedef unsigned char Boolean;
 extern CFNumberRef CFNumberCreate(CFAllocatorRef allocator, CFNumberType theType, const void *valuePtr);
+Boolean CFNumberGetValue(CFNumberRef number, CFNumberType theType, void *valuePtr);
 
-CFNumberRef f1(unsigned char x) {
-  return CFNumberCreate(0, kCFNumberSInt16Type, &x);  // expected-warning{{An 8 bit integer is used to initialize a CFNumber object that represents a 16 bit integer. 8 bits of the CFNumber value will be garbage}}
+__attribute__((cf_returns_retained)) CFNumberRef f1(unsigned char x) {
+  return CFNumberCreate(0, kCFNumberSInt16Type, &x);  // expected-warning{{An 8-bit integer is used to initialize a CFNumber object that represents a 16-bit integer; 8 bits of the CFNumber value will be garbage}}
 }
 
 __attribute__((cf_returns_retained)) CFNumberRef f2(unsigned short x) {
-  return CFNumberCreate(0, kCFNumberSInt8Type, &x); // expected-warning{{A 16 bit integer is used to initialize a CFNumber object that represents an 8 bit integer. 8 bits of the input integer will be lost}}
+  return CFNumberCreate(0, kCFNumberSInt8Type, &x); // expected-warning{{A 16-bit integer is used to initialize a CFNumber object that represents an 8-bit integer; 8 bits of the integer value will be lost}}
 }
 
 // test that the attribute overrides the naming convention.
 __attribute__((cf_returns_not_retained)) CFNumberRef CreateNum(unsigned char x) {
   return CFNumberCreate(0, kCFNumberSInt8Type, &x); // expected-warning{{leak}}
 }
 
-CFNumberRef f3(unsigned i) {
-  return CFNumberCreate(0, kCFNumberLongType, &i); // expected-warning{{A 32 bit integer is used to initialize a CFNumber object that represents a 64 bit integer}}
+__attribute__((cf_returns_retained)) CFNumberRef f3(unsigned i) {
+  return CFNumberCreate(0, kCFNumberLongType, &i); // expected-warning{{A 32-bit integer is used to initialize a CFNumber object that represents a 64-bit integer}}
+}
+
+unsigned char getValueTest1(CFNumberRef x) {
+  unsigned char scalar = 0;
+  CFNumberGetValue(x, kCFNumberSInt16Type, &scalar);  // expected-warning{{A CFNumber object that represents a 16-bit integer is used to initialize an 8-bit integer; 8 bits of the CFNumber value will overwrite adjacent storage}}
+  return scalar;
+}
+
+unsigned char getValueTest2(CFNumberRef x) {
+  unsigned short scalar = 0;
+  CFNumberGetValue(x, kCFNumberSInt8Type, &scalar);  // expected-warning{{A CFNumber object that represents an 8-bit integer is used to initialize a 16-bit integer; 8 bits of the integer value will be garbage}}
+  return scalar;
 }
Index: lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
===
--- lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
+++ lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
@@ -336,15 +336,15 @@
 }
 
 //===--===//
-// Error reporting.
+// Checking for mismatched types passed to CFNumberCreate/CFNumberGetValue.
 //===--===//
 
 namespace {
-class CFNumberCreateChecker : public Checker< check::PreStmt > {
+class CFNumberChecker : public Checker< check::PreStmt > {
   mutable std::unique_ptr BT;
-  mutable IdentifierInfo* II;
+  mutable IdentifierInfo *ICreate, *IGetValue;
 public:
-  CFNumberCreateChecker() : II(nullptr) {}
+  CFNumberChecker() : ICreate(nullptr), IGetValue(nullptr) {}
 
   void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
 
@@ -425,18 +425,20 @@
 }
 #endif
 
-void CFNumberCreateChecker::checkPreStmt(const CallExpr *CE,
+void CFNumberChecker::checkPreStmt(const CallExpr *CE,
  CheckerContext &C) const {
   ProgramStateRef state = C.getState();
   const FunctionDecl *FD = C.getCalleeDecl(CE);
   if (!FD)
 return;
 
   ASTContext &Ctx = C.getASTContext();
-  if (!II)
-II = &Ctx.Idents.get("CFNumberCreate");
-
-  if (FD->getIdentifier() != II || CE->getNumArgs() != 3)
+  if (!ICreate) {
+ICreate = &Ctx.Idents.get("CFNumberCreate");
+IGetValue = &Ctx.Idents.get("CFNumberGetValue");
+  }
+  if (!(FD->getIdentifier() == ICreate || FD->getIdentifier() == IGetValue) ||
+  CE->getNumArgs() != 3)
 return;
 
   // Get the value of the "theType" argument.
@@ -450,13 +452,13 @@
 return;
 
   uint64_t NumberKind = V->getValue().getLimit

[PATCH] D25876: [analyzer] Report CFNumberGetValue API misuse

2016-10-21 Thread Devin Coughlin via cfe-commits
dcoughlin added a comment.

LGTM!


https://reviews.llvm.org/D25876



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


[PATCH] D25876: [analyzer] Report CFNumberGetValue API misuse

2016-10-21 Thread Devin Coughlin via cfe-commits
dcoughlin added inline comments.



Comment at: test/Analysis/CFNumber.c:39
+  unsigned char scalar = 0;
+  CFNumberGetValue(x, kCFNumberSInt16Type, &scalar);  // expected-warning{{A 
CFNumber object that represents a 16 bit integer is used to initialize an 8 bit 
integer. 8 bits of the CFNumber value will be lost}}
+  return scalar;

I feel like this diagnostic is not dire enough. The problem is not that the 
bits will be lost -- but rather that they will be overwritten on top of 
something else!

How about something like "The remaining 8 bits will overwrite adjacent 
storage."?



Comment at: test/Analysis/CFNumber.c:45
+  unsigned short scalar = 0;
+  CFNumberGetValue(x, kCFNumberSInt8Type, &scalar);  // expected-warning{{A 
CFNumber object that represents an 8 bit integer is used to initialize a 16 bit 
integer. 8 bits of the integer value will be garbage}}
+  return scalar;

Some grammar/style nits. (I realize these also hold for the pre-existing 
checks):

- There should be a dash between the number and 'bit'. That is, it should be 
"16-bit" and "8-bit".
- It is generally considered bad style to start a sentence with a number that 
is not written out (except for dates). How about starting the second sentence 
with "The remaining 8 bits ..."?


https://reviews.llvm.org/D25876



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


[PATCH] D25876: [analyzer] Report CFNumberGetValue API misuse

2016-10-21 Thread Anna Zaks via cfe-commits
zaks.anna created this revision.
zaks.anna added reviewers: dcoughlin, NoQ.
zaks.anna added subscribers: cfe-commits, rgov.

This patch contains 2 improvements to the CFNumber checker:

- Checking of CFNumberGetValue misuse.
- Treating all CFNumber API misuse errors as non-fatal. (Previously we treated 
errors that could cause uninitialized memory as syncs and the truncation errors 
as non-fatal.)

This implements a subset of functionality from https://reviews.llvm.org/D17954.


https://reviews.llvm.org/D25876

Files:
  include/clang/StaticAnalyzer/Checkers/Checkers.td
  lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
  test/Analysis/CFNumber.c

Index: test/Analysis/CFNumber.c
===
--- test/Analysis/CFNumber.c
+++ test/Analysis/CFNumber.c
@@ -13,21 +13,35 @@
kCFNumberMaxType = 16 };
 typedef CFIndex CFNumberType;
 typedef const struct __CFNumber * CFNumberRef;
+typedef unsigned char Boolean;
 extern CFNumberRef CFNumberCreate(CFAllocatorRef allocator, CFNumberType theType, const void *valuePtr);
+Boolean CFNumberGetValue(CFNumberRef number, CFNumberType theType, void *valuePtr);
 
-CFNumberRef f1(unsigned char x) {
+__attribute__((cf_returns_retained)) CFNumberRef f1(unsigned char x) {
   return CFNumberCreate(0, kCFNumberSInt16Type, &x);  // expected-warning{{An 8 bit integer is used to initialize a CFNumber object that represents a 16 bit integer. 8 bits of the CFNumber value will be garbage}}
 }
 
 __attribute__((cf_returns_retained)) CFNumberRef f2(unsigned short x) {
-  return CFNumberCreate(0, kCFNumberSInt8Type, &x); // expected-warning{{A 16 bit integer is used to initialize a CFNumber object that represents an 8 bit integer. 8 bits of the input integer will be lost}}
+  return CFNumberCreate(0, kCFNumberSInt8Type, &x); // expected-warning{{A 16 bit integer is used to initialize a CFNumber object that represents an 8 bit integer. 8 bits of the integer value will be lost}}
 }
 
 // test that the attribute overrides the naming convention.
 __attribute__((cf_returns_not_retained)) CFNumberRef CreateNum(unsigned char x) {
   return CFNumberCreate(0, kCFNumberSInt8Type, &x); // expected-warning{{leak}}
 }
 
-CFNumberRef f3(unsigned i) {
+__attribute__((cf_returns_retained)) CFNumberRef f3(unsigned i) {
   return CFNumberCreate(0, kCFNumberLongType, &i); // expected-warning{{A 32 bit integer is used to initialize a CFNumber object that represents a 64 bit integer}}
 }
+
+unsigned char getValueTest1(CFNumberRef x) {
+  unsigned char scalar = 0;
+  CFNumberGetValue(x, kCFNumberSInt16Type, &scalar);  // expected-warning{{A CFNumber object that represents a 16 bit integer is used to initialize an 8 bit integer. 8 bits of the CFNumber value will be lost}}
+  return scalar;
+}
+
+unsigned char getValueTest2(CFNumberRef x) {
+  unsigned short scalar = 0;
+  CFNumberGetValue(x, kCFNumberSInt8Type, &scalar);  // expected-warning{{A CFNumber object that represents an 8 bit integer is used to initialize a 16 bit integer. 8 bits of the integer value will be garbage}}
+  return scalar;
+}
Index: lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
===
--- lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
+++ lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
@@ -336,15 +336,15 @@
 }
 
 //===--===//
-// Error reporting.
+// Checking for mismatched types passed to CFNumberCreate/CFNumberGetValue.
 //===--===//
 
 namespace {
-class CFNumberCreateChecker : public Checker< check::PreStmt > {
+class CFNumberChecker : public Checker< check::PreStmt > {
   mutable std::unique_ptr BT;
-  mutable IdentifierInfo* II;
+  mutable IdentifierInfo *ICreate, *IGetValue;
 public:
-  CFNumberCreateChecker() : II(nullptr) {}
+  CFNumberChecker() : ICreate(nullptr), IGetValue(nullptr) {}
 
   void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
 
@@ -425,18 +425,20 @@
 }
 #endif
 
-void CFNumberCreateChecker::checkPreStmt(const CallExpr *CE,
+void CFNumberChecker::checkPreStmt(const CallExpr *CE,
  CheckerContext &C) const {
   ProgramStateRef state = C.getState();
   const FunctionDecl *FD = C.getCalleeDecl(CE);
   if (!FD)
 return;
 
   ASTContext &Ctx = C.getASTContext();
-  if (!II)
-II = &Ctx.Idents.get("CFNumberCreate");
-
-  if (FD->getIdentifier() != II || CE->getNumArgs() != 3)
+  if (!ICreate) {
+ICreate = &Ctx.Idents.get("CFNumberCreate");
+IGetValue = &Ctx.Idents.get("CFNumberGetValue");
+  }
+  if (!(FD->getIdentifier() == ICreate || FD->getIdentifier() == IGetValue) ||
+  CE->getNumArgs() != 3)
 return;
 
   // Get the value of the "theType" argument.
@@ -450,13 +452,13 @@
 return;
 
   uint64_t NumberKind = V->getValue().getLimitedValue();
-  Option