[llvm-branch-commits] [clang] 64c979d - [analyzer] StdLibraryFunctionsChecker: Add support for new functions

Zurab Tsinadze via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Wed Aug 12 07:15:42 PDT 2020


Author: Zurab Tsinadze
Date: 2020-08-12T16:11:14+02:00
New Revision: 64c979d948f7af2e88416618f8abe658c7014d9c

URL: https://github.com/llvm/llvm-project/commit/64c979d948f7af2e88416618f8abe658c7014d9c
DIFF: https://github.com/llvm/llvm-project/commit/64c979d948f7af2e88416618f8abe658c7014d9c.diff

LOG: [analyzer] StdLibraryFunctionsChecker: Add support for new functions

`toupper`, `tolower`, `toascii` functions were added to
StdLibraryFunctionsChecker to fully cover CERT STR37-C rule:
https://wiki.sei.cmu.edu/confluence/x/BNcxBQ

Reviewed By: martong

Differential Revision: https://reviews.llvm.org/D85093

Added: 
    

Modified: 
    clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
    clang/test/Analysis/std-c-library-functions-arg-constraints.c

Removed: 
    


################################################################################
diff  --git a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
index e437c33bd81a..030f995739e3 100644
--- a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
@@ -40,12 +40,12 @@
 //
 // The following standard C functions are currently supported:
 //
-//   fgetc      getline   isdigit   isupper
+//   fgetc      getline   isdigit   isupper     toascii
 //   fread      isalnum   isgraph   isxdigit
 //   fwrite     isalpha   islower   read
 //   getc       isascii   isprint   write
-//   getchar    isblank   ispunct
-//   getdelim   iscntrl   isspace
+//   getchar    isblank   ispunct   toupper
+//   getdelim   iscntrl   isspace   tolower
 //
 //===----------------------------------------------------------------------===//
 
@@ -147,9 +147,7 @@ class StdLibraryFunctionsChecker
     RangeConstraint(ArgNo ArgN, RangeKind Kind, const IntRangeVector &Args)
         : ValueConstraint(ArgN), Kind(Kind), Args(Args) {}
 
-    const IntRangeVector &getRanges() const {
-      return Args;
-    }
+    const IntRangeVector &getRanges() const { return Args; }
 
   private:
     ProgramStateRef applyAsOutOfRange(ProgramStateRef State,
@@ -158,6 +156,7 @@ class StdLibraryFunctionsChecker
     ProgramStateRef applyAsWithinRange(ProgramStateRef State,
                                        const CallEvent &Call,
                                        const Summary &Summary) const;
+
   public:
     ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
                           const Summary &Summary,
@@ -408,7 +407,7 @@ class StdLibraryFunctionsChecker
       return *this;
     }
 
-    Summary &Case(ConstraintSet&& CS) {
+    Summary &Case(ConstraintSet &&CS) {
       CaseConstraints.push_back(std::move(CS));
       return *this;
     }
@@ -796,13 +795,13 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
   const QualType LongLongTy = ACtx.LongLongTy;
   const QualType SizeTy = ACtx.getSizeType();
 
-  const QualType VoidPtrTy = ACtx.VoidPtrTy; // void *
+  const QualType VoidPtrTy = ACtx.VoidPtrTy;            // void *
   const QualType IntPtrTy = ACtx.getPointerType(IntTy); // int *
   const QualType UnsignedIntPtrTy =
       ACtx.getPointerType(UnsignedIntTy); // unsigned int *
   const QualType VoidPtrRestrictTy = getRestrictTy(VoidPtrTy);
   const QualType ConstVoidPtrTy =
-      ACtx.getPointerType(ACtx.VoidTy.withConst()); // const void *
+      ACtx.getPointerType(ACtx.VoidTy.withConst());            // const void *
   const QualType CharPtrTy = ACtx.getPointerType(ACtx.CharTy); // char *
   const QualType CharPtrRestrictTy = getRestrictTy(CharPtrTy);
   const QualType ConstCharPtrTy =
@@ -1117,6 +1116,18 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
           .Case({ArgumentCondition(0U, OutOfRange,
                                    {{'0', '9'}, {'A', 'F'}, {'a', 'f'}}),
                  ReturnValueCondition(WithinRange, SingleValue(0))}));
