diff --git a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp --- a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp @@ -302,6 +302,13 @@ Tmp.Op = BinaryOperator::negateComparisonOp(Op); return std::make_shared(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 @@ // 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 @@ assertArgTypeSuitableForSignature(ArgTy); } } + bool matches(const FunctionDecl *FD) const; private: @@ -380,7 +388,7 @@ /// rules for the given parameter's type, those rules are checked once the /// signature is matched. class Summary { - const Signature Sign; + Optional Sign; const InvalidationKind InvalidationKd; Cases CaseConstraints; ConstraintSet ArgConstraints; @@ -391,7 +399,14 @@ 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 @@ // 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 @@ 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 @@ 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 @@ // 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(D)) { if (S.matchesAndSet(FD)) { @@ -856,10 +869,14 @@ 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 &Summaries) { @@ -927,8 +944,7 @@ // 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 @@ Optional 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 @@ .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))) .ArgConstraint(NotNull(ArgNo(1))) .ArgConstraint(NotNull(ArgNo(2)))); + + Optional StructSockaddrTy = lookupType("sockaddr", ACtx); + Optional StructSockaddrPtrTy, ConstStructSockaddrPtrTy, + StructSockaddrPtrRestrictTy, ConstStructSockaddrPtrRestrictTy; + if (StructSockaddrTy) { + StructSockaddrPtrTy = ACtx.getPointerType(*StructSockaddrTy); + ConstStructSockaddrPtrTy = + ACtx.getPointerType(StructSockaddrTy->withConst()); + StructSockaddrPtrRestrictTy = getRestrictTy(*StructSockaddrPtrTy); + ConstStructSockaddrPtrRestrictTy = + getRestrictTy(*ConstStructSockaddrPtrTy); + } + Optional Socklen_tTy = lookupType("socklen_t", ACtx); + Optional Socklen_tPtrTy, Socklen_tPtrRestrictTy; + Optional 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 StructMsghdrTy = lookupType("msghdr", ACtx); + Optional 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 --- /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 --- 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 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() {