martong updated this revision to Diff 285682.
martong added a comment.

- Use Optionals through the Signature


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D84415/new/

https://reviews.llvm.org/D84415

Files:
  clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
  clang/test/Analysis/std-c-library-functions-POSIX.c

Index: clang/test/Analysis/std-c-library-functions-POSIX.c
===================================================================
--- clang/test/Analysis/std-c-library-functions-POSIX.c
+++ clang/test/Analysis/std-c-library-functions-POSIX.c
@@ -95,6 +95,20 @@
 // CHECK: Loaded summary for: ssize_t send(int sockfd, const void *buf, size_t len, int flags)
 // CHECK: Loaded summary for: int socketpair(int domain, int type, int protocol, int sv[2])
 // CHECK: Loaded summary for: int getnameinfo(const struct sockaddr *restrict sa, socklen_t salen, char *restrict node, socklen_t nodelen, char *restrict service, socklen_t servicelen, int flags)
+// CHECK: Loaded summary for: int pthread_cond_signal(pthread_cond_t *cond)
+// CHECK: Loaded summary for: int pthread_cond_broadcast(pthread_cond_t *cond)
+// CHECK: Loaded summary for: int pthread_create(pthread_t *restrict thread, const pthread_attr_t *restrict attr, void *(*start_routine)(void *), void *restrict arg)
+// CHECK: Loaded summary for: int pthread_attr_destroy(pthread_attr_t *attr)
+// CHECK: Loaded summary for: int pthread_attr_init(pthread_attr_t *attr)
+// CHECK: Loaded summary for: int pthread_attr_getstacksize(const pthread_attr_t *restrict attr, size_t *restrict stacksize)
+// CHECK: Loaded summary for: int pthread_attr_getguardsize(const pthread_attr_t *restrict attr, size_t *restrict guardsize)
+// CHECK: Loaded summary for: int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize)
+// CHECK: Loaded summary for: int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize)
+// CHECK: Loaded summary for: int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr)
+// CHECK: Loaded summary for: int pthread_mutex_destroy(pthread_mutex_t *mutex)
+// CHECK: Loaded summary for: int pthread_mutex_lock(pthread_mutex_t *mutex)
+// CHECK: Loaded summary for: int pthread_mutex_trylock(pthread_mutex_t *mutex)
+// CHECK: Loaded summary for: int pthread_mutex_unlock(pthread_mutex_t *mutex)
 
 long a64l(const char *str64);
 char *l64a(long value);
@@ -227,6 +241,26 @@
 int socketpair(int domain, int type, int protocol, int sv[2]);
 int getnameinfo(const struct sockaddr *restrict sa, socklen_t salen, char *restrict node, socklen_t nodelen, char *restrict service, socklen_t servicelen, int flags);
 