+  addToFunctionSummaryMap(
+      "toupper", Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
+                     .ArgConstraint(ArgumentCondition(
+                         0U, WithinRange, {{EOFv, EOFv}, {0, UCharRangeMax}})));
+  addToFunctionSummaryMap(
+      "tolower", Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
+                     .ArgConstraint(ArgumentCondition(
+                         0U, WithinRange, {{EOFv, EOFv}, {0, UCharRangeMax}})));
+  addToFunctionSummaryMap(
+      "toascii", Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
+                     .ArgConstraint(ArgumentCondition(
+                         0U, WithinRange, {{EOFv, EOFv}, {0, UCharRangeMax}})));
 
   // The getc() family of functions that returns either a char or an EOF.
   if (FilePtrTy) {
@@ -2033,7 +2044,8 @@ void ento::registerStdCLibraryFunctionsChecker(CheckerManager &mgr) {
       mgr.getAnalyzerOptions().getCheckerBooleanOption(Checker, "ModelPOSIX");
 }
 
-bool ento::shouldRegisterStdCLibraryFunctionsChecker(const CheckerManager &mgr) {
+bool ento::shouldRegisterStdCLibraryFunctionsChecker(
+    const CheckerManager &mgr) {
   return true;
 }
 

diff  --git a/clang/test/Analysis/std-c-library-functions-arg-constraints.c b/clang/test/Analysis/std-c-library-functions-arg-constraints.c
index b23700a96f38..e926cd15384d 100644
--- a/clang/test/Analysis/std-c-library-functions-arg-constraints.c
+++ b/clang/test/Analysis/std-c-library-functions-arg-constraints.c
@@ -45,7 +45,6 @@ void test_alnum_symbolic(int x) {
   // bugpath-note{{TRUE}} \
   // bugpath-note{{Left side of '&&' is true}} \
   // bugpath-note{{'x' is <= 255}}
-
 }
 
 void test_alnum_symbolic2(int x) {
@@ -62,6 +61,114 @@ void test_alnum_symbolic2(int x) {
   }
 }
 
+int toupper(int);
+
+void test_toupper_concrete(int v) {
+  int ret = toupper(256); // \
+  // report-warning{{Function argument constraint is not satisfied}} \
+  // bugpath-warning{{Function argument constraint is not satisfied}} \
+  // bugpath-note{{Function argument constraint is not satisfied}}
+  (void)ret;
+}
+
+void test_toupper_symbolic(int x) {
+  int ret = toupper(x);
+  (void)ret;
+
+  clang_analyzer_eval(EOF <= x && x <= 255); // \
+  // report-warning{{TRUE}} \
+  // bugpath-warning{{TRUE}} \
+  // bugpath-note{{TRUE}} \
+  // bugpath-note{{Left side of '&&' is true}} \
+  // bugpath-note{{'x' is <= 255}}
+}
+
+void test_toupper_symbolic2(int x) {
+  if (x > 255) { // \
+    // bugpath-note{{Assuming 'x' is > 255}} \
+    // bugpath-note{{Taking true branch}}
+
+    int ret = toupper(x); // \
+    // report-warning{{Function argument constraint is not satisfied}} \
+    // bugpath-warning{{Function argument constraint is not satisfied}} \
+    // bugpath-note{{Function argument constraint is not satisfied}}
+
+    (void)ret;
+  }
+}
+
+int tolower(int);
+
+void test_tolower_concrete(int v) {
+  int ret = tolower(256); // \
+  // report-warning{{Function argument constraint is not satisfied}} \
+  // bugpath-warning{{Function argument constraint is not satisfied}} \
+  // bugpath-note{{Function argument constraint is not satisfied}}
+  (void)ret;
+}
+
+void test_tolower_symbolic(int x) {
+  int ret = tolower(x);
+  (void)ret;
+
+  clang_analyzer_eval(EOF <= x && x <= 255); // \
+  // report-warning{{TRUE}} \
+  // bugpath-warning{{TRUE}} \
+  // bugpath-note{{TRUE}} \
+  // bugpath-note{{Left side of '&&' is true}} \
+  // bugpath-note{{'x' is <= 255}}
+}
+
+void test_tolower_symbolic2(int x) {
+  if (x > 255) { // \
+    // bugpath-note{{Assuming 'x' is > 255}} \
+    // bugpath-note{{Taking true branch}}
+
+    int ret = tolower(x); // \
+    // report-warning{{Function argument constraint is not satisfied}} \
+    // bugpath-warning{{Function argument constraint is not satisfied}} \
+    // bugpath-note{{Function argument constraint is not satisfied}}
+
+    (void)ret;
+  }
+}
+
+int toascii(int);
+
+void test_toascii_concrete(int v) {
+  int ret = toascii(256); // \
+  // report-warning{{Function argument constraint is not satisfied}} \
+  // bugpath-warning{{Function argument constraint is not satisfied}} \
+  // bugpath-note{{Function argument constraint is not satisfied}}
+  (void)ret;
+}
+
+void test_toascii_symbolic(int x) {
+  int ret = toascii(x);
+  (void)ret;
+
+  clang_analyzer_eval(EOF <= x && x <= 255); // \
+  // report-warning{{TRUE}} \
+  // bugpath-warning{{TRUE}} \
+  // bugpath-note{{TRUE}} \
+  // bugpath-note{{Left side of '&&' is true}} \
+  // bugpath-note{{'x' is <= 255}}
+}
+
+void test_toascii_symbolic2(int x) {
+  if (x > 255) { // \
+    // bugpath-note{{Assuming 'x' is > 255}} \
+    // bugpath-note{{Taking true branch}}
+
+    int ret = toascii(x); // \
+    // report-warning{{Function argument constraint is not satisfied}} \
+    // bugpath-warning{{Function argument constraint is not satisfied}} \
+    // bugpath-note{{Function argument constraint is not satisfied}}
+
+    (void)ret;
+  }
+}
+
 typedef struct FILE FILE;
 typedef typeof(sizeof(int)) size_t;
 size_t fread(void *restrict, size_t, size_t, FILE *restrict);
@@ -80,7 +187,7 @@ void test_notnull_symbolic(FILE *fp, int *buf) {
   // bugpath-note{{'buf' is not equal to null}}
 }
 void test_notnull_symbolic2(FILE *fp, int *buf) {
-  if (!buf) // bugpath-note{{Assuming 'buf' is null}} \
+  if (!buf)                          // bugpath-note{{Assuming 'buf' is null}} \
             // bugpath-note{{Taking true branch}}
     fread(buf, sizeof(int), 10, fp); // \
     // report-warning{{Function argument constraint is not satisfied}} \
@@ -151,7 +258,7 @@ void test_buf_size_symbolic_and_offset(int s) {
 }
 int __buf_size_arg_constraint_mul(const void *, size_t, size_t);
 void test_buf_size_concrete_with_multiplication() {
-  short buf[3];         // bugpath-note{{'buf' initialized here}}
+  short buf[3];                                         // bugpath-note{{'buf' initialized here}}
   __buf_size_arg_constraint_mul(buf, 4, sizeof(short)); // \
   // report-warning{{Function argument constraint is not satisfied}} \
   // bugpath-warning{{Function argument constraint is not satisfied}} \


        


More information about the llvm-branch-commits mailing list