[clang] 3ff220d - [analyzer][StdLibraryFunctionsChecker] Add POSIX networking functions

Gabor Marton via cfe-commits cfe-commits at lists.llvm.org
Mon Jul 20 13:47:06 PDT 2020


Author: Gabor Marton
Date: 2020-07-20T22:46:24+02:00
New Revision: 3ff220de900970a20c9882b7199c178c6b6428b2

URL: https://github.com/llvm/llvm-project/commit/3ff220de900970a20c9882b7199c178c6b6428b2
DIFF: https://github.com/llvm/llvm-project/commit/3ff220de900970a20c9882b7199c178c6b6428b2.diff

LOG: [analyzer][StdLibraryFunctionsChecker] Add POSIX networking functions

Summary:
Adding networking functions from the POSIX standard (2017). This includes
functions that deal with sockets from socket.h, netdb.h.

In 'socket.h' of some libc implementations (e.g. glibc) with C99, sockaddr
parameter is a transparent union of the underlying sockaddr_ family of pointers
instead of being a pointer to struct sockaddr. In these cases, the standardized
signature will not match, thus we try to match with another signature that has
the joker Irrelevant type. In the case of transparent unions, we also not add
those constraints which require pointer types for the sockaddr param.

Interestingly, in 'netdb.h' sockaddr is not handled as a transparent union.

Tags: #clang

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

Added: 
    clang/test/Analysis/std-c-library-functions-POSIX-socket-sockaddr.cpp

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

Removed: 
    


################################################################################
diff  --git a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
index 8b575f4f4759..e437c33bd81a 100644
--- a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
@@ -302,6 +302,13 @@ class StdLibraryFunctionsChecker
       Tmp.Op = BinaryOperator::negateComparisonOp(Op);
       return std::make_shared<BufferSizeConstraint>(Tmp);
     }
+
+    bool checkSpecificValidity(const FunctionDecl *FD) const override {
+      const bool ValidArg = getArgType(FD, ArgN)->isPointerType();
+      assert(ValidArg &&
+             "This constraint should be applied only on a pointer type");
+      return ValidArg;
+    }
   };
 
   /// The complete list of constraints that defines a single branch.
@@ -318,8 +325,8 @@ class StdLibraryFunctionsChecker
   // concessive signature, meaning there may be irrelevant types in the
   // signature which we do not check against a function with concrete types.
   struct Signature {
-    const ArgTypes ArgTys;
-    const QualType RetTy;
+    ArgTypes 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) {
@@ -327,6 +334,7 @@ class StdLibraryFunctionsChecker
         assertArgTypeSuitableForSignature(ArgTy);
       }
     }
+
     bool matches(const FunctionDecl *FD) const;
 
   private:
@@ -380,7 +388,7 @@ class StdLibraryFunctionsChecker
   ///   rules for the given parameter's type, those rules are checked once the
   ///   signature is matched.
   class Summary {
-    const Signature Sign;
+    Optional<Signature> Sign;
     const InvalidationKind InvalidationKd;
     Cases CaseConstraints;
     ConstraintSet ArgConstraints;
@@ -391,7 +399,14 @@ class StdLibraryFunctionsChecker
 
   public:
     Summary(ArgTypes ArgTys, QualType RetTy, InvalidationKind InvalidationKd)
-        : Sign(ArgTys, RetTy), InvalidationKd(InvalidationKd) {}
+        : Sign(Signature(ArgTys, RetTy)), InvalidationKd(InvalidationKd) {}
+
+    Summary(InvalidationKind InvalidationKd) : InvalidationKd(InvalidationKd) {}
+
+    Summary &setSignature(const Signature &S) {
+      Sign = S;
+      return *this;
+    }
 
     Summary &Case(ConstraintSet&& CS) {
       CaseConstraints.push_back(std::move(CS));
@@ -413,7 +428,9 @@ class StdLibraryFunctionsChecker
     // Returns true if the summary should be applied to the given function.
     // And if yes then store the function declaration.
     bool matchesAndSet(const FunctionDecl *FD) {
-      bool Result = Sign.matches(FD) && validateByConstraints(FD);
+      assert(Sign &&
+             "Signature must be set before comparing to a FunctionDecl");
+      bool Result = Sign->matches(FD) && validateByConstraints(FD);
       if (Result) {
         assert(!this->FD && "FD must not be set more than once");
         this->FD = FD;
@@ -761,6 +778,10 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
   BasicValueFactory &BVF = SVB.getBasicValueFactory();
   const ASTContext &ACtx = BVF.getContext();
 
+  auto getRestrictTy = [&ACtx](QualType Ty) {
+    return ACtx.getLangOpts().C99 ? ACtx.getRestrictType(Ty) : Ty;
+  };
+
   // These types are useful for writing specifications quickly,
   // New specifications should probably introduce more types.
   // Some types are hard to obtain from the AST, eg. "ssize_t".
@@ -779,28 +800,18 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
   const QualType IntPtrTy = ACtx.getPointerType(IntTy); // int *
   const QualType UnsignedIntPtrTy =
       ACtx.getPointerType(UnsignedIntTy); // unsigned int *
-  const QualType VoidPtrRestrictTy =
-      ACtx.getLangOpts().C99 ? ACtx.getRestrictType(VoidPtrTy) // void *restrict
-                             : VoidPtrTy;
+  const QualType VoidPtrRestrictTy = getRestrictTy(VoidPtrTy);
   const QualType ConstVoidPtrTy =
       ACtx.getPointerType(ACtx.VoidTy.withConst()); // const void *
   const QualType CharPtrTy = ACtx.getPointerType(ACtx.CharTy); // char *
-  const QualType CharPtrRestrictTy =
-      ACtx.getLangOpts().C99 ? ACtx.getRestrictType(CharPtrTy) // char *restrict
-                             : CharPtrTy;
+  const QualType CharPtrRestrictTy = getRestrictTy(CharPtrTy);
   const QualType ConstCharPtrTy =
       ACtx.getPointerType(ACtx.CharTy.withConst()); // const char *
-  const QualType ConstCharPtrRestrictTy =
-      ACtx.getLangOpts().C99
-          ? ACtx.getRestrictType(ConstCharPtrTy) // const char *restrict
-          : ConstCharPtrTy;
+  const QualType ConstCharPtrRestrictTy = getRestrictTy(ConstCharPtrTy);
   const QualType Wchar_tPtrTy = ACtx.getPointerType(ACtx.WCharTy); // wchar_t *
   const QualType ConstWchar_tPtrTy =
       ACtx.getPointerType(ACtx.WCharTy.withConst()); // const wchar_t *
-  const QualType ConstVoidPtrRestrictTy =
-      ACtx.getLangOpts().C99
-          ? ACtx.getRestrictType(ConstVoidPtrTy) // const void *restrict
-          : ConstVoidPtrTy;
+  const QualType ConstVoidPtrRestrictTy = getRestrictTy(ConstVoidPtrTy);
 
   const RangeInt IntMax = BVF.getMaxValue(IntTy).getLimitedValue();
   const RangeInt UnsignedIntMax =
@@ -840,11 +851,13 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
     // Add a summary to a FunctionDecl found by lookup. The lookup is performed
     // by the given Name, and in the global scope. The summary will be attached
     // to the found FunctionDecl only if the signatures match.
-    void operator()(StringRef Name, Summary S) {
+    //
+    // Returns true if the summary has been added, false otherwise.
+    bool operator()(StringRef Name, Summary S) {
       IdentifierInfo &II = ACtx.Idents.get(Name);
       auto LookupRes = ACtx.getTranslationUnitDecl()->lookup(&II);
       if (LookupRes.size() == 0)
-        return;
+        return false;
       for (Decl *D : LookupRes) {
         if (auto *FD = dyn_cast<FunctionDecl>(D)) {
           if (S.matchesAndSet(FD)) {
@@ -856,10 +869,14 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
               FD->print(llvm::errs());
               llvm::errs() << "\n";
             }
-            return;
+            return true;
           }
         }
       }
+      return false;
+    }
+    bool operator()(StringRef Name, Signature Sign, Summary Sum) {
+      return operator()(Name, Sum.setSignature(Sign));
     }
     // Add several summaries for the given name.
     void operator()(StringRef Name, const std::vector<Summary> &Summaries) {
@@ -927,8 +944,7 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
     // FILE *
     FilePtrTy = ACtx.getPointerType(*FileTy);
     // FILE *restrict
-    FilePtrRestrictTy =
-        ACtx.getLangOpts().C99 ? ACtx.getRestrictType(*FilePtrTy) : *FilePtrTy;
+    FilePtrRestrictTy = getRestrictTy(*FilePtrTy);
   }
 
   using RetType = QualType;
@@ -1434,9 +1450,7 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
     Optional<QualType> StructStatPtrTy, StructStatPtrRestrictTy;
     if (StructStatTy) {
       StructStatPtrTy = ACtx.getPointerType(*StructStatTy);
-      StructStatPtrRestrictTy = ACtx.getLangOpts().C99
-                                    ? ACtx.getRestrictType(*StructStatPtrTy)
-                                    : *StructStatPtrTy;
+      StructStatPtrRestrictTy = getRestrictTy(*StructStatPtrTy);
     }
 
     if (StructStatPtrTy)
@@ -1702,6 +1716,276 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
             .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
             .ArgConstraint(NotNull(ArgNo(1)))
             .ArgConstraint(NotNull(ArgNo(2))));
+
+    Optional<QualType> StructSockaddrTy = lookupType("sockaddr", ACtx);
+    Optional<QualType> StructSockaddrPtrTy, ConstStructSockaddrPtrTy,
+        StructSockaddrPtrRestrictTy, ConstStructSockaddrPtrRestrictTy;
+    if (StructSockaddrTy) {
+      StructSockaddrPtrTy = ACtx.getPointerType(*StructSockaddrTy);
+      ConstStructSockaddrPtrTy =
+          ACtx.getPointerType(StructSockaddrTy->withConst());
+      StructSockaddrPtrRestrictTy = getRestrictTy(*StructSockaddrPtrTy);
+      ConstStructSockaddrPtrRestrictTy =
+          getRestrictTy(*ConstStructSockaddrPtrTy);
+    }
+    Optional<QualType> Socklen_tTy = lookupType("socklen_t", ACtx);
+    Optional<QualType> Socklen_tPtrTy, Socklen_tPtrRestrictTy;
+    Optional<RangeInt> Socklen_tMax;
+    if (Socklen_tTy) {
+      Socklen_tMax = BVF.getMaxValue(*Socklen_tTy).getLimitedValue();
+      Socklen_tPtrTy = ACtx.getPointerType(*Socklen_tTy);
+      Socklen_tPtrRestrictTy = getRestrictTy(*Socklen_tPtrTy);
+    }
+
+    // In 'socket.h' of some libc implementations with C99, sockaddr parameter
+    // is a transparent union of the underlying sockaddr_ family of pointers
+    // instead of being a pointer to struct sockaddr. In these cases, the
+    // standardized signature will not match, thus we try to match with another
+    // signature that has the joker Irrelevant type. We also remove those
+    // constraints which require pointer types for the sockaddr param.
+    if (StructSockaddrPtrRestrictTy && Socklen_tPtrRestrictTy) {
+      auto Accept = Summary(NoEvalCall)
+                        .ArgConstraint(ArgumentCondition(0, WithinRange,
+                                                         Range(0, IntMax)));
+      if (!addToFunctionSummaryMap(
+              "accept",
+              // int accept(int socket, struct sockaddr *restrict address,
+              //            socklen_t *restrict address_len);
+              Signature(ArgTypes{IntTy, *StructSockaddrPtrRestrictTy,
+                                 *Socklen_tPtrRestrictTy},
+                        RetType{IntTy}),
+              Accept))
+        addToFunctionSummaryMap(
+            "accept",
+            Signature(ArgTypes{IntTy, Irrelevant, *Socklen_tPtrRestrictTy},
+                      RetType{IntTy}),
+            Accept);
+
+      // int bind(int socket, const struct sockaddr *address, socklen_t
+      //          address_len);
+      if (!addToFunctionSummaryMap(
+              "bind",
+              Summary(ArgTypes{IntTy, *ConstStructSockaddrPtrTy, *Socklen_tTy},
+                      RetType{IntTy}, NoEvalCall)
+                  .ArgConstraint(
+                      ArgumentCondition(0, WithinRange, Range(0, IntMax)))
+                  .ArgConstraint(NotNull(ArgNo(1)))
+                  .ArgConstraint(
+                      BufferSize(/*Buffer=*/ArgNo(1), /*BufSize=*/ArgNo(2)))
+                  .ArgConstraint(ArgumentCondition(2, WithinRange,
+                                                   Range(0, *Socklen_tMax)))))
+        // Do not add constraints on sockaddr.
+        addToFunctionSummaryMap(
+            "bind", Summary(ArgTypes{IntTy, Irrelevant, *Socklen_tTy},
+                            RetType{IntTy}, NoEvalCall)
+                        .ArgConstraint(
+                            ArgumentCondition(0, WithinRange, Range(0, IntMax)))
+                        .ArgConstraint(ArgumentCondition(
+                            2, WithinRange, Range(0, *Socklen_tMax))));
+
+      // int getpeername(int socket, struct sockaddr *restrict address,
+      //                 socklen_t *restrict address_len);
+      if (!addToFunctionSummaryMap(
+              "getpeername",
+              Summary(ArgTypes{IntTy, *StructSockaddrPtrRestrictTy,
+                               *Socklen_tPtrRestrictTy},
+                      RetType{IntTy}, NoEvalCall)
+                  .ArgConstraint(
+                      ArgumentCondition(0, WithinRange, Range(0, IntMax)))
+                  .ArgConstraint(NotNull(ArgNo(1)))
+                  .ArgConstraint(NotNull(ArgNo(2)))))
+        addToFunctionSummaryMap(
+            "getpeername",
+            Summary(ArgTypes{IntTy, Irrelevant, *Socklen_tPtrRestrictTy},
+                    RetType{IntTy}, NoEvalCall)
+                .ArgConstraint(
+                    ArgumentCondition(0, WithinRange, Range(0, IntMax))));
+
+      // int getsockname(int socket, struct sockaddr *restrict address,
+      //                 socklen_t *restrict address_len);
+      if (!addToFunctionSummaryMap(
+              "getsockname",
+              Summary(ArgTypes{IntTy, *StructSockaddrPtrRestrictTy,
+                               *Socklen_tPtrRestrictTy},
+                      RetType{IntTy}, NoEvalCall)
+                  .ArgConstraint(
+                      ArgumentCondition(0, WithinRange, Range(0, IntMax)))
+                  .ArgConstraint(NotNull(ArgNo(1)))
+                  .ArgConstraint(NotNull(ArgNo(2)))))
+        addToFunctionSummaryMap(
+            "getsockname",
+            Summary(ArgTypes{IntTy, Irrelevant, *Socklen_tPtrRestrictTy},
+                    RetType{IntTy}, NoEvalCall)
+                .ArgConstraint(
+                    ArgumentCondition(0, WithinRange, Range(0, IntMax))));
+
+      // int connect(int socket, const struct sockaddr *address, socklen_t
+      //             address_len);
+      if (!addToFunctionSummaryMap(
+              "connect",
+              Summary(ArgTypes{IntTy, *ConstStructSockaddrPtrTy, *Socklen_tTy},
+                      RetType{IntTy}, NoEvalCall)
+                  .ArgConstraint(
+                      ArgumentCondition(0, WithinRange, Range(0, IntMax)))
+                  .ArgConstraint(NotNull(ArgNo(1)))))
+        addToFunctionSummaryMap(
+            "connect", Summary(ArgTypes{IntTy, Irrelevant, *Socklen_tTy},
+                               RetType{IntTy}, NoEvalCall)
+                           .ArgConstraint(ArgumentCondition(0, WithinRange,
+                                                            Range(0, IntMax))));
+
+      auto Recvfrom = Summary(NoEvalCall)
+                          .ArgConstraint(ArgumentCondition(0, WithinRange,
+                                                           Range(0, IntMax)))
+                          .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
+                                                    /*BufSize=*/ArgNo(2)));
+      if (Ssize_tTy &&
+          !addToFunctionSummaryMap(
+              "recvfrom",
+              // ssize_t recvfrom(int socket, void *restrict buffer,
+              //                  size_t length,
+              //                  int flags, struct sockaddr *restrict address,
+              //                  socklen_t *restrict address_len);
+              Signature(ArgTypes{IntTy, VoidPtrRestrictTy, SizeTy, IntTy,
+                                 *StructSockaddrPtrRestrictTy,
+                                 *Socklen_tPtrRestrictTy},
+                        RetType{*Ssize_tTy}),
+              Recvfrom))
+        addToFunctionSummaryMap(
+            "recvfrom",
+            Signature(ArgTypes{IntTy, VoidPtrRestrictTy, SizeTy, IntTy,
+                               Irrelevant, *Socklen_tPtrRestrictTy},
+                      RetType{*Ssize_tTy}),
+            Recvfrom);
+
+      auto Sendto = Summary(NoEvalCall)
+                        .ArgConstraint(
+                            ArgumentCondition(0, WithinRange, Range(0, IntMax)))
+                        .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
+                                                  /*BufSize=*/ArgNo(2)));
+      if (Ssize_tTy &&
+          !addToFunctionSummaryMap(
+              "sendto",
+              // ssize_t sendto(int socket, const void *message, size_t length,
+              //                int flags, const struct sockaddr *dest_addr,
+              //                socklen_t dest_len);
+              Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTy, IntTy,
+                                 *ConstStructSockaddrPtrTy, *Socklen_tTy},
+                        RetType{*Ssize_tTy}),
+              Sendto))
+        addToFunctionSummaryMap(
+            "sendto",
+            Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTy, IntTy, Irrelevant,
+                               *Socklen_tTy},
+                      RetType{*Ssize_tTy}),
+            Sendto);
+    }
+
+    // int listen(int sockfd, int backlog);
+    addToFunctionSummaryMap(
+        "listen", Summary(ArgTypes{IntTy, IntTy}, RetType{IntTy}, NoEvalCall)
+                      .ArgConstraint(
+                          ArgumentCondition(0, WithinRange, Range(0, IntMax))));
+
+    if (Ssize_tTy)
+      // ssize_t recv(int sockfd, void *buf, size_t len, int flags);
+      addToFunctionSummaryMap(
+          "recv", Summary(ArgTypes{IntTy, VoidPtrTy, SizeTy, IntTy},
+                          RetType{*Ssize_tTy}, NoEvalCall)
+                      .ArgConstraint(
+                          ArgumentCondition(0, WithinRange, Range(0, IntMax)))
+                      .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
+                                                /*BufSize=*/ArgNo(2))));
+
+    Optional<QualType> StructMsghdrTy = lookupType("msghdr", ACtx);
+    Optional<QualType> StructMsghdrPtrTy, ConstStructMsghdrPtrTy;
+    if (StructMsghdrTy) {
+      StructMsghdrPtrTy = ACtx.getPointerType(*StructMsghdrTy);
+      ConstStructMsghdrPtrTy = ACtx.getPointerType(StructMsghdrTy->withConst());
+    }
+
+    if (Ssize_tTy && StructMsghdrPtrTy)
+      // ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);
+      addToFunctionSummaryMap(
+          "recvmsg", Summary(ArgTypes{IntTy, *StructMsghdrPtrTy, IntTy},
+                             RetType{*Ssize_tTy}, NoEvalCall)
+                         .ArgConstraint(ArgumentCondition(0, WithinRange,
+                                                          Range(0, IntMax))));
+
+    if (Ssize_tTy && ConstStructMsghdrPtrTy)
+      // ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
+      addToFunctionSummaryMap(
+          "sendmsg", Summary(ArgTypes{IntTy, *ConstStructMsghdrPtrTy, IntTy},
+                             RetType{*Ssize_tTy}, NoEvalCall)
+                         .ArgConstraint(ArgumentCondition(0, WithinRange,
+                                                          Range(0, IntMax))));
+
+    if (Socklen_tTy)
+      // int setsockopt(int socket, int level, int option_name,
+      //                const void *option_value, socklen_t option_len);
+      addToFunctionSummaryMap(
+          "setsockopt",
+          Summary(ArgTypes{IntTy, IntTy, IntTy, ConstVoidPtrTy, *Socklen_tTy},
+                  RetType{IntTy}, NoEvalCall)
+              .ArgConstraint(NotNull(ArgNo(3)))
+              .ArgConstraint(
+                  BufferSize(/*Buffer=*/ArgNo(3), /*BufSize=*/ArgNo(4)))
+              .ArgConstraint(
+                  ArgumentCondition(4, WithinRange, Range(0, *Socklen_tMax))));
+
+    if (Socklen_tPtrRestrictTy)
+      // int getsockopt(int socket, int level, int option_name,
+      //                void *restrict option_value,
+      //                socklen_t *restrict option_len);
+      addToFunctionSummaryMap(
+          "getsockopt", Summary(ArgTypes{IntTy, IntTy, IntTy, VoidPtrRestrictTy,
+                                         *Socklen_tPtrRestrictTy},
+                                RetType{IntTy}, NoEvalCall)
+                            .ArgConstraint(NotNull(ArgNo(3)))
+                            .ArgConstraint(NotNull(ArgNo(4))));
+
+    if (Ssize_tTy)
+      // ssize_t send(int sockfd, const void *buf, size_t len, int flags);
+      addToFunctionSummaryMap(
+          "send", Summary(ArgTypes{IntTy, ConstVoidPtrTy, SizeTy, IntTy},
+                          RetType{*Ssize_tTy}, NoEvalCall)
+                      .ArgConstraint(
+                          ArgumentCondition(0, WithinRange, Range(0, IntMax)))
+                      .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
+                                                /*BufSize=*/ArgNo(2))));
+
+    // int socketpair(int domain, int type, int protocol, int sv[2]);
+    addToFunctionSummaryMap("socketpair",
+                            Summary(ArgTypes{IntTy, IntTy, IntTy, IntPtrTy},
+                                    RetType{IntTy}, NoEvalCall)
+                                .ArgConstraint(NotNull(ArgNo(3))));
+
+    if (ConstStructSockaddrPtrRestrictTy && Socklen_tTy)
+      // int getnameinfo(const struct sockaddr *restrict sa, socklen_t salen,
+      //                 char *restrict node, socklen_t nodelen,
+      //                 char *restrict service,
+      //                 socklen_t servicelen, int flags);
+      //
+      // This is defined in netdb.h. And contrary to 'socket.h', the sockaddr
+      // parameter is never handled as a transparent union in netdb.h
+      addToFunctionSummaryMap(
+          "getnameinfo",
+          Summary(ArgTypes{*ConstStructSockaddrPtrRestrictTy, *Socklen_tTy,
+                           CharPtrRestrictTy, *Socklen_tTy, CharPtrRestrictTy,
+                           *Socklen_tTy, IntTy},
+                  RetType{IntTy}, NoEvalCall)
+              .ArgConstraint(
+                  BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1)))
+              .ArgConstraint(
+                  ArgumentCondition(1, WithinRange, Range(0, *Socklen_tMax)))
+              .ArgConstraint(
+                  BufferSize(/*Buffer=*/ArgNo(2), /*BufSize=*/ArgNo(3)))
+              .ArgConstraint(
+                  ArgumentCondition(3, WithinRange, Range(0, *Socklen_tMax)))
+              .ArgConstraint(
+                  BufferSize(/*Buffer=*/ArgNo(4), /*BufSize=*/ArgNo(5)))
+              .ArgConstraint(
+                  ArgumentCondition(5, WithinRange, Range(0, *Socklen_tMax))));
   }
 
   // Functions for testing.

diff  --git a/clang/test/Analysis/std-c-library-functions-POSIX-socket-sockaddr.cpp b/clang/test/Analysis/std-c-library-functions-POSIX-socket-sockaddr.cpp
new file mode 100644
index 000000000000..a35bb5cdc3a0
--- /dev/null
+++ b/clang/test/Analysis/std-c-library-functions-POSIX-socket-sockaddr.cpp
@@ -0,0 +1,37 @@
+// RUN: %clang_analyze_cc1 %s \
+// RUN:   -analyzer-checker=core \
+// RUN:   -analyzer-checker=apiModeling.StdCLibraryFunctions \
+// RUN:   -analyzer-config apiModeling.StdCLibraryFunctions:ModelPOSIX=true \
+// RUN:   -analyzer-config apiModeling.StdCLibraryFunctions:DisplayLoadedSummaries=true \
+// RUN:   -analyzer-checker=debug.ExprInspection \
+// RUN:   -analyzer-config eagerly-assume=false \
+// RUN:   -triple i686-unknown-linux 2>&1 | FileCheck %s
+
+// We test here that functions from socket.h are added when sockaddr is not a
+// transparent union of other sockaddr_ pointers. This is the case in C++.
+
+// CHECK: Loaded summary for: int accept(int socket, struct sockaddr *address, socklen_t *address_len)
+// CHECK: Loaded summary for: int bind(int socket, const struct sockaddr *address, socklen_t address_len)
+// CHECK: Loaded summary for: int getpeername(int socket, struct sockaddr *address, socklen_t *address_len)
+// CHECK: Loaded summary for: int getsockname(int socket, struct sockaddr *address, socklen_t *address_len)
+// CHECK: Loaded summary for: int connect(int socket, const struct sockaddr *address, socklen_t address_len)
+// CHECK: Loaded summary for: ssize_t recvfrom(int socket, void *buffer, size_t length, int flags, struct sockaddr *address, socklen_t *address_len)
+// CHECK: Loaded summary for: ssize_t sendto(int socket, const void *message, size_t length, int flags, const struct sockaddr *dest_addr, socklen_t dest_len)
+
+struct sockaddr;
+using socklen_t = unsigned;
+int accept(int socket, struct sockaddr *address, socklen_t *address_len);
+int bind(int socket, const struct sockaddr *address, socklen_t address_len);
+int getpeername(int socket, struct sockaddr *address, socklen_t *address_len);
+int getsockname(int socket, struct sockaddr *address, socklen_t *address_len);
+int connect(int socket, const struct sockaddr *address, socklen_t address_len);
+typedef decltype(sizeof(int)) size_t;
+typedef size_t ssize_t;
+ssize_t recvfrom(int socket, void *buffer, size_t length, int flags, struct sockaddr *address, socklen_t *address_len);
+ssize_t sendto(int socket, const void *message, size_t length, int flags, const struct sockaddr *dest_addr, socklen_t dest_len);
+
+// Must have at least one call expression to initialize the summary map.
+int bar(void);
+void foo() {
+  bar();
+}

diff  --git a/clang/test/Analysis/std-c-library-functions-POSIX.c b/clang/test/Analysis/std-c-library-functions-POSIX.c
index e6f5b19baa00..3638ad100240 100644
--- a/clang/test/Analysis/std-c-library-functions-POSIX.c
+++ b/clang/test/Analysis/std-c-library-functions-POSIX.c
@@ -79,6 +79,22 @@
 // CHECK: Loaded summary for: int execv(const char *path, char *const argv[])
 // CHECK: Loaded summary for: int execvp(const char *file, char *const argv[])
 // CHECK: Loaded summary for: int getopt(int argc, char *const argv[], const char *optstring)
+// CHECK: Loaded summary for: int accept(int socket, __SOCKADDR_ARG address, socklen_t *restrict address_len)
+// CHECK: Loaded summary for: int bind(int socket, __CONST_SOCKADDR_ARG address, socklen_t address_len)
+// CHECK: Loaded summary for: int getpeername(int socket, __SOCKADDR_ARG address, socklen_t *restrict address_len)
+// CHECK: Loaded summary for: int getsockname(int socket, __SOCKADDR_ARG address, socklen_t *restrict address_len)
+// CHECK: Loaded summary for: int connect(int socket, __CONST_SOCKADDR_ARG address, socklen_t address_len)
+// CHECK: Loaded summary for: ssize_t recvfrom(int socket, void *restrict buffer, size_t length, int flags, __SOCKADDR_ARG address, socklen_t *restrict address_len)
+// CHECK: Loaded summary for: ssize_t sendto(int socket, const void *message, size_t length, int flags, __CONST_SOCKADDR_ARG dest_addr, socklen_t dest_len)
+// CHECK: Loaded summary for: int listen(int sockfd, int backlog)
+// CHECK: Loaded summary for: ssize_t recv(int sockfd, void *buf, size_t len, int flags)
+// CHECK: Loaded summary for: ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags)
+// CHECK: Loaded summary for: ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags)
+// CHECK: Loaded summary for: int setsockopt(int socket, int level, int option_name, const void *option_value, socklen_t option_len)
+// CHECK: Loaded summary for: int getsockopt(int socket, int level, int option_name, void *restrict option_value, socklen_t *restrict option_len)
+// 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)
 
 long a64l(const char *str64);
 char *l64a(long value);
@@ -171,6 +187,46 @@ int execv(const char *path, char *const argv[]);
 int execvp(const char *file, char *const argv[]);
 int getopt(int argc, char *const argv[], const char *optstring);
 
+// In some libc implementations, sockaddr parameter is a transparent
+// union of the underlying sockaddr_ pointers instead of being a
+// pointer to struct sockaddr.
+// We match that with the joker Irrelevant type.
+struct sockaddr;
+struct sockaddr_at;
+#define __SOCKADDR_ALLTYPES    \
+  __SOCKADDR_ONETYPE(sockaddr) \
+  __SOCKADDR_ONETYPE(sockaddr_at)
+#define __SOCKADDR_ONETYPE(type) struct type *__restrict __##type##__;
+typedef union {
+  __SOCKADDR_ALLTYPES
+} __SOCKADDR_ARG __attribute__((__transparent_union__));
+#undef __SOCKADDR_ONETYPE
+#define __SOCKADDR_ONETYPE(type) const struct type *__restrict __##type##__;
+typedef union {
+  __SOCKADDR_ALLTYPES
+} __CONST_SOCKADDR_ARG __attribute__((__transparent_union__));
+#undef __SOCKADDR_ONETYPE
+typedef unsigned socklen_t;
+
+int accept(int socket, __SOCKADDR_ARG address, socklen_t *restrict address_len);
+int bind(int socket, __CONST_SOCKADDR_ARG address, socklen_t address_len);
+int getpeername(int socket, __SOCKADDR_ARG address, socklen_t *restrict address_len);
+int getsockname(int socket, __SOCKADDR_ARG address, socklen_t *restrict address_len);
+int connect(int socket, __CONST_SOCKADDR_ARG address, socklen_t address_len);
+ssize_t recvfrom(int socket, void *restrict buffer, size_t length, int flags, __SOCKADDR_ARG address, socklen_t *restrict address_len);
+ssize_t sendto(int socket, const void *message, size_t length, int flags, __CONST_SOCKADDR_ARG dest_addr, socklen_t dest_len);
+
+int listen(int sockfd, int backlog);
+ssize_t recv(int sockfd, void *buf, size_t len, int flags);
+struct msghdr;
+ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);
+ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
+int setsockopt(int socket, int level, int option_name, const void *option_value, socklen_t option_len);
+int getsockopt(int socket, int level, int option_name, void *restrict option_value, socklen_t *restrict option_len);
+ssize_t send(int sockfd, const void *buf, size_t len, int flags);
+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);
+
 // Must have at least one call expression to initialize the summary map.
 int bar(void);
 void foo() {


        


More information about the cfe-commits mailing list