+typedef union { int x; } pthread_cond_t;
+int pthread_cond_signal(pthread_cond_t *cond);
+int pthread_cond_broadcast(pthread_cond_t *cond);
+typedef union { int x; } pthread_attr_t;
+typedef unsigned long int pthread_t;
+int pthread_create(pthread_t *restrict thread, const pthread_attr_t *restrict attr, void *(*start_routine)(void *), void *restrict arg);
+int pthread_attr_destroy(pthread_attr_t *attr);
+int pthread_attr_init(pthread_attr_t *attr);
+int pthread_attr_getstacksize(const pthread_attr_t *restrict attr, size_t *restrict stacksize);
+int pthread_attr_getguardsize(const pthread_attr_t *restrict attr, size_t *restrict guardsize);
+int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize);
+int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize);
+typedef union { int x; } pthread_mutex_t;
+typedef union { int x; } pthread_mutexattr_t;
+int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);
+int pthread_mutex_destroy(pthread_mutex_t *mutex);
+int pthread_mutex_lock(pthread_mutex_t *mutex);
+int pthread_mutex_trylock(pthread_mutex_t *mutex);
+int pthread_mutex_unlock(pthread_mutex_t *mutex);
+
 // Must have at least one call expression to initialize the summary map.
 int bar(void);
 void foo() {
Index: clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
+++ clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
@@ -314,7 +314,7 @@
   /// The complete list of constraints that defines a single branch.
   typedef std::vector<ValueConstraintPtr> ConstraintSet;
 
-  using ArgTypes = std::vector<QualType>;
+  using ArgTypes = std::vector<Optional<QualType>>;
 
   // A placeholder type, we use it whenever we do not care about the concrete
   // type in a Signature.
@@ -324,20 +324,45 @@
   // The signature of a function we want to describe with a summary. This is a
   // concessive signature, meaning there may be irrelevant types in the
   // signature which we do not check against a function with concrete types.
-  struct Signature {
-    ArgTypes ArgTys;
+  class Signature {
+    using ArgQualTypes = std::vector<QualType>;
+    ArgQualTypes ArgTys;
     QualType RetTy;
-    Signature(ArgTypes ArgTys, QualType RetTy) : ArgTys(ArgTys), RetTy(RetTy) {
-      assertRetTypeSuitableForSignature(RetTy);
-      for (size_t I = 0, E = ArgTys.size(); I != E; ++I) {
-        QualType ArgTy = ArgTys[I];
-        assertArgTypeSuitableForSignature(ArgTy);
+    // True if any component type is not found by lookup.
+    bool Invalid = false;
+
+  public:
+    // If any of the types is not set then the signature will be invalid.
+    Signature(ArgTypes ArgTys, Optional<QualType> RetTy) {
+      ArgQualTypes Args;
+      for (Optional<QualType> Arg : ArgTys) {
+        if (!Arg) {
+          Invalid = true;
+          return;
+        } else {
+          Args.push_back(*Arg);
+        }
+      }
+      if (!RetTy) {
+        Invalid = true;
+        return;
+      } else {
+        *this = Signature(Args, *RetTy);
       }
     }
 
+    bool isInvalid() const { return Invalid; }
     bool matches(const FunctionDecl *FD) const;
 
   private:
+    Signature(ArgQualTypes ArgTys, QualType RetTy)
+        : ArgTys(ArgTys), RetTy(RetTy) {
+      assertRetTypeSuitableForSignature(RetTy);
+      for (size_t I = 0, E = ArgTys.size(); I != E; ++I) {
+        QualType ArgTy = ArgTys[I];
+        assertArgTypeSuitableForSignature(ArgTy);
+      }
+    }
     static void assertArgTypeSuitableForSignature(QualType T) {
       assert((T.isNull() || !T->isVoidType()) &&
              "We should have no void types in the spec");
@@ -388,6 +413,9 @@
   ///   rules for the given parameter's type, those rules are checked once the
   ///   signature is matched.
   class Summary {
+    // FIXME Probably the Signature should not be part of the Summary,
+    // We can remove once all overload of addToFunctionSummaryMap requires the
+    // Signature explicitly given.
     Optional<Signature> Sign;
     const InvalidationKind InvalidationKd;
     Cases CaseConstraints;
@@ -403,6 +431,8 @@
 
     Summary(InvalidationKind InvalidationKd) : InvalidationKd(InvalidationKd) {}
 
+    // FIXME Remove, once all overload of addToFunctionSummaryMap requires the
+    // Signature explicitly given.
     Summary &setSignature(const Signature &S) {
       Sign = S;
       return *this;
@@ -438,6 +468,13 @@
       return Result;
     }
 
+    // FIXME Remove, once all overload of addToFunctionSummaryMap requires the
+    // Signature explicitly given.
+    bool hasInvalidSignature() {
+      assert(Sign && "Signature must be set before this query");
+      return Sign->isInvalid();
+    }
+
   private:
     // Once we know the exact type of the function then do sanity check on all
     // the given constraints.
@@ -778,9 +815,38 @@
   BasicValueFactory &BVF = SVB.getBasicValueFactory();
   const ASTContext &ACtx = BVF.getContext();
 
-  auto getRestrictTy = [&ACtx](QualType Ty) {
-    return ACtx.getLangOpts().C99 ? ACtx.getRestrictType(Ty) : Ty;
-  };
+  class GetRestrictTy {
+    const ASTContext &ACtx;
+
+  public:
+    GetRestrictTy(const ASTContext &ACtx) : ACtx(ACtx) {}
+    QualType operator()(QualType Ty) {
+      return ACtx.getLangOpts().C99 ? ACtx.getRestrictType(Ty) : Ty;
+    }
+    Optional<QualType> operator()(Optional<QualType> Ty) {
+      if (Ty)
+        return operator()(*Ty);
+      return None;
+    }
+  } getRestrictTy(ACtx);
+
+  class GetPointerTy {
+    const ASTContext &ACtx;
+
+  public:
+    GetPointerTy(const ASTContext &ACtx) : ACtx(ACtx) {}
+    QualType operator()(QualType Ty) { return ACtx.getPointerType(Ty); }
+    Optional<QualType> operator()(Optional<QualType> Ty) {
+      if (Ty)
+        return operator()(*Ty);
+      return None;
+    }
+    Optional<QualType> withConst(Optional<QualType> Ty) {
+      if (Ty)
+        return operator()(Ty->withConst());
+      return None;
+    }
+  } getPointerTy(ACtx);
 
   // These types are useful for writing specifications quickly,
   // New specifications should probably introduce more types.
@@ -797,21 +863,23 @@
   const QualType SizeTy = ACtx.getSizeType();
 
   const QualType VoidPtrTy = ACtx.VoidPtrTy; // void *
-  const QualType IntPtrTy = ACtx.getPointerType(IntTy); // int *
+  const QualType IntPtrTy = getPointerTy(IntTy); // int *
   const QualType UnsignedIntPtrTy =
-      ACtx.getPointerType(UnsignedIntTy); // unsigned int *
+      getPointerTy(UnsignedIntTy); // unsigned int *
   const QualType VoidPtrRestrictTy = getRestrictTy(VoidPtrTy);
   const QualType ConstVoidPtrTy =
-      ACtx.getPointerType(ACtx.VoidTy.withConst()); // const void *
-  const QualType CharPtrTy = ACtx.getPointerType(ACtx.CharTy); // char *
+      getPointerTy(ACtx.VoidTy.withConst());            // const void *
+  const QualType CharPtrTy = getPointerTy(ACtx.CharTy); // char *
   const QualType CharPtrRestrictTy = getRestrictTy(CharPtrTy);
   const QualType ConstCharPtrTy =
-      ACtx.getPointerType(ACtx.CharTy.withConst()); // const char *
+      getPointerTy(ACtx.CharTy.withConst()); // const char *
   const QualType ConstCharPtrRestrictTy = getRestrictTy(ConstCharPtrTy);
-  const QualType Wchar_tPtrTy = ACtx.getPointerType(ACtx.WCharTy); // wchar_t *
+  const QualType Wchar_tPtrTy = getPointerTy(ACtx.WCharTy); // wchar_t *
   const QualType ConstWchar_tPtrTy =
-      ACtx.getPointerType(ACtx.WCharTy.withConst()); // const wchar_t *
+      getPointerTy(ACtx.WCharTy.withConst()); // const wchar_t *
   const QualType ConstVoidPtrRestrictTy = getRestrictTy(ConstVoidPtrTy);
+  const QualType SizePtrTy = getPointerTy(SizeTy);
+  const QualType SizePtrRestrictTy = getRestrictTy(SizePtrTy);
 
   const RangeInt IntMax = BVF.getMaxValue(IntTy).getLimitedValue();
   const RangeInt UnsignedIntMax =
@@ -853,7 +921,10 @@
     // to the found FunctionDecl only if the signatures match.
     //
     // Returns true if the summary has been added, false otherwise.
+    // FIXME remove all overloads without the explicit Signature parameter.
     bool operator()(StringRef Name, Summary S) {
+      if (S.hasInvalidSignature())
+        return false;
       IdentifierInfo &II = ACtx.Idents.get(Name);
       auto LookupRes = ACtx.getTranslationUnitDecl()->lookup(&II);
       if (LookupRes.size() == 0)
@@ -875,6 +946,7 @@
       }
       return false;
     }
+    // Add the summary with the Signature explicitly given.
     bool operator()(StringRef Name, Signature Sign, Summary Sum) {
       return operator()(Name, Sum.setSignature(Sign));
     }
@@ -883,6 +955,17 @@
       for (const Summary &S : Summaries)
         operator()(Name, S);
     }
+    // Add the same summary for different names.
+    void operator()(std::vector<StringRef> Names, Summary S) {
+      for (StringRef Name : Names)
+        operator()(Name, S);
+    }
+    // Add the same summary for different names with the Signature explicitly
+    // given.
+    void operator()(std::vector<StringRef> Names, Signature Sign, Summary Sum) {
+      for (StringRef Name : Names)
+        operator()(Name, Sign, Sum);
+    }
   } addToFunctionSummaryMap(ACtx, FunctionSummaryMap, DisplayLoadedSummaries);
 
   // We are finally ready to define specifications for all supported functions.
@@ -942,7 +1025,7 @@
   Optional<QualType> FilePtrTy, FilePtrRestrictTy;
   if (FileTy) {
     // FILE *
-    FilePtrTy = ACtx.getPointerType(*FileTy);
+    FilePtrTy = getPointerTy(*FileTy);
     // FILE *restrict
     FilePtrRestrictTy = getRestrictTy(*FilePtrTy);
   }
@@ -1262,7 +1345,7 @@
     Optional<QualType> DirTy = lookupType("DIR", ACtx);
     Optional<QualType> DirPtrTy;
     if (DirTy)
-      DirPtrTy = ACtx.getPointerType(*DirTy);
+      DirPtrTy = getPointerTy(*DirTy);
 
     if (DirPtrTy)
       // int dirfd(DIR *dirp);
@@ -1449,7 +1532,7 @@
     Optional<QualType> StructStatTy = lookupType("stat", ACtx);
     Optional<QualType> StructStatPtrTy, StructStatPtrRestrictTy;
     if (StructStatTy) {
-      StructStatPtrTy = ACtx.getPointerType(*StructStatTy);
+      StructStatPtrTy = getPointerTy(*StructStatTy);
       StructStatPtrRestrictTy = getRestrictTy(*StructStatPtrTy);
     }
 
@@ -1694,7 +1777,7 @@
                             RetType{CharPtrTy}, NoEvalCall)
                         .ArgConstraint(NotNull(ArgNo(0))));
 
-    QualType CharPtrConstPtr = ACtx.getPointerType(CharPtrTy.withConst());
+    QualType CharPtrConstPtr = getPointerTy(CharPtrTy.withConst());
 
     // int execv(const char *path, char *const argv[]);
     addToFunctionSummaryMap("execv",
@@ -1721,9 +1804,8 @@
     Optional<QualType> StructSockaddrPtrTy, ConstStructSockaddrPtrTy,
         StructSockaddrPtrRestrictTy, ConstStructSockaddrPtrRestrictTy;
     if (StructSockaddrTy) {
-      StructSockaddrPtrTy = ACtx.getPointerType(*StructSockaddrTy);
-      ConstStructSockaddrPtrTy =
-          ACtx.getPointerType(StructSockaddrTy->withConst());
+      StructSockaddrPtrTy = getPointerTy(*StructSockaddrTy);
+      ConstStructSockaddrPtrTy = getPointerTy(StructSockaddrTy->withConst());
       StructSockaddrPtrRestrictTy = getRestrictTy(*StructSockaddrPtrTy);
       ConstStructSockaddrPtrRestrictTy =
           getRestrictTy(*ConstStructSockaddrPtrTy);
@@ -1733,7 +1815,7 @@
     Optional<RangeInt> Socklen_tMax;
     if (Socklen_tTy) {
       Socklen_tMax = BVF.getMaxValue(*Socklen_tTy).getLimitedValue();
-      Socklen_tPtrTy = ACtx.getPointerType(*Socklen_tTy);
+      Socklen_tPtrTy = getPointerTy(*Socklen_tTy);
       Socklen_tPtrRestrictTy = getRestrictTy(*Socklen_tPtrTy);
     }
 
@@ -1900,8 +1982,8 @@
     Optional<QualType> StructMsghdrTy = lookupType("msghdr", ACtx);
     Optional<QualType> StructMsghdrPtrTy, ConstStructMsghdrPtrTy;
     if (StructMsghdrTy) {
-      StructMsghdrPtrTy = ACtx.getPointerType(*StructMsghdrTy);
-      ConstStructMsghdrPtrTy = ACtx.getPointerType(StructMsghdrTy->withConst());
+      StructMsghdrPtrTy = getPointerTy(*StructMsghdrTy);
+      ConstStructMsghdrPtrTy = getPointerTy(StructMsghdrTy->withConst());
     }
 
     if (Ssize_tTy && StructMsghdrPtrTy)
@@ -1986,6 +2068,100 @@
                   BufferSize(/*Buffer=*/ArgNo(4), /*BufSize=*/ArgNo(5)))
               .ArgConstraint(
                   ArgumentCondition(5, WithinRange, Range(0, *Socklen_tMax))));
+
+    Optional<QualType> Pthread_cond_tTy = lookupType("pthread_cond_t", ACtx);
+    Optional<QualType> Pthread_cond_tPtrTy = getPointerTy(Pthread_cond_tTy);
+    Optional<QualType> Pthread_tTy = lookupType("pthread_t", ACtx);
+    Optional<QualType> Pthread_tPtrTy = getPointerTy(Pthread_tTy);
+    Optional<QualType> Pthread_tPtrRestrictTy = getRestrictTy(Pthread_tPtrTy);
+    Optional<QualType> Pthread_mutex_tTy = lookupType("pthread_mutex_t", ACtx);
+    Optional<QualType> Pthread_mutex_tPtrTy = getPointerTy(Pthread_mutex_tTy);
+    Optional<QualType> Pthread_mutex_tPtrRestrictTy =
+        getRestrictTy(Pthread_mutex_tPtrTy);
+    Optional<QualType> Pthread_attr_tTy = lookupType("pthread_attr_t", ACtx);
+    Optional<QualType> Pthread_attr_tPtrTy = getPointerTy(Pthread_attr_tTy);
+    Optional<QualType> ConstPthread_attr_tPtrTy =
+        getPointerTy.withConst(Pthread_attr_tTy);
+    Optional<QualType> ConstPthread_attr_tPtrRestrictTy =
+        getRestrictTy(ConstPthread_attr_tPtrTy);
+    Optional<QualType> Pthread_mutexattr_tTy =
+        lookupType("pthread_mutexattr_t", ACtx);
+    Optional<QualType> ConstPthread_mutexattr_tPtrTy =
+        getPointerTy.withConst(Pthread_mutexattr_tTy);
+    Optional<QualType> ConstPthread_mutexattr_tPtrRestrictTy =
+        getRestrictTy(ConstPthread_mutexattr_tPtrTy);
+
+    QualType PthreadStartRoutineTy = getPointerTy(
+        ACtx.getFunctionType(/*ResultTy=*/VoidPtrTy, /*Args=*/VoidPtrTy,
+                             FunctionProtoType::ExtProtoInfo()));
+
+    // int pthread_cond_signal(pthread_cond_t *cond);
+    // int pthread_cond_broadcast(pthread_cond_t *cond);
+    addToFunctionSummaryMap(
+        {"pthread_cond_signal", "pthread_cond_broadcast"},
+        Signature(ArgTypes{Pthread_cond_tPtrTy}, RetType{IntTy}),
+        Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
+
+    // int pthread_create(pthread_t *restrict thread,
+    //                    const pthread_attr_t *restrict attr,
+    //                    void *(*start_routine)(void*), void *restrict arg);
+    addToFunctionSummaryMap(
+        "pthread_create",
+        Signature(ArgTypes{Pthread_tPtrRestrictTy,
+                           ConstPthread_attr_tPtrRestrictTy,
+                           PthreadStartRoutineTy, VoidPtrRestrictTy},
+                  RetType{IntTy}),
+        Summary(NoEvalCall)
+            .ArgConstraint(NotNull(ArgNo(0)))
+            .ArgConstraint(NotNull(ArgNo(2))));
+
+    // int pthread_attr_destroy(pthread_attr_t *attr);
+    // int pthread_attr_init(pthread_attr_t *attr);
+    addToFunctionSummaryMap(
+        {"pthread_attr_destroy", "pthread_attr_init"},
+        Signature(ArgTypes{Pthread_attr_tPtrTy}, RetType{IntTy}),
+        Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
+
+    // int pthread_attr_getstacksize(const pthread_attr_t *restrict attr,
+    //                               size_t *restrict stacksize);
+    // int pthread_attr_getguardsize(const pthread_attr_t *restrict attr,
+    //                               size_t *restrict guardsize);
+    addToFunctionSummaryMap(
+        {"pthread_attr_getstacksize", "pthread_attr_getguardsize"},
+        Signature(ArgTypes{ConstPthread_attr_tPtrRestrictTy, SizePtrRestrictTy},
+                  RetType{IntTy}),
+        Summary(NoEvalCall)
+            .ArgConstraint(NotNull(ArgNo(0)))
+            .ArgConstraint(NotNull(ArgNo(1))));
+
+    // int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize);
+    // int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize);
+    addToFunctionSummaryMap(
+        {"pthread_attr_setstacksize", "pthread_attr_setguardsize"},
+        Signature(ArgTypes{Pthread_attr_tPtrTy, SizeTy}, RetType{IntTy}),
+        Summary(NoEvalCall)
+            .ArgConstraint(NotNull(ArgNo(0)))
+            .ArgConstraint(
+                ArgumentCondition(1, WithinRange, Range(0, SizeMax))));
+
+    // int pthread_mutex_init(pthread_mutex_t *restrict mutex, const
+    //                        pthread_mutexattr_t *restrict attr);
+    addToFunctionSummaryMap(
+        "pthread_mutex_init",
+        Signature(ArgTypes{Pthread_mutex_tPtrRestrictTy,
+                           ConstPthread_mutexattr_tPtrRestrictTy},
+                  RetType{IntTy}),
+        Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
+
+    // int pthread_mutex_destroy(pthread_mutex_t *mutex);
+    // int pthread_mutex_lock(pthread_mutex_t *mutex);
+    // int pthread_mutex_trylock(pthread_mutex_t *mutex);
+    // int pthread_mutex_unlock(pthread_mutex_t *mutex);
+    addToFunctionSummaryMap(
+        {"pthread_mutex_destroy", "pthread_mutex_lock", "pthread_mutex_trylock",
+         "pthread_mutex_unlock"},
+        Signature(ArgTypes{Pthread_mutex_tPtrTy}, RetType{IntTy}),
+        Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
   }
 
   // Functions for testing.
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to