martong created this revision. martong added reviewers: gamesh411, Szelethus, NoQ. Herald added subscribers: cfe-commits, ASDenysPetrov, steakhal, Charusso, dkrupp, donat.nagy, mikhail.ramalho, a.sidorin, rnkovacs, szepet, baloghadamsoftware, xazax.hun, whisperity. Herald added a project: clang.
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. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D83407 Files: clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp clang/test/Analysis/std-c-library-functions-POSIX-socket-sockaddr.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 @@ -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,47 @@ 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##__; +#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() { Index: clang/test/Analysis/std-c-library-functions-POSIX-socket-sockaddr.cpp =================================================================== --- /dev/null +++ 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(); +} Index: clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp =================================================================== --- clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp +++ clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp @@ -302,6 +302,13 @@ 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. @@ -839,11 +846,13 @@ // 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)) { @@ -855,10 +864,11 @@ FD->print(llvm::errs()); llvm::errs() << "\n"; } - return; + return true; } } } + return false; } // Add several summaries for the given name. void operator()(StringRef Name, const std::vector<Summary> &Summaries) { @@ -1701,6 +1711,279 @@ .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 = + ACtx.getLangOpts().C99 ? ACtx.getRestrictType(*StructSockaddrPtrTy) + : *StructSockaddrPtrTy; + ConstStructSockaddrPtrRestrictTy = + ACtx.getLangOpts().C99 + ? ACtx.getRestrictType(*ConstStructSockaddrPtrTy) + : *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 = ACtx.getLangOpts().C99 + ? ACtx.getRestrictType(*Socklen_tPtrTy) + : *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) { + // int accept(int socket, struct sockaddr *restrict address, + // socklen_t *restrict address_len); + if (!addToFunctionSummaryMap( + "accept", Summary(ArgTypes{IntTy, *StructSockaddrPtrRestrictTy, + *Socklen_tPtrRestrictTy}, + RetType{IntTy}, NoEvalCall) + .ArgConstraint(ArgumentCondition( + 0, WithinRange, Range(0, IntMax))))) + // Do not add constraints on sockaddr. + addToFunctionSummaryMap( + "accept", + Summary(ArgTypes{IntTy, Irrelevant, *Socklen_tPtrRestrictTy}, + RetType{IntTy}, NoEvalCall) + .ArgConstraint( + ArgumentCondition(0, WithinRange, Range(0, IntMax)))); + + // 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))))) + 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)))); + + // ssize_t recvfrom(int socket, void *restrict buffer, size_t length, + // int flags, struct sockaddr *restrict address, + // socklen_t *restrict address_len); + if (Ssize_tTy && + !addToFunctionSummaryMap( + "recvfrom", Summary(ArgTypes{IntTy, VoidPtrRestrictTy, SizeTy, + IntTy, *StructSockaddrPtrRestrictTy, + *Socklen_tPtrRestrictTy}, + RetType{*Ssize_tTy}, NoEvalCall) + .ArgConstraint(ArgumentCondition( + 0, WithinRange, Range(0, IntMax))) + .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1), + /*BufSize=*/ArgNo(2))))) + addToFunctionSummaryMap( + "recvfrom", + Summary(ArgTypes{IntTy, VoidPtrRestrictTy, SizeTy, IntTy, + Irrelevant, *Socklen_tPtrRestrictTy}, + RetType{*Ssize_tTy}, NoEvalCall) + .ArgConstraint( + ArgumentCondition(0, WithinRange, Range(0, IntMax))) + .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1), + /*BufSize=*/ArgNo(2)))); + + // ssize_t sendto(int socket, const void *message, size_t length, + // int flags, const struct sockaddr *dest_addr, + // socklen_t dest_len); + if (Ssize_tTy && + !addToFunctionSummaryMap( + "sendto", + Summary(ArgTypes{IntTy, ConstVoidPtrTy, SizeTy, IntTy, + *ConstStructSockaddrPtrTy, *Socklen_tTy}, + RetType{*Ssize_tTy}, NoEvalCall) + .ArgConstraint( + ArgumentCondition(0, WithinRange, Range(0, IntMax))) + .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1), + /*BufSize=*/ArgNo(2))))) + addToFunctionSummaryMap( + "sendto", Summary(ArgTypes{IntTy, ConstVoidPtrTy, SizeTy, IntTy, + Irrelevant, *Socklen_tTy}, + RetType{*Ssize_tTy}, NoEvalCall) + .ArgConstraint(ArgumentCondition(0, WithinRange, + Range(0, IntMax))) + .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1), + /*BufSize=*/ArgNo(2)))); + } + + // 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.
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits