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 @@ -138,18 +138,24 @@ /// Given a range, should the argument stay inside or outside this range? enum RangeKind { OutOfRange, WithinRange }; - /// Encapsulates a single range on a single symbol within a branch. + /// Encapsulates a range on a single symbol. class RangeConstraint : public ValueConstraint { - RangeKind Kind; // Kind of range definition. - IntRangeVector Args; // Polymorphic arguments. + RangeKind Kind; + // A range is formed as a set of intervals (sub-ranges). + // E.g. {['A', 'Z'], ['a', 'z']} + // + // The default constructed RangeConstraint has an empty range set, applying + // such constraint does not involve any assumptions, thus the State remains + // unchanged. This is meaningful, if the range is dependent on a looked up + // type (e.g. [0, Socklen_tMax]). If the type is not found, then the range + // is default initialized to be empty. + IntRangeVector Ranges; public: - RangeConstraint(ArgNo ArgN, RangeKind Kind, const IntRangeVector &Args) - : ValueConstraint(ArgN), Kind(Kind), Args(Args) {} + RangeConstraint(ArgNo ArgN, RangeKind Kind, const IntRangeVector &Ranges) + : ValueConstraint(ArgN), Kind(Kind), Ranges(Ranges) {} - const IntRangeVector &getRanges() const { - return Args; - } + const IntRangeVector &getRanges() const { return Ranges; } private: ProgramStateRef applyAsOutOfRange(ProgramStateRef State, @@ -314,7 +320,8 @@ /// The complete list of constraints that defines a single branch. typedef std::vector ConstraintSet; - using ArgTypes = std::vector; + using ArgTypes = std::vector>; + using RetType = Optional; // A placeholder type, we use it whenever we do not care about the concrete // type in a Signature. @@ -324,17 +331,37 @@ // 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; + // All types in the spec need to be canonical. + class Signature { + using ArgQualTypes = std::vector; + 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: + // Construct a signature from optional types. If any of the optional types + // are not set then the signature will be invalid. + Signature(ArgTypes ArgTys, RetType RetTy) { + for (Optional Arg : ArgTys) { + if (!Arg) { + Invalid = true; + return; + } else { + assertArgTypeSuitableForSignature(*Arg); + this->ArgTys.push_back(*Arg); + } + } + if (!RetTy) { + Invalid = true; + return; + } else { + assertRetTypeSuitableForSignature(*RetTy); + this->RetTy = *RetTy; } } + bool isInvalid() const { return Invalid; } bool matches(const FunctionDecl *FD) const; private: @@ -388,6 +415,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 Sign; const InvalidationKind InvalidationKd; Cases CaseConstraints; @@ -398,11 +428,13 @@ const FunctionDecl *FD = nullptr; public: - Summary(ArgTypes ArgTys, QualType RetTy, InvalidationKind InvalidationKd) + Summary(ArgTypes ArgTys, RetType RetTy, InvalidationKind InvalidationKd) : Sign(Signature(ArgTys, RetTy)), InvalidationKd(InvalidationKd) {} 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 +470,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. @@ -512,6 +551,8 @@ ProgramStateRef StdLibraryFunctionsChecker::RangeConstraint::applyAsOutOfRange( ProgramStateRef State, const CallEvent &Call, const Summary &Summary) const { + if (Ranges.empty()) + return State; ProgramStateManager &Mgr = State->getStateManager(); SValBuilder &SVB = Mgr.getSValBuilder(); @@ -539,6 +580,8 @@ ProgramStateRef StdLibraryFunctionsChecker::RangeConstraint::applyAsWithinRange( ProgramStateRef State, const CallEvent &Call, const Summary &Summary) const { + if (Ranges.empty()) + return State; ProgramStateManager &Mgr = State->getStateManager(); SValBuilder &SVB = Mgr.getSValBuilder(); @@ -699,6 +742,7 @@ bool StdLibraryFunctionsChecker::Signature::matches( const FunctionDecl *FD) const { + assert(!isInvalid()); // Check number of arguments: if (FD->param_size() != ArgTys.size()) return false; @@ -743,32 +787,6 @@ return findFunctionSummary(FD, C); } -static llvm::Optional lookupType(StringRef Name, - const ASTContext &ACtx) { - IdentifierInfo &II = ACtx.Idents.get(Name); - auto LookupRes = ACtx.getTranslationUnitDecl()->lookup(&II); - if (LookupRes.size() == 0) - return None; - - // Prioritze typedef declarations. - // This is needed in case of C struct typedefs. E.g.: - // typedef struct FILE FILE; - // In this case, we have a RecordDecl 'struct FILE' with the name 'FILE' and - // we have a TypedefDecl with the name 'FILE'. - for (Decl *D : LookupRes) - if (auto *TD = dyn_cast(D)) - return ACtx.getTypeDeclType(TD).getCanonicalType(); - - // Find the first TypeDecl. - // There maybe cases when a function has the same name as a struct. - // E.g. in POSIX: `struct stat` and the function `stat()`: - // int stat(const char *restrict path, struct stat *restrict buf); - for (Decl *D : LookupRes) - if (auto *TD = dyn_cast(D)) - return ACtx.getTypeDeclType(TD).getCanonicalType(); - return None; -} - void StdLibraryFunctionsChecker::initFunctionSummaries( CheckerContext &C) const { if (!FunctionSummaryMap.empty()) @@ -778,9 +796,90 @@ BasicValueFactory &BVF = SVB.getBasicValueFactory(); const ASTContext &ACtx = BVF.getContext(); - auto getRestrictTy = [&ACtx](QualType Ty) { - return ACtx.getLangOpts().C99 ? ACtx.getRestrictType(Ty) : Ty; - }; + // Helper class to lookup a type by its name. + class LookupType { + const ASTContext &ACtx; + + public: + LookupType(const ASTContext &ACtx) : ACtx(ACtx) {} + + // Find the type. If not found then the optional is not set. + llvm::Optional operator()(StringRef Name) { + IdentifierInfo &II = ACtx.Idents.get(Name); + auto LookupRes = ACtx.getTranslationUnitDecl()->lookup(&II); + if (LookupRes.size() == 0) + return None; + + // Prioritze typedef declarations. + // This is needed in case of C struct typedefs. E.g.: + // typedef struct FILE FILE; + // In this case, we have a RecordDecl 'struct FILE' with the name 'FILE' + // and we have a TypedefDecl with the name 'FILE'. + for (Decl *D : LookupRes) + if (auto *TD = dyn_cast(D)) + return ACtx.getTypeDeclType(TD).getCanonicalType(); + + // Find the first TypeDecl. + // There maybe cases when a function has the same name as a struct. + // E.g. in POSIX: `struct stat` and the function `stat()`: + // int stat(const char *restrict path, struct stat *restrict buf); + for (Decl *D : LookupRes) + if (auto *TD = dyn_cast(D)) + return ACtx.getTypeDeclType(TD).getCanonicalType(); + return None; + } + } lookupTy(ACtx); + + // Below are auxiliary classes to handle optional types that we get as a + // result of the lookup. + 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 operator()(Optional 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 operator()(Optional Ty) { + if (Ty) + return operator()(*Ty); + return None; + } + } getPointerTy(ACtx); + class { + public: + Optional operator()(Optional Ty) { + return Ty ? Optional(Ty->withConst()) : None; + } + QualType operator()(QualType Ty) { return Ty.withConst(); } + } getConstTy; + class GetMaxValue { + BasicValueFactory &BVF; + + public: + GetMaxValue(BasicValueFactory &BVF) : BVF(BVF) {} + Optional operator()(QualType Ty) { + return BVF.getMaxValue(Ty).getLimitedValue(); + } + Optional operator()(Optional Ty) { + if (Ty) { + return operator()(*Ty); + } + return None; + } + } getMaxValue(BVF); // These types are useful for writing specifications quickly, // New specifications should probably introduce more types. @@ -790,27 +889,29 @@ // or long long, so three summary variants would be enough). // Of course, function variants are also useful for C++ overloads. const QualType VoidTy = ACtx.VoidTy; + const QualType CharTy = ACtx.CharTy; + const QualType WCharTy = ACtx.WCharTy; const QualType IntTy = ACtx.IntTy; const QualType UnsignedIntTy = ACtx.UnsignedIntTy; const QualType LongTy = ACtx.LongTy; const QualType LongLongTy = ACtx.LongLongTy; const QualType SizeTy = ACtx.getSizeType(); - const QualType VoidPtrTy = ACtx.VoidPtrTy; // void * - const QualType IntPtrTy = ACtx.getPointerType(IntTy); // int * + const QualType VoidPtrTy = getPointerTy(VoidTy); // void * + 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(getConstTy(VoidTy)); // const void * + const QualType CharPtrTy = getPointerTy(CharTy); // char * const QualType CharPtrRestrictTy = getRestrictTy(CharPtrTy); const QualType ConstCharPtrTy = - ACtx.getPointerType(ACtx.CharTy.withConst()); // const char * + getPointerTy(getConstTy(CharTy)); // const char * const QualType ConstCharPtrRestrictTy = getRestrictTy(ConstCharPtrTy); - const QualType Wchar_tPtrTy = ACtx.getPointerType(ACtx.WCharTy); // wchar_t * + const QualType Wchar_tPtrTy = getPointerTy(WCharTy); // wchar_t * const QualType ConstWchar_tPtrTy = - ACtx.getPointerType(ACtx.WCharTy.withConst()); // const wchar_t * + getPointerTy(getConstTy(WCharTy)); // const wchar_t * const QualType ConstVoidPtrRestrictTy = getRestrictTy(ConstVoidPtrTy); const RangeInt IntMax = BVF.getMaxValue(IntTy).getLimitedValue(); @@ -853,7 +954,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 +979,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)); } @@ -885,32 +990,6 @@ } } addToFunctionSummaryMap(ACtx, FunctionSummaryMap, DisplayLoadedSummaries); - // We are finally ready to define specifications for all supported functions. - // - // The signature needs to have the correct number of arguments. - // However, we insert `Irrelevant' when the type is insignificant. - // - // Argument ranges should always cover all variants. If return value - // is completely unknown, omit it from the respective range set. - // - // All types in the spec need to be canonical. - // - // Every item in the list of range sets represents a particular - // execution path the analyzer would need to explore once - // the call is modeled - a new program state is constructed - // for every range set, and each range line in the range set - // corresponds to a specific constraint within this state. - // - // Upon comparing to another argument, the other argument is casted - // to the current argument's type. This avoids proper promotion but - // seems useful. For example, read() receives size_t argument, - // and its return value, which is of type ssize_t, cannot be greater - // than this argument. If we made a promotion, and the size argument - // is equal to, say, 10, then we'd impose a range of [0, 10] on the - // return value, however the correct range is [-1, 10]. - // - // Please update the list of functions in the header after editing! - // Below are helpers functions to create the summaries. auto ArgumentCondition = [](ArgNo ArgN, RangeKind Kind, IntRangeVector Ranges) { @@ -927,9 +1006,16 @@ return std::make_shared(Ret, Op, OtherArgN); } } ReturnValueCondition; - auto Range = [](RangeInt b, RangeInt e) { - return IntRangeVector{std::pair{b, e}}; - }; + struct { + auto operator()(RangeInt b, RangeInt e) { + return IntRangeVector{std::pair{b, e}}; + } + auto operator()(RangeInt b, Optional e) { + if (e) + return IntRangeVector{std::pair{b, *e}}; + return IntRangeVector{}; + } + } Range; auto SingleValue = [](RangeInt v) { return IntRangeVector{std::pair{v, v}}; }; @@ -938,19 +1024,13 @@ return std::make_shared(ArgN); }; - Optional FileTy = lookupType("FILE", ACtx); - Optional FilePtrTy, FilePtrRestrictTy; - if (FileTy) { - // FILE * - FilePtrTy = ACtx.getPointerType(*FileTy); - // FILE *restrict - FilePtrRestrictTy = getRestrictTy(*FilePtrTy); - } + Optional FileTy = lookupTy("FILE"); + Optional FilePtrTy = getPointerTy(FileTy); + Optional FilePtrRestrictTy = getRestrictTy(FilePtrTy); - using RetType = QualType; // Templates for summaries that are reused by many functions. auto Getc = [&]() { - return Summary(ArgTypes{*FilePtrTy}, RetType{IntTy}, NoEvalCall) + return Summary(ArgTypes{FilePtrTy}, RetType{IntTy}, NoEvalCall) .Case({ReturnValueCondition(WithinRange, {{EOFv, EOFv}, {0, UCharRangeMax}})}); }; @@ -962,7 +1042,7 @@ }; auto Fread = [&]() { return Summary( - ArgTypes{VoidPtrRestrictTy, SizeTy, SizeTy, *FilePtrRestrictTy}, + ArgTypes{VoidPtrRestrictTy, SizeTy, SizeTy, FilePtrRestrictTy}, RetType{SizeTy}, NoEvalCall) .Case({ ReturnValueCondition(LessThanOrEq, ArgNo(2)), @@ -971,7 +1051,7 @@ }; auto Fwrite = [&]() { return Summary(ArgTypes{ConstVoidPtrRestrictTy, SizeTy, SizeTy, - *FilePtrRestrictTy}, + FilePtrRestrictTy}, RetType{SizeTy}, NoEvalCall) .Case({ ReturnValueCondition(LessThanOrEq, ArgNo(2)), @@ -984,6 +1064,17 @@ .Case({ReturnValueCondition(WithinRange, {{-1, -1}, {1, Max}})}); }; + // We are finally ready to define specifications for all supported functions. + // + // Argument ranges should always cover all variants. If return value + // is completely unknown, omit it from the respective range set. + // + // Every item in the list of range sets represents a particular + // execution path the analyzer would need to explore once + // the call is modeled - a new program state is constructed + // for every range set, and each range line in the range set + // corresponds to a specific constraint within this state. + // The isascii() family of functions. // The behavior is undefined if the value of the argument is not // representable as unsigned char or is not equal to EOF. See e.g. C99 @@ -1119,20 +1210,16 @@ ReturnValueCondition(WithinRange, SingleValue(0))})); // The getc() family of functions that returns either a char or an EOF. - if (FilePtrTy) { addToFunctionSummaryMap("getc", Getc()); addToFunctionSummaryMap("fgetc", Getc()); - } addToFunctionSummaryMap( "getchar", Summary(ArgTypes{}, RetType{IntTy}, NoEvalCall) .Case({ReturnValueCondition( WithinRange, {{EOFv, EOFv}, {0, UCharRangeMax}})})); // read()-like functions that never return more than buffer size. - if (FilePtrRestrictTy) { addToFunctionSummaryMap("fread", Fread()); addToFunctionSummaryMap("fwrite", Fwrite()); - } // We are not sure how ssize_t is defined on every platform, so we // provide three variants that should cover common cases. @@ -1210,14 +1297,13 @@ .ArgConstraint( ArgumentCondition(0, WithinRange, Range(0, IntMax)))); - Optional Off_tTy = lookupType("off_t", ACtx); + Optional Off_tTy = lookupTy("off_t"); - if (Off_tTy) - // int truncate(const char *path, off_t length); - addToFunctionSummaryMap("truncate", - Summary(ArgTypes{ConstCharPtrTy, *Off_tTy}, - RetType{IntTy}, NoEvalCall) - .ArgConstraint(NotNull(ArgNo(0)))); + // int truncate(const char *path, off_t length); + addToFunctionSummaryMap( + "truncate", + Summary(ArgTypes{ConstCharPtrTy, Off_tTy}, RetType{IntTy}, NoEvalCall) + .ArgConstraint(NotNull(ArgNo(0)))); // int symlink(const char *oldpath, const char *newpath); addToFunctionSummaryMap("symlink", @@ -1235,22 +1321,19 @@ .ArgConstraint(ArgumentCondition(1, WithinRange, Range(0, IntMax))) .ArgConstraint(NotNull(ArgNo(2)))); - if (Off_tTy) - // int lockf(int fd, int cmd, off_t len); - addToFunctionSummaryMap( - "lockf", - Summary(ArgTypes{IntTy, IntTy, *Off_tTy}, RetType{IntTy}, NoEvalCall) - .ArgConstraint( - ArgumentCondition(0, WithinRange, Range(0, IntMax)))); + // int lockf(int fd, int cmd, off_t len); + addToFunctionSummaryMap( + "lockf", + Summary(ArgTypes{IntTy, IntTy, Off_tTy}, RetType{IntTy}, NoEvalCall) + .ArgConstraint( + ArgumentCondition(0, WithinRange, Range(0, IntMax)))); - Optional Mode_tTy = lookupType("mode_t", ACtx); + Optional Mode_tTy = lookupTy("mode_t"); - if (Mode_tTy) - // int creat(const char *pathname, mode_t mode); - addToFunctionSummaryMap("creat", - Summary(ArgTypes{ConstCharPtrTy, *Mode_tTy}, - RetType{IntTy}, NoEvalCall) - .ArgConstraint(NotNull(ArgNo(0)))); + // int creat(const char *pathname, mode_t mode); + addToFunctionSummaryMap("creat", Summary(ArgTypes{ConstCharPtrTy, Mode_tTy}, + RetType{IntTy}, NoEvalCall) + .ArgConstraint(NotNull(ArgNo(0)))); // unsigned int sleep(unsigned int seconds); addToFunctionSummaryMap( @@ -1259,16 +1342,13 @@ .ArgConstraint( ArgumentCondition(0, WithinRange, Range(0, UnsignedIntMax)))); - Optional DirTy = lookupType("DIR", ACtx); - Optional DirPtrTy; - if (DirTy) - DirPtrTy = ACtx.getPointerType(*DirTy); + Optional DirTy = lookupTy("DIR"); + Optional DirPtrTy = getPointerTy(DirTy); - if (DirPtrTy) - // int dirfd(DIR *dirp); - addToFunctionSummaryMap( - "dirfd", Summary(ArgTypes{*DirPtrTy}, RetType{IntTy}, NoEvalCall) - .ArgConstraint(NotNull(ArgNo(0)))); + // int dirfd(DIR *dirp); + addToFunctionSummaryMap( + "dirfd", Summary(ArgTypes{DirPtrTy}, RetType{IntTy}, NoEvalCall) + .ArgConstraint(NotNull(ArgNo(0)))); // unsigned int alarm(unsigned int seconds); addToFunctionSummaryMap( @@ -1277,11 +1357,10 @@ .ArgConstraint( ArgumentCondition(0, WithinRange, Range(0, UnsignedIntMax)))); - if (DirPtrTy) - // int closedir(DIR *dir); - addToFunctionSummaryMap( - "closedir", Summary(ArgTypes{*DirPtrTy}, RetType{IntTy}, NoEvalCall) - .ArgConstraint(NotNull(ArgNo(0)))); + // int closedir(DIR *dir); + addToFunctionSummaryMap( + "closedir", Summary(ArgTypes{DirPtrTy}, RetType{IntTy}, NoEvalCall) + .ArgConstraint(NotNull(ArgNo(0)))); // char *strdup(const char *s); addToFunctionSummaryMap("strdup", Summary(ArgTypes{ConstCharPtrTy}, @@ -1318,92 +1397,80 @@ .ArgConstraint( ArgumentCondition(1, WithinRange, Range(0, SizeMax)))); - if (Mode_tTy) { - // int mkdir(const char *pathname, mode_t mode); - addToFunctionSummaryMap("mkdir", - Summary(ArgTypes{ConstCharPtrTy, *Mode_tTy}, - RetType{IntTy}, NoEvalCall) - .ArgConstraint(NotNull(ArgNo(0)))); + // int mkdir(const char *pathname, mode_t mode); + addToFunctionSummaryMap("mkdir", Summary(ArgTypes{ConstCharPtrTy, Mode_tTy}, + RetType{IntTy}, NoEvalCall) + .ArgConstraint(NotNull(ArgNo(0)))); - // int mkdirat(int dirfd, const char *pathname, mode_t mode); - addToFunctionSummaryMap( - "mkdirat", Summary(ArgTypes{IntTy, ConstCharPtrTy, *Mode_tTy}, - RetType{IntTy}, NoEvalCall) - .ArgConstraint(NotNull(ArgNo(1)))); - } + // int mkdirat(int dirfd, const char *pathname, mode_t mode); + addToFunctionSummaryMap("mkdirat", + Summary(ArgTypes{IntTy, ConstCharPtrTy, Mode_tTy}, + RetType{IntTy}, NoEvalCall) + .ArgConstraint(NotNull(ArgNo(1)))); - Optional Dev_tTy = lookupType("dev_t", ACtx); + Optional Dev_tTy = lookupTy("dev_t"); - if (Mode_tTy && Dev_tTy) { - // int mknod(const char *pathname, mode_t mode, dev_t dev); - addToFunctionSummaryMap( - "mknod", Summary(ArgTypes{ConstCharPtrTy, *Mode_tTy, *Dev_tTy}, - RetType{IntTy}, NoEvalCall) - .ArgConstraint(NotNull(ArgNo(0)))); + // int mknod(const char *pathname, mode_t mode, dev_t dev); + addToFunctionSummaryMap("mknod", + Summary(ArgTypes{ConstCharPtrTy, Mode_tTy, Dev_tTy}, + RetType{IntTy}, NoEvalCall) + .ArgConstraint(NotNull(ArgNo(0)))); - // int mknodat(int dirfd, const char *pathname, mode_t mode, dev_t dev); - addToFunctionSummaryMap("mknodat", Summary(ArgTypes{IntTy, ConstCharPtrTy, - *Mode_tTy, *Dev_tTy}, - RetType{IntTy}, NoEvalCall) - .ArgConstraint(NotNull(ArgNo(1)))); - } + // int mknodat(int dirfd, const char *pathname, mode_t mode, dev_t dev); + addToFunctionSummaryMap( + "mknodat", Summary(ArgTypes{IntTy, ConstCharPtrTy, Mode_tTy, Dev_tTy}, + RetType{IntTy}, NoEvalCall) + .ArgConstraint(NotNull(ArgNo(1)))); - if (Mode_tTy) { - // int chmod(const char *path, mode_t mode); - addToFunctionSummaryMap("chmod", - Summary(ArgTypes{ConstCharPtrTy, *Mode_tTy}, - RetType{IntTy}, NoEvalCall) - .ArgConstraint(NotNull(ArgNo(0)))); + // int chmod(const char *path, mode_t mode); + addToFunctionSummaryMap("chmod", Summary(ArgTypes{ConstCharPtrTy, Mode_tTy}, + RetType{IntTy}, NoEvalCall) + .ArgConstraint(NotNull(ArgNo(0)))); - // int fchmodat(int dirfd, const char *pathname, mode_t mode, int flags); - addToFunctionSummaryMap( - "fchmodat", Summary(ArgTypes{IntTy, ConstCharPtrTy, *Mode_tTy, IntTy}, - RetType{IntTy}, NoEvalCall) - .ArgConstraint(ArgumentCondition(0, WithinRange, - Range(0, IntMax))) - .ArgConstraint(NotNull(ArgNo(1)))); + // int fchmodat(int dirfd, const char *pathname, mode_t mode, int flags); + addToFunctionSummaryMap( + "fchmodat", + Summary(ArgTypes{IntTy, ConstCharPtrTy, Mode_tTy, IntTy}, + RetType{IntTy}, NoEvalCall) + .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))) + .ArgConstraint(NotNull(ArgNo(1)))); - // int fchmod(int fildes, mode_t mode); - addToFunctionSummaryMap( - "fchmod", - Summary(ArgTypes{IntTy, *Mode_tTy}, RetType{IntTy}, NoEvalCall) - .ArgConstraint( - ArgumentCondition(0, WithinRange, Range(0, IntMax)))); - } + // int fchmod(int fildes, mode_t mode); + addToFunctionSummaryMap( + "fchmod", Summary(ArgTypes{IntTy, Mode_tTy}, RetType{IntTy}, NoEvalCall) + .ArgConstraint( + ArgumentCondition(0, WithinRange, Range(0, IntMax)))); - Optional Uid_tTy = lookupType("uid_t", ACtx); - Optional Gid_tTy = lookupType("gid_t", ACtx); + Optional Uid_tTy = lookupTy("uid_t"); + Optional Gid_tTy = lookupTy("gid_t"); - if (Uid_tTy && Gid_tTy) { - // int fchownat(int dirfd, const char *pathname, uid_t owner, gid_t group, - // int flags); - addToFunctionSummaryMap( - "fchownat", - Summary(ArgTypes{IntTy, ConstCharPtrTy, *Uid_tTy, *Gid_tTy, IntTy}, - RetType{IntTy}, NoEvalCall) - .ArgConstraint( - ArgumentCondition(0, WithinRange, Range(0, IntMax))) - .ArgConstraint(NotNull(ArgNo(1)))); + // int fchownat(int dirfd, const char *pathname, uid_t owner, gid_t group, + // int flags); + addToFunctionSummaryMap( + "fchownat", + Summary(ArgTypes{IntTy, ConstCharPtrTy, Uid_tTy, Gid_tTy, IntTy}, + RetType{IntTy}, NoEvalCall) + .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))) + .ArgConstraint(NotNull(ArgNo(1)))); - // int chown(const char *path, uid_t owner, gid_t group); - addToFunctionSummaryMap( - "chown", Summary(ArgTypes{ConstCharPtrTy, *Uid_tTy, *Gid_tTy}, - RetType{IntTy}, NoEvalCall) - .ArgConstraint(NotNull(ArgNo(0)))); + // int chown(const char *path, uid_t owner, gid_t group); + addToFunctionSummaryMap("chown", + Summary(ArgTypes{ConstCharPtrTy, Uid_tTy, Gid_tTy}, + RetType{IntTy}, NoEvalCall) + .ArgConstraint(NotNull(ArgNo(0)))); - // int lchown(const char *path, uid_t owner, gid_t group); - addToFunctionSummaryMap( - "lchown", Summary(ArgTypes{ConstCharPtrTy, *Uid_tTy, *Gid_tTy}, - RetType{IntTy}, NoEvalCall) - .ArgConstraint(NotNull(ArgNo(0)))); + // int lchown(const char *path, uid_t owner, gid_t group); + addToFunctionSummaryMap("lchown", + Summary(ArgTypes{ConstCharPtrTy, Uid_tTy, Gid_tTy}, + RetType{IntTy}, NoEvalCall) + .ArgConstraint(NotNull(ArgNo(0)))); - // int fchown(int fildes, uid_t owner, gid_t group); - addToFunctionSummaryMap( - "fchown", Summary(ArgTypes{IntTy, *Uid_tTy, *Gid_tTy}, RetType{IntTy}, - NoEvalCall) - .ArgConstraint(ArgumentCondition(0, WithinRange, - Range(0, IntMax)))); - } + // int fchown(int fildes, uid_t owner, gid_t group); + addToFunctionSummaryMap( + "fchown", + Summary(ArgTypes{IntTy, Uid_tTy, Gid_tTy}, RetType{IntTy}, NoEvalCall) + .ArgConstraint( + ArgumentCondition(0, WithinRange, Range(0, IntMax)))); // int rmdir(const char *pathname); addToFunctionSummaryMap( @@ -1446,63 +1513,52 @@ .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))) .ArgConstraint(NotNull(ArgNo(1)))); - Optional StructStatTy = lookupType("stat", ACtx); - Optional StructStatPtrTy, StructStatPtrRestrictTy; - if (StructStatTy) { - StructStatPtrTy = ACtx.getPointerType(*StructStatTy); - StructStatPtrRestrictTy = getRestrictTy(*StructStatPtrTy); - } + Optional StructStatTy = lookupTy("stat"); + Optional StructStatPtrTy = getPointerTy(StructStatTy); + Optional StructStatPtrRestrictTy = getRestrictTy(StructStatPtrTy); - if (StructStatPtrTy) - // int fstat(int fd, struct stat *statbuf); - addToFunctionSummaryMap( - "fstat", - Summary(ArgTypes{IntTy, *StructStatPtrTy}, RetType{IntTy}, NoEvalCall) - .ArgConstraint( - ArgumentCondition(0, WithinRange, Range(0, IntMax))) - .ArgConstraint(NotNull(ArgNo(1)))); + // int fstat(int fd, struct stat *statbuf); + addToFunctionSummaryMap( + "fstat", + Summary(ArgTypes{IntTy, StructStatPtrTy}, RetType{IntTy}, NoEvalCall) + .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))) + .ArgConstraint(NotNull(ArgNo(1)))); - if (StructStatPtrRestrictTy) { - // int stat(const char *restrict path, struct stat *restrict buf); - addToFunctionSummaryMap( - "stat", - Summary(ArgTypes{ConstCharPtrRestrictTy, *StructStatPtrRestrictTy}, - RetType{IntTy}, NoEvalCall) - .ArgConstraint(NotNull(ArgNo(0))) - .ArgConstraint(NotNull(ArgNo(1)))); + // int stat(const char *restrict path, struct stat *restrict buf); + addToFunctionSummaryMap("stat", Summary(ArgTypes{ConstCharPtrRestrictTy, + StructStatPtrRestrictTy}, + RetType{IntTy}, NoEvalCall) + .ArgConstraint(NotNull(ArgNo(0))) + .ArgConstraint(NotNull(ArgNo(1)))); + + // int lstat(const char *restrict path, struct stat *restrict buf); + addToFunctionSummaryMap("lstat", Summary(ArgTypes{ConstCharPtrRestrictTy, + StructStatPtrRestrictTy}, + RetType{IntTy}, NoEvalCall) + .ArgConstraint(NotNull(ArgNo(0))) + .ArgConstraint(NotNull(ArgNo(1)))); + + // int fstatat(int fd, const char *restrict path, + // struct stat *restrict buf, int flag); + addToFunctionSummaryMap( + "fstatat", + Summary(ArgTypes{IntTy, ConstCharPtrRestrictTy, StructStatPtrRestrictTy, + IntTy}, + RetType{IntTy}, NoEvalCall) + .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))) + .ArgConstraint(NotNull(ArgNo(1))) + .ArgConstraint(NotNull(ArgNo(2)))); - // int lstat(const char *restrict path, struct stat *restrict buf); - addToFunctionSummaryMap( - "lstat", - Summary(ArgTypes{ConstCharPtrRestrictTy, *StructStatPtrRestrictTy}, - RetType{IntTy}, NoEvalCall) - .ArgConstraint(NotNull(ArgNo(0))) - .ArgConstraint(NotNull(ArgNo(1)))); + // DIR *opendir(const char *name); + addToFunctionSummaryMap("opendir", Summary(ArgTypes{ConstCharPtrTy}, + RetType{DirPtrTy}, NoEvalCall) + .ArgConstraint(NotNull(ArgNo(0)))); - // int fstatat(int fd, const char *restrict path, - // struct stat *restrict buf, int flag); - addToFunctionSummaryMap( - "fstatat", Summary(ArgTypes{IntTy, ConstCharPtrRestrictTy, - *StructStatPtrRestrictTy, IntTy}, - RetType{IntTy}, NoEvalCall) + // DIR *fdopendir(int fd); + addToFunctionSummaryMap( + "fdopendir", Summary(ArgTypes{IntTy}, RetType{DirPtrTy}, NoEvalCall) .ArgConstraint(ArgumentCondition(0, WithinRange, - Range(0, IntMax))) - .ArgConstraint(NotNull(ArgNo(1))) - .ArgConstraint(NotNull(ArgNo(2)))); - } - - if (DirPtrTy) { - // DIR *opendir(const char *name); - addToFunctionSummaryMap("opendir", Summary(ArgTypes{ConstCharPtrTy}, - RetType{*DirPtrTy}, NoEvalCall) - .ArgConstraint(NotNull(ArgNo(0)))); - - // DIR *fdopendir(int fd); - addToFunctionSummaryMap( - "fdopendir", Summary(ArgTypes{IntTy}, RetType{*DirPtrTy}, NoEvalCall) - .ArgConstraint(ArgumentCondition(0, WithinRange, - Range(0, IntMax)))); - } + Range(0, IntMax)))); // int isatty(int fildes); addToFunctionSummaryMap( @@ -1510,19 +1566,17 @@ .ArgConstraint( ArgumentCondition(0, WithinRange, Range(0, IntMax)))); - if (FilePtrTy) { - // FILE *popen(const char *command, const char *type); - addToFunctionSummaryMap("popen", - Summary(ArgTypes{ConstCharPtrTy, ConstCharPtrTy}, - RetType{*FilePtrTy}, NoEvalCall) - .ArgConstraint(NotNull(ArgNo(0))) - .ArgConstraint(NotNull(ArgNo(1)))); + // FILE *popen(const char *command, const char *type); + addToFunctionSummaryMap("popen", + Summary(ArgTypes{ConstCharPtrTy, ConstCharPtrTy}, + RetType{FilePtrTy}, NoEvalCall) + .ArgConstraint(NotNull(ArgNo(0))) + .ArgConstraint(NotNull(ArgNo(1)))); - // int pclose(FILE *stream); - addToFunctionSummaryMap( - "pclose", Summary(ArgTypes{*FilePtrTy}, RetType{IntTy}, NoEvalCall) - .ArgConstraint(NotNull(ArgNo(0)))); - } + // int pclose(FILE *stream); + addToFunctionSummaryMap( + "pclose", Summary(ArgTypes{FilePtrTy}, RetType{IntTy}, NoEvalCall) + .ArgConstraint(NotNull(ArgNo(0)))); // int close(int fildes); addToFunctionSummaryMap( @@ -1542,26 +1596,22 @@ RetType{LongTy}, NoEvalCall) .ArgConstraint(NotNull(ArgNo(0)))); - if (FilePtrTy) - // FILE *fdopen(int fd, const char *mode); - addToFunctionSummaryMap( - "fdopen", Summary(ArgTypes{IntTy, ConstCharPtrTy}, - RetType{*FilePtrTy}, NoEvalCall) - .ArgConstraint( - ArgumentCondition(0, WithinRange, Range(0, IntMax))) - .ArgConstraint(NotNull(ArgNo(1)))); - - if (DirPtrTy) { - // void rewinddir(DIR *dir); - addToFunctionSummaryMap( - "rewinddir", Summary(ArgTypes{*DirPtrTy}, RetType{VoidTy}, NoEvalCall) - .ArgConstraint(NotNull(ArgNo(0)))); + // FILE *fdopen(int fd, const char *mode); + addToFunctionSummaryMap( + "fdopen", + Summary(ArgTypes{IntTy, ConstCharPtrTy}, RetType{FilePtrTy}, NoEvalCall) + .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))) + .ArgConstraint(NotNull(ArgNo(1)))); - // void seekdir(DIR *dirp, long loc); - addToFunctionSummaryMap("seekdir", Summary(ArgTypes{*DirPtrTy, LongTy}, - RetType{VoidTy}, NoEvalCall) - .ArgConstraint(NotNull(ArgNo(0)))); - } + // void rewinddir(DIR *dir); + addToFunctionSummaryMap( + "rewinddir", Summary(ArgTypes{DirPtrTy}, RetType{VoidTy}, NoEvalCall) + .ArgConstraint(NotNull(ArgNo(0)))); + + // void seekdir(DIR *dirp, long loc); + addToFunctionSummaryMap("seekdir", Summary(ArgTypes{DirPtrTy, LongTy}, + RetType{VoidTy}, NoEvalCall) + .ArgConstraint(NotNull(ArgNo(0)))); // int rand_r(unsigned int *seedp); addToFunctionSummaryMap("rand_r", Summary(ArgTypes{UnsignedIntPtrTy}, @@ -1584,100 +1634,86 @@ .ArgConstraint(ArgumentCondition( 2, WithinRange, Range(0, SizeMax)))); - if (FilePtrTy && Off_tTy) { - - // int fileno(FILE *stream); - addToFunctionSummaryMap( - "fileno", Summary(ArgTypes{*FilePtrTy}, RetType{IntTy}, NoEvalCall) - .ArgConstraint(NotNull(ArgNo(0)))); - - // int fseeko(FILE *stream, off_t offset, int whence); - addToFunctionSummaryMap("fseeko", - Summary(ArgTypes{*FilePtrTy, *Off_tTy, IntTy}, - RetType{IntTy}, NoEvalCall) - .ArgConstraint(NotNull(ArgNo(0)))); + // int fileno(FILE *stream); + addToFunctionSummaryMap( + "fileno", Summary(ArgTypes{FilePtrTy}, RetType{IntTy}, NoEvalCall) + .ArgConstraint(NotNull(ArgNo(0)))); - // off_t ftello(FILE *stream); - addToFunctionSummaryMap( - "ftello", Summary(ArgTypes{*FilePtrTy}, RetType{*Off_tTy}, NoEvalCall) - .ArgConstraint(NotNull(ArgNo(0)))); - } + // int fseeko(FILE *stream, off_t offset, int whence); + addToFunctionSummaryMap( + "fseeko", + Summary(ArgTypes{FilePtrTy, Off_tTy, IntTy}, RetType{IntTy}, NoEvalCall) + .ArgConstraint(NotNull(ArgNo(0)))); - if (Off_tTy) { - Optional Off_tMax = BVF.getMaxValue(*Off_tTy).getLimitedValue(); + // off_t ftello(FILE *stream); + addToFunctionSummaryMap( + "ftello", Summary(ArgTypes{FilePtrTy}, RetType{Off_tTy}, NoEvalCall) + .ArgConstraint(NotNull(ArgNo(0)))); - // void *mmap(void *addr, size_t length, int prot, int flags, int fd, - // off_t offset); - addToFunctionSummaryMap( - "mmap", - Summary(ArgTypes{VoidPtrTy, SizeTy, IntTy, IntTy, IntTy, *Off_tTy}, - RetType{VoidPtrTy}, NoEvalCall) - .ArgConstraint( - ArgumentCondition(1, WithinRange, Range(1, SizeMax))) - .ArgConstraint( - ArgumentCondition(4, WithinRange, Range(0, *Off_tMax)))); - } + Optional Off_tMax = getMaxValue(Off_tTy); + // void *mmap(void *addr, size_t length, int prot, int flags, int fd, + // off_t offset); + addToFunctionSummaryMap( + "mmap", + Summary(ArgTypes{VoidPtrTy, SizeTy, IntTy, IntTy, IntTy, Off_tTy}, + RetType{VoidPtrTy}, NoEvalCall) + .ArgConstraint(ArgumentCondition(1, WithinRange, Range(1, SizeMax))) + .ArgConstraint( + ArgumentCondition(4, WithinRange, Range(0, Off_tMax)))); - Optional Off64_tTy = lookupType("off64_t", ACtx); - Optional Off64_tMax; - if (Off64_tTy) { - Off64_tMax = BVF.getMaxValue(*Off_tTy).getLimitedValue(); - // void *mmap64(void *addr, size_t length, int prot, int flags, int fd, - // off64_t offset); - addToFunctionSummaryMap( - "mmap64", - Summary(ArgTypes{VoidPtrTy, SizeTy, IntTy, IntTy, IntTy, *Off64_tTy}, - RetType{VoidPtrTy}, NoEvalCall) - .ArgConstraint( - ArgumentCondition(1, WithinRange, Range(1, SizeMax))) - .ArgConstraint( - ArgumentCondition(4, WithinRange, Range(0, *Off64_tMax)))); - } + Optional Off64_tTy = lookupTy("off64_t"); + Optional Off64_tMax = getMaxValue(Off_tTy); + // void *mmap64(void *addr, size_t length, int prot, int flags, int fd, + // off64_t offset); + addToFunctionSummaryMap( + "mmap64", + Summary(ArgTypes{VoidPtrTy, SizeTy, IntTy, IntTy, IntTy, Off64_tTy}, + RetType{VoidPtrTy}, NoEvalCall) + .ArgConstraint(ArgumentCondition(1, WithinRange, Range(1, SizeMax))) + .ArgConstraint( + ArgumentCondition(4, WithinRange, Range(0, Off64_tMax)))); // int pipe(int fildes[2]); addToFunctionSummaryMap( "pipe", Summary(ArgTypes{IntPtrTy}, RetType{IntTy}, NoEvalCall) .ArgConstraint(NotNull(ArgNo(0)))); - if (Off_tTy) - // off_t lseek(int fildes, off_t offset, int whence); - addToFunctionSummaryMap( - "lseek", Summary(ArgTypes{IntTy, *Off_tTy, IntTy}, RetType{*Off_tTy}, - NoEvalCall) - .ArgConstraint(ArgumentCondition(0, WithinRange, - Range(0, IntMax)))); + // off_t lseek(int fildes, off_t offset, int whence); + addToFunctionSummaryMap( + "lseek", + Summary(ArgTypes{IntTy, Off_tTy, IntTy}, RetType{Off_tTy}, NoEvalCall) + .ArgConstraint( + ArgumentCondition(0, WithinRange, Range(0, IntMax)))); - Optional Ssize_tTy = lookupType("ssize_t", ACtx); + Optional Ssize_tTy = lookupTy("ssize_t"); - if (Ssize_tTy) { - // ssize_t readlink(const char *restrict path, char *restrict buf, - // size_t bufsize); - addToFunctionSummaryMap( - "readlink", - Summary(ArgTypes{ConstCharPtrRestrictTy, CharPtrRestrictTy, SizeTy}, - RetType{*Ssize_tTy}, NoEvalCall) - .ArgConstraint(NotNull(ArgNo(0))) - .ArgConstraint(NotNull(ArgNo(1))) - .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1), - /*BufSize=*/ArgNo(2))) - .ArgConstraint( - ArgumentCondition(2, WithinRange, Range(0, SizeMax)))); + // ssize_t readlink(const char *restrict path, char *restrict buf, + // size_t bufsize); + addToFunctionSummaryMap( + "readlink", + Summary(ArgTypes{ConstCharPtrRestrictTy, CharPtrRestrictTy, SizeTy}, + RetType{Ssize_tTy}, NoEvalCall) + .ArgConstraint(NotNull(ArgNo(0))) + .ArgConstraint(NotNull(ArgNo(1))) + .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1), + /*BufSize=*/ArgNo(2))) + .ArgConstraint( + ArgumentCondition(2, WithinRange, Range(0, SizeMax)))); - // ssize_t readlinkat(int fd, const char *restrict path, - // char *restrict buf, size_t bufsize); - addToFunctionSummaryMap( - "readlinkat", Summary(ArgTypes{IntTy, ConstCharPtrRestrictTy, - CharPtrRestrictTy, SizeTy}, - RetType{*Ssize_tTy}, NoEvalCall) - .ArgConstraint(ArgumentCondition(0, WithinRange, - Range(0, IntMax))) - .ArgConstraint(NotNull(ArgNo(1))) - .ArgConstraint(NotNull(ArgNo(2))) - .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(2), - /*BufSize=*/ArgNo(3))) - .ArgConstraint(ArgumentCondition( - 3, WithinRange, Range(0, SizeMax)))); - } + // ssize_t readlinkat(int fd, const char *restrict path, + // char *restrict buf, size_t bufsize); + addToFunctionSummaryMap( + "readlinkat", + Summary( + ArgTypes{IntTy, ConstCharPtrRestrictTy, CharPtrRestrictTy, SizeTy}, + RetType{Ssize_tTy}, NoEvalCall) + .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))) + .ArgConstraint(NotNull(ArgNo(1))) + .ArgConstraint(NotNull(ArgNo(2))) + .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(2), + /*BufSize=*/ArgNo(3))) + .ArgConstraint( + ArgumentCondition(3, WithinRange, Range(0, SizeMax)))); // int renameat(int olddirfd, const char *oldpath, int newdirfd, const char // *newpath); @@ -1694,7 +1730,7 @@ RetType{CharPtrTy}, NoEvalCall) .ArgConstraint(NotNull(ArgNo(0)))); - QualType CharPtrConstPtr = ACtx.getPointerType(CharPtrTy.withConst()); + QualType CharPtrConstPtr = getPointerTy(getConstTy(CharPtrTy)); // int execv(const char *path, char *const argv[]); addToFunctionSummaryMap("execv", @@ -1717,25 +1753,18 @@ .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); - } + Optional StructSockaddrTy = lookupTy("sockaddr"); + Optional StructSockaddrPtrTy = getPointerTy(StructSockaddrTy); + Optional ConstStructSockaddrPtrTy = + getPointerTy(getConstTy(StructSockaddrTy)); + Optional StructSockaddrPtrRestrictTy = + getRestrictTy(StructSockaddrPtrTy); + Optional ConstStructSockaddrPtrRestrictTy = + getRestrictTy(ConstStructSockaddrPtrTy); + Optional Socklen_tTy = lookupTy("socklen_t"); + Optional Socklen_tPtrTy = getPointerTy(Socklen_tTy); + Optional Socklen_tPtrRestrictTy = getRestrictTy(Socklen_tPtrTy); + Optional Socklen_tMax = getMaxValue(Socklen_tTy); // In 'socket.h' of some libc implementations with C99, sockaddr parameter // is a transparent union of the underlying sockaddr_ family of pointers @@ -1743,143 +1772,137 @@ // 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( + auto Accept = + Summary(NoEvalCall) + .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax))); + if (!addToFunctionSummaryMap( "accept", - Signature(ArgTypes{IntTy, Irrelevant, *Socklen_tPtrRestrictTy}, + // int accept(int socket, struct sockaddr *restrict address, + // socklen_t *restrict address_len); + Signature(ArgTypes{IntTy, StructSockaddrPtrRestrictTy, + 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}, + 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)))); - - // 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}, + 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)))); - - // 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( + 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 (!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, - 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( + 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 (!addToFunctionSummaryMap( "sendto", - Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTy, IntTy, Irrelevant, - *Socklen_tTy}, - RetType{*Ssize_tTy}), - 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( @@ -1887,72 +1910,64 @@ .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()); - } + // 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)))); - 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)))); + Optional StructMsghdrTy = lookupTy("msghdr"); + Optional StructMsghdrPtrTy = getPointerTy(StructMsghdrTy); + Optional ConstStructMsghdrPtrTy = + getPointerTy(getConstTy(StructMsghdrTy)); - 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)))); + // 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 (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)))); + // 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_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 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)))); + + // 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)))); + + // 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", @@ -1960,32 +1975,31 @@ 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)))); + // 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-lookup.c b/clang/test/Analysis/std-c-library-functions-POSIX-lookup.c new file mode 100644 --- /dev/null +++ b/clang/test/Analysis/std-c-library-functions-POSIX-lookup.c @@ -0,0 +1,22 @@ +// 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 --allow-empty + +// We test here the implementation of our summary API with Optional types. In +// this TU we do not provide declaration for any of the functions that have +// summaries. The implementation should be able to handle the nonexistent +// declarations in a way that the summary is not added to the map. We expect no +// crashes (i.e. no optionals should be 'dereferenced') and no output. + +// Must have at least one call expression to initialize the summary map. +int bar(void); +void foo() { + bar(); +} + +// CHECK-NOT: Loaded summary for: