123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688 |
- //=== StdLibraryFunctionsChecker.cpp - Model standard functions -*- C++ -*-===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- //
- // This checker improves modeling of a few simple library functions.
- //
- // This checker provides a specification format - `Summary' - and
- // contains descriptions of some library functions in this format. Each
- // specification contains a list of branches for splitting the program state
- // upon call, and range constraints on argument and return-value symbols that
- // are satisfied on each branch. This spec can be expanded to include more
- // items, like external effects of the function.
- //
- // The main difference between this approach and the body farms technique is
- // in more explicit control over how many branches are produced. For example,
- // consider standard C function `ispunct(int x)', which returns a non-zero value
- // iff `x' is a punctuation character, that is, when `x' is in range
- // ['!', '/'] [':', '@'] U ['[', '\`'] U ['{', '~'].
- // `Summary' provides only two branches for this function. However,
- // any attempt to describe this range with if-statements in the body farm
- // would result in many more branches. Because each branch needs to be analyzed
- // independently, this significantly reduces performance. Additionally,
- // once we consider a branch on which `x' is in range, say, ['!', '/'],
- // we assume that such branch is an important separate path through the program,
- // which may lead to false positives because considering this particular path
- // was not consciously intended, and therefore it might have been unreachable.
- //
- // This checker uses eval::Call for modeling pure functions (functions without
- // side effets), for which their `Summary' is a precise model. This avoids
- // unnecessary invalidation passes. Conflicts with other checkers are unlikely
- // because if the function has no other effects, other checkers would probably
- // never want to improve upon the modeling done by this checker.
- //
- // Non-pure functions, for which only partial improvement over the default
- // behavior is expected, are modeled via check::PostCall, non-intrusively.
- //
- // The following standard C functions are currently supported:
- //
- // fgetc getline isdigit isupper toascii
- // fread isalnum isgraph isxdigit
- // fwrite isalpha islower read
- // getc isascii isprint write
- // getchar isblank ispunct toupper
- // getdelim iscntrl isspace tolower
- //
- //===----------------------------------------------------------------------===//
- #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
- #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
- #include "clang/StaticAnalyzer/Core/Checker.h"
- #include "clang/StaticAnalyzer/Core/CheckerManager.h"
- #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
- #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
- #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h"
- #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicExtent.h"
- #include "llvm/ADT/SmallString.h"
- #include "llvm/ADT/StringExtras.h"
- #include <string>
- using namespace clang;
- using namespace clang::ento;
- namespace {
- class StdLibraryFunctionsChecker
- : public Checker<check::PreCall, check::PostCall, eval::Call> {
- class Summary;
- /// Specify how much the analyzer engine should entrust modeling this function
- /// to us. If he doesn't, he performs additional invalidations.
- enum InvalidationKind { NoEvalCall, EvalCallAsPure };
- // The universal integral type to use in value range descriptions.
- // Unsigned to make sure overflows are well-defined.
- typedef uint64_t RangeInt;
- /// Normally, describes a single range constraint, eg. {{0, 1}, {3, 4}} is
- /// a non-negative integer, which less than 5 and not equal to 2. For
- /// `ComparesToArgument', holds information about how exactly to compare to
- /// the argument.
- typedef std::vector<std::pair<RangeInt, RangeInt>> IntRangeVector;
- /// A reference to an argument or return value by its number.
- /// ArgNo in CallExpr and CallEvent is defined as Unsigned, but
- /// obviously uint32_t should be enough for all practical purposes.
- typedef uint32_t ArgNo;
- static const ArgNo Ret;
- /// Returns the string representation of an argument index.
- /// E.g.: (1) -> '1st arg', (2) - > '2nd arg'
- static SmallString<8> getArgDesc(ArgNo);
- class ValueConstraint;
- // Pointer to the ValueConstraint. We need a copyable, polymorphic and
- // default initialize able type (vector needs that). A raw pointer was good,
- // however, we cannot default initialize that. unique_ptr makes the Summary
- // class non-copyable, therefore not an option. Releasing the copyability
- // requirement would render the initialization of the Summary map infeasible.
- using ValueConstraintPtr = std::shared_ptr<ValueConstraint>;
- /// Polymorphic base class that represents a constraint on a given argument
- /// (or return value) of a function. Derived classes implement different kind
- /// of constraints, e.g range constraints or correlation between two
- /// arguments.
- class ValueConstraint {
- public:
- ValueConstraint(ArgNo ArgN) : ArgN(ArgN) {}
- virtual ~ValueConstraint() {}
- /// Apply the effects of the constraint on the given program state. If null
- /// is returned then the constraint is not feasible.
- virtual ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
- const Summary &Summary,
- CheckerContext &C) const = 0;
- virtual ValueConstraintPtr negate() const {
- llvm_unreachable("Not implemented");
- };
- // Check whether the constraint is malformed or not. It is malformed if the
- // specified argument has a mismatch with the given FunctionDecl (e.g. the
- // arg number is out-of-range of the function's argument list).
- bool checkValidity(const FunctionDecl *FD) const {
- const bool ValidArg = ArgN == Ret || ArgN < FD->getNumParams();
- assert(ValidArg && "Arg out of range!");
- if (!ValidArg)
- return false;
- // Subclasses may further refine the validation.
- return checkSpecificValidity(FD);
- }
- ArgNo getArgNo() const { return ArgN; }
- // Return those arguments that should be tracked when we report a bug. By
- // default it is the argument that is constrained, however, in some special
- // cases we need to track other arguments as well. E.g. a buffer size might
- // be encoded in another argument.
- virtual std::vector<ArgNo> getArgsToTrack() const { return {ArgN}; }
- virtual StringRef getName() const = 0;
- // Give a description that explains the constraint to the user. Used when
- // the bug is reported.
- virtual std::string describe(ProgramStateRef State,
- const Summary &Summary) const {
- // There are some descendant classes that are not used as argument
- // constraints, e.g. ComparisonConstraint. In that case we can safely
- // ignore the implementation of this function.
- llvm_unreachable("Not implemented");
- }
- protected:
- ArgNo ArgN; // Argument to which we apply the constraint.
- /// Do polymorphic validation check on the constraint.
- virtual bool checkSpecificValidity(const FunctionDecl *FD) const {
- return true;
- }
- };
- /// Given a range, should the argument stay inside or outside this range?
- enum RangeKind { OutOfRange, WithinRange };
- /// Encapsulates a range on a single symbol.
- class RangeConstraint : public ValueConstraint {
- 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:
- StringRef getName() const override { return "Range"; }
- RangeConstraint(ArgNo ArgN, RangeKind Kind, const IntRangeVector &Ranges)
- : ValueConstraint(ArgN), Kind(Kind), Ranges(Ranges) {}
- std::string describe(ProgramStateRef State,
- const Summary &Summary) const override;
- const IntRangeVector &getRanges() const { return Ranges; }
- private:
- ProgramStateRef applyAsOutOfRange(ProgramStateRef State,
- const CallEvent &Call,
- const Summary &Summary) const;
- ProgramStateRef applyAsWithinRange(ProgramStateRef State,
- const CallEvent &Call,
- const Summary &Summary) const;
- public:
- ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
- const Summary &Summary,
- CheckerContext &C) const override {
- switch (Kind) {
- case OutOfRange:
- return applyAsOutOfRange(State, Call, Summary);
- case WithinRange:
- return applyAsWithinRange(State, Call, Summary);
- }
- llvm_unreachable("Unknown range kind!");
- }
- ValueConstraintPtr negate() const override {
- RangeConstraint Tmp(*this);
- switch (Kind) {
- case OutOfRange:
- Tmp.Kind = WithinRange;
- break;
- case WithinRange:
- Tmp.Kind = OutOfRange;
- break;
- }
- return std::make_shared<RangeConstraint>(Tmp);
- }
- bool checkSpecificValidity(const FunctionDecl *FD) const override {
- const bool ValidArg =
- getArgType(FD, ArgN)->isIntegralType(FD->getASTContext());
- assert(ValidArg &&
- "This constraint should be applied on an integral type");
- return ValidArg;
- }
- };
- class ComparisonConstraint : public ValueConstraint {
- BinaryOperator::Opcode Opcode;
- ArgNo OtherArgN;
- public:
- virtual StringRef getName() const override { return "Comparison"; };
- ComparisonConstraint(ArgNo ArgN, BinaryOperator::Opcode Opcode,
- ArgNo OtherArgN)
- : ValueConstraint(ArgN), Opcode(Opcode), OtherArgN(OtherArgN) {}
- ArgNo getOtherArgNo() const { return OtherArgN; }
- BinaryOperator::Opcode getOpcode() const { return Opcode; }
- ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
- const Summary &Summary,
- CheckerContext &C) const override;
- };
- class NotNullConstraint : public ValueConstraint {
- using ValueConstraint::ValueConstraint;
- // This variable has a role when we negate the constraint.
- bool CannotBeNull = true;
- public:
- std::string describe(ProgramStateRef State,
- const Summary &Summary) const override;
- StringRef getName() const override { return "NonNull"; }
- ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
- const Summary &Summary,
- CheckerContext &C) const override {
- SVal V = getArgSVal(Call, getArgNo());
- if (V.isUndef())
- return State;
- DefinedOrUnknownSVal L = V.castAs<DefinedOrUnknownSVal>();
- if (!L.getAs<Loc>())
- return State;
- return State->assume(L, CannotBeNull);
- }
- ValueConstraintPtr negate() const override {
- NotNullConstraint Tmp(*this);
- Tmp.CannotBeNull = !this->CannotBeNull;
- return std::make_shared<NotNullConstraint>(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;
- }
- };
- // Represents a buffer argument with an additional size constraint. The
- // constraint may be a concrete value, or a symbolic value in an argument.
- // Example 1. Concrete value as the minimum buffer size.
- // char *asctime_r(const struct tm *restrict tm, char *restrict buf);
- // // `buf` size must be at least 26 bytes according the POSIX standard.
- // Example 2. Argument as a buffer size.
- // ctime_s(char *buffer, rsize_t bufsz, const time_t *time);
- // Example 3. The size is computed as a multiplication of other args.
- // size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
- // // Here, ptr is the buffer, and its minimum size is `size * nmemb`.
- class BufferSizeConstraint : public ValueConstraint {
- // The concrete value which is the minimum size for the buffer.
- llvm::Optional<llvm::APSInt> ConcreteSize;
- // The argument which holds the size of the buffer.
- llvm::Optional<ArgNo> SizeArgN;
- // The argument which is a multiplier to size. This is set in case of
- // `fread` like functions where the size is computed as a multiplication of
- // two arguments.
- llvm::Optional<ArgNo> SizeMultiplierArgN;
- // The operator we use in apply. This is negated in negate().
- BinaryOperator::Opcode Op = BO_LE;
- public:
- StringRef getName() const override { return "BufferSize"; }
- BufferSizeConstraint(ArgNo Buffer, llvm::APSInt BufMinSize)
- : ValueConstraint(Buffer), ConcreteSize(BufMinSize) {}
- BufferSizeConstraint(ArgNo Buffer, ArgNo BufSize)
- : ValueConstraint(Buffer), SizeArgN(BufSize) {}
- BufferSizeConstraint(ArgNo Buffer, ArgNo BufSize, ArgNo BufSizeMultiplier)
- : ValueConstraint(Buffer), SizeArgN(BufSize),
- SizeMultiplierArgN(BufSizeMultiplier) {}
- std::vector<ArgNo> getArgsToTrack() const override {
- std::vector<ArgNo> Result{ArgN};
- if (SizeArgN)
- Result.push_back(*SizeArgN);
- if (SizeMultiplierArgN)
- Result.push_back(*SizeMultiplierArgN);
- return Result;
- }
- std::string describe(ProgramStateRef State,
- const Summary &Summary) const override;
- ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
- const Summary &Summary,
- CheckerContext &C) const override {
- SValBuilder &SvalBuilder = C.getSValBuilder();
- // The buffer argument.
- SVal BufV = getArgSVal(Call, getArgNo());
- // Get the size constraint.
- const SVal SizeV = [this, &State, &Call, &Summary, &SvalBuilder]() {
- if (ConcreteSize) {
- return SVal(SvalBuilder.makeIntVal(*ConcreteSize));
- }
- assert(SizeArgN && "The constraint must be either a concrete value or "
- "encoded in an argument.");
- // The size argument.
- SVal SizeV = getArgSVal(Call, *SizeArgN);
- // Multiply with another argument if given.
- if (SizeMultiplierArgN) {
- SVal SizeMulV = getArgSVal(Call, *SizeMultiplierArgN);
- SizeV = SvalBuilder.evalBinOp(State, BO_Mul, SizeV, SizeMulV,
- Summary.getArgType(*SizeArgN));
- }
- return SizeV;
- }();
- // The dynamic size of the buffer argument, got from the analyzer engine.
- SVal BufDynSize = getDynamicExtentWithOffset(State, BufV);
- SVal Feasible = SvalBuilder.evalBinOp(State, Op, SizeV, BufDynSize,
- SvalBuilder.getContext().BoolTy);
- if (auto F = Feasible.getAs<DefinedOrUnknownSVal>())
- return State->assume(*F, true);
- // We can get here only if the size argument or the dynamic size is
- // undefined. But the dynamic size should never be undefined, only
- // unknown. So, here, the size of the argument is undefined, i.e. we
- // cannot apply the constraint. Actually, other checkers like
- // CallAndMessage should catch this situation earlier, because we call a
- // function with an uninitialized argument.
- llvm_unreachable("Size argument or the dynamic size is Undefined");
- }
- ValueConstraintPtr negate() const override {
- BufferSizeConstraint Tmp(*this);
- 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.
- typedef std::vector<ValueConstraintPtr> ConstraintSet;
- using ArgTypes = std::vector<Optional<QualType>>;
- using RetType = Optional<QualType>;
- // A placeholder type, we use it whenever we do not care about the concrete
- // type in a Signature.
- const QualType Irrelevant{};
- bool static isIrrelevant(QualType T) { return T.isNull(); }
- // 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.
- // All types in the spec need to be canonical.
- class Signature {
- using ArgQualTypes = std::vector<QualType>;
- ArgQualTypes ArgTys;
- QualType RetTy;
- // 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<QualType> 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:
- static void assertArgTypeSuitableForSignature(QualType T) {
- assert((T.isNull() || !T->isVoidType()) &&
- "We should have no void types in the spec");
- assert((T.isNull() || T.isCanonical()) &&
- "We should only have canonical types in the spec");
- }
- static void assertRetTypeSuitableForSignature(QualType T) {
- assert((T.isNull() || T.isCanonical()) &&
- "We should only have canonical types in the spec");
- }
- };
- static QualType getArgType(const FunctionDecl *FD, ArgNo ArgN) {
- assert(FD && "Function must be set");
- QualType T = (ArgN == Ret)
- ? FD->getReturnType().getCanonicalType()
- : FD->getParamDecl(ArgN)->getType().getCanonicalType();
- return T;
- }
- using Cases = std::vector<ConstraintSet>;
- /// A summary includes information about
- /// * function prototype (signature)
- /// * approach to invalidation,
- /// * a list of branches - a list of list of ranges -
- /// A branch represents a path in the exploded graph of a function (which
- /// is a tree). So, a branch is a series of assumptions. In other words,
- /// branches represent split states and additional assumptions on top of
- /// the splitting assumption.
- /// For example, consider the branches in `isalpha(x)`
- /// Branch 1)
- /// x is in range ['A', 'Z'] or in ['a', 'z']
- /// then the return value is not 0. (I.e. out-of-range [0, 0])
- /// Branch 2)
- /// x is out-of-range ['A', 'Z'] and out-of-range ['a', 'z']
- /// then the return value is 0.
- /// * a list of argument constraints, that must be true on every branch.
- /// If these constraints are not satisfied that means a fatal error
- /// usually resulting in undefined behaviour.
- ///
- /// Application of a summary:
- /// The signature and argument constraints together contain information
- /// about which functions are handled by the summary. The signature can use
- /// "wildcards", i.e. Irrelevant types. Irrelevant type of a parameter in
- /// a signature means that type is not compared to the type of the parameter
- /// in the found FunctionDecl. Argument constraints may specify additional
- /// rules for the given parameter's type, those rules are checked once the
- /// signature is matched.
- class Summary {
- const InvalidationKind InvalidationKd;
- Cases CaseConstraints;
- ConstraintSet ArgConstraints;
- // The function to which the summary applies. This is set after lookup and
- // match to the signature.
- const FunctionDecl *FD = nullptr;
- public:
- Summary(InvalidationKind InvalidationKd) : InvalidationKd(InvalidationKd) {}
- Summary &Case(ConstraintSet &&CS) {
- CaseConstraints.push_back(std::move(CS));
- return *this;
- }
- Summary &Case(const ConstraintSet &CS) {
- CaseConstraints.push_back(CS);
- return *this;
- }
- Summary &ArgConstraint(ValueConstraintPtr VC) {
- assert(VC->getArgNo() != Ret &&
- "Arg constraint should not refer to the return value");
- ArgConstraints.push_back(VC);
- return *this;
- }
- InvalidationKind getInvalidationKd() const { return InvalidationKd; }
- const Cases &getCaseConstraints() const { return CaseConstraints; }
- const ConstraintSet &getArgConstraints() const { return ArgConstraints; }
- QualType getArgType(ArgNo ArgN) const {
- return StdLibraryFunctionsChecker::getArgType(FD, ArgN);
- }
- // Returns true if the summary should be applied to the given function.
- // And if yes then store the function declaration.
- bool matchesAndSet(const Signature &Sign, const FunctionDecl *FD) {
- bool Result = Sign.matches(FD) && validateByConstraints(FD);
- if (Result) {
- assert(!this->FD && "FD must not be set more than once");
- this->FD = FD;
- }
- return Result;
- }
- private:
- // Once we know the exact type of the function then do validation check on
- // all the given constraints.
- bool validateByConstraints(const FunctionDecl *FD) const {
- for (const ConstraintSet &Case : CaseConstraints)
- for (const ValueConstraintPtr &Constraint : Case)
- if (!Constraint->checkValidity(FD))
- return false;
- for (const ValueConstraintPtr &Constraint : ArgConstraints)
- if (!Constraint->checkValidity(FD))
- return false;
- return true;
- }
- };
- // The map of all functions supported by the checker. It is initialized
- // lazily, and it doesn't change after initialization.
- using FunctionSummaryMapType = llvm::DenseMap<const FunctionDecl *, Summary>;
- mutable FunctionSummaryMapType FunctionSummaryMap;
- mutable std::unique_ptr<BugType> BT_InvalidArg;
- mutable bool SummariesInitialized = false;
- static SVal getArgSVal(const CallEvent &Call, ArgNo ArgN) {
- return ArgN == Ret ? Call.getReturnValue() : Call.getArgSVal(ArgN);
- }
- public:
- void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
- void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
- bool evalCall(const CallEvent &Call, CheckerContext &C) const;
- enum CheckKind {
- CK_StdCLibraryFunctionArgsChecker,
- CK_StdCLibraryFunctionsTesterChecker,
- CK_NumCheckKinds
- };
- DefaultBool ChecksEnabled[CK_NumCheckKinds];
- CheckerNameRef CheckNames[CK_NumCheckKinds];
- bool DisplayLoadedSummaries = false;
- bool ModelPOSIX = false;
- bool ShouldAssumeControlledEnvironment = false;
- private:
- Optional<Summary> findFunctionSummary(const FunctionDecl *FD,
- CheckerContext &C) const;
- Optional<Summary> findFunctionSummary(const CallEvent &Call,
- CheckerContext &C) const;
- void initFunctionSummaries(CheckerContext &C) const;
- void reportBug(const CallEvent &Call, ExplodedNode *N,
- const ValueConstraint *VC, const Summary &Summary,
- CheckerContext &C) const {
- if (!ChecksEnabled[CK_StdCLibraryFunctionArgsChecker])
- return;
- std::string Msg =
- (Twine("Function argument constraint is not satisfied, constraint: ") +
- VC->getName().data())
- .str();
- if (!BT_InvalidArg)
- BT_InvalidArg = std::make_unique<BugType>(
- CheckNames[CK_StdCLibraryFunctionArgsChecker],
- "Unsatisfied argument constraints", categories::LogicError);
- auto R = std::make_unique<PathSensitiveBugReport>(*BT_InvalidArg, Msg, N);
- for (ArgNo ArgN : VC->getArgsToTrack())
- bugreporter::trackExpressionValue(N, Call.getArgExpr(ArgN), *R);
- // Highlight the range of the argument that was violated.
- R->addRange(Call.getArgSourceRange(VC->getArgNo()));
- // Describe the argument constraint in a note.
- R->addNote(VC->describe(C.getState(), Summary), R->getLocation(),
- Call.getArgSourceRange(VC->getArgNo()));
- C.emitReport(std::move(R));
- }
- };
- const StdLibraryFunctionsChecker::ArgNo StdLibraryFunctionsChecker::Ret =
- std::numeric_limits<ArgNo>::max();
- } // end of anonymous namespace
- static BasicValueFactory &getBVF(ProgramStateRef State) {
- ProgramStateManager &Mgr = State->getStateManager();
- SValBuilder &SVB = Mgr.getSValBuilder();
- return SVB.getBasicValueFactory();
- }
- std::string StdLibraryFunctionsChecker::NotNullConstraint::describe(
- ProgramStateRef State, const Summary &Summary) const {
- SmallString<48> Result;
- Result += "The ";
- Result += getArgDesc(ArgN);
- Result += " should not be NULL";
- return Result.c_str();
- }
- std::string StdLibraryFunctionsChecker::RangeConstraint::describe(
- ProgramStateRef State, const Summary &Summary) const {
- BasicValueFactory &BVF = getBVF(State);
- QualType T = Summary.getArgType(getArgNo());
- SmallString<48> Result;
- Result += "The ";
- Result += getArgDesc(ArgN);
- Result += " should be ";
- // Range kind as a string.
- Kind == OutOfRange ? Result += "out of" : Result += "within";
- // Get the range values as a string.
- Result += " the range ";
- if (Ranges.size() > 1)
- Result += "[";
- unsigned I = Ranges.size();
- for (const std::pair<RangeInt, RangeInt> &R : Ranges) {
- Result += "[";
- const llvm::APSInt &Min = BVF.getValue(R.first, T);
- const llvm::APSInt &Max = BVF.getValue(R.second, T);
- Min.toString(Result);
- Result += ", ";
- Max.toString(Result);
- Result += "]";
- if (--I > 0)
- Result += ", ";
- }
- if (Ranges.size() > 1)
- Result += "]";
- return Result.c_str();
- }
- SmallString<8>
- StdLibraryFunctionsChecker::getArgDesc(StdLibraryFunctionsChecker::ArgNo ArgN) {
- SmallString<8> Result;
- Result += std::to_string(ArgN + 1);
- Result += llvm::getOrdinalSuffix(ArgN + 1);
- Result += " arg";
- return Result;
- }
- std::string StdLibraryFunctionsChecker::BufferSizeConstraint::describe(
- ProgramStateRef State, const Summary &Summary) const {
- SmallString<96> Result;
- Result += "The size of the ";
- Result += getArgDesc(ArgN);
- Result += " should be equal to or less than the value of ";
- if (ConcreteSize) {
- ConcreteSize->toString(Result);
- } else if (SizeArgN) {
- Result += "the ";
- Result += getArgDesc(*SizeArgN);
- if (SizeMultiplierArgN) {
- Result += " times the ";
- Result += getArgDesc(*SizeMultiplierArgN);
- }
- }
- return Result.c_str();
- }
- 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();
- BasicValueFactory &BVF = SVB.getBasicValueFactory();
- ConstraintManager &CM = Mgr.getConstraintManager();
- QualType T = Summary.getArgType(getArgNo());
- SVal V = getArgSVal(Call, getArgNo());
- if (auto N = V.getAs<NonLoc>()) {
- const IntRangeVector &R = getRanges();
- size_t E = R.size();
- for (size_t I = 0; I != E; ++I) {
- const llvm::APSInt &Min = BVF.getValue(R[I].first, T);
- const llvm::APSInt &Max = BVF.getValue(R[I].second, T);
- assert(Min <= Max);
- State = CM.assumeInclusiveRange(State, *N, Min, Max, false);
- if (!State)
- break;
- }
- }
- return State;
- }
- 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();
- BasicValueFactory &BVF = SVB.getBasicValueFactory();
- ConstraintManager &CM = Mgr.getConstraintManager();
- QualType T = Summary.getArgType(getArgNo());
- SVal V = getArgSVal(Call, getArgNo());
- // "WithinRange R" is treated as "outside [T_MIN, T_MAX] \ R".
- // We cut off [T_MIN, min(R) - 1] and [max(R) + 1, T_MAX] if necessary,
- // and then cut away all holes in R one by one.
- //
- // E.g. consider a range list R as [A, B] and [C, D]
- // -------+--------+------------------+------------+----------->
- // A B C D
- // Then we assume that the value is not in [-inf, A - 1],
- // then not in [D + 1, +inf], then not in [B + 1, C - 1]
- if (auto N = V.getAs<NonLoc>()) {
- const IntRangeVector &R = getRanges();
- size_t E = R.size();
- const llvm::APSInt &MinusInf = BVF.getMinValue(T);
- const llvm::APSInt &PlusInf = BVF.getMaxValue(T);
- const llvm::APSInt &Left = BVF.getValue(R[0].first - 1ULL, T);
- if (Left != PlusInf) {
- assert(MinusInf <= Left);
- State = CM.assumeInclusiveRange(State, *N, MinusInf, Left, false);
- if (!State)
- return nullptr;
- }
- const llvm::APSInt &Right = BVF.getValue(R[E - 1].second + 1ULL, T);
- if (Right != MinusInf) {
- assert(Right <= PlusInf);
- State = CM.assumeInclusiveRange(State, *N, Right, PlusInf, false);
- if (!State)
- return nullptr;
- }
- for (size_t I = 1; I != E; ++I) {
- const llvm::APSInt &Min = BVF.getValue(R[I - 1].second + 1ULL, T);
- const llvm::APSInt &Max = BVF.getValue(R[I].first - 1ULL, T);
- if (Min <= Max) {
- State = CM.assumeInclusiveRange(State, *N, Min, Max, false);
- if (!State)
- return nullptr;
- }
- }
- }
- return State;
- }
- ProgramStateRef StdLibraryFunctionsChecker::ComparisonConstraint::apply(
- ProgramStateRef State, const CallEvent &Call, const Summary &Summary,
- CheckerContext &C) const {
- ProgramStateManager &Mgr = State->getStateManager();
- SValBuilder &SVB = Mgr.getSValBuilder();
- QualType CondT = SVB.getConditionType();
- QualType T = Summary.getArgType(getArgNo());
- SVal V = getArgSVal(Call, getArgNo());
- BinaryOperator::Opcode Op = getOpcode();
- ArgNo OtherArg = getOtherArgNo();
- SVal OtherV = getArgSVal(Call, OtherArg);
- QualType OtherT = Summary.getArgType(OtherArg);
- // Note: we avoid integral promotion for comparison.
- OtherV = SVB.evalCast(OtherV, T, OtherT);
- if (auto CompV = SVB.evalBinOp(State, Op, V, OtherV, CondT)
- .getAs<DefinedOrUnknownSVal>())
- State = State->assume(*CompV, true);
- return State;
- }
- void StdLibraryFunctionsChecker::checkPreCall(const CallEvent &Call,
- CheckerContext &C) const {
- Optional<Summary> FoundSummary = findFunctionSummary(Call, C);
- if (!FoundSummary)
- return;
- const Summary &Summary = *FoundSummary;
- ProgramStateRef State = C.getState();
- ProgramStateRef NewState = State;
- for (const ValueConstraintPtr &Constraint : Summary.getArgConstraints()) {
- ProgramStateRef SuccessSt = Constraint->apply(NewState, Call, Summary, C);
- ProgramStateRef FailureSt =
- Constraint->negate()->apply(NewState, Call, Summary, C);
- // The argument constraint is not satisfied.
- if (FailureSt && !SuccessSt) {
- if (ExplodedNode *N = C.generateErrorNode(NewState))
- reportBug(Call, N, Constraint.get(), Summary, C);
- break;
- } else {
- // We will apply the constraint even if we cannot reason about the
- // argument. This means both SuccessSt and FailureSt can be true. If we
- // weren't applying the constraint that would mean that symbolic
- // execution continues on a code whose behaviour is undefined.
- assert(SuccessSt);
- NewState = SuccessSt;
- }
- }
- if (NewState && NewState != State)
- C.addTransition(NewState);
- }
- void StdLibraryFunctionsChecker::checkPostCall(const CallEvent &Call,
- CheckerContext &C) const {
- Optional<Summary> FoundSummary = findFunctionSummary(Call, C);
- if (!FoundSummary)
- return;
- // Now apply the constraints.
- const Summary &Summary = *FoundSummary;
- ProgramStateRef State = C.getState();
- // Apply case/branch specifications.
- for (const ConstraintSet &Case : Summary.getCaseConstraints()) {
- ProgramStateRef NewState = State;
- for (const ValueConstraintPtr &Constraint : Case) {
- NewState = Constraint->apply(NewState, Call, Summary, C);
- if (!NewState)
- break;
- }
- if (NewState && NewState != State)
- C.addTransition(NewState);
- }
- }
- bool StdLibraryFunctionsChecker::evalCall(const CallEvent &Call,
- CheckerContext &C) const {
- Optional<Summary> FoundSummary = findFunctionSummary(Call, C);
- if (!FoundSummary)
- return false;
- const Summary &Summary = *FoundSummary;
- switch (Summary.getInvalidationKd()) {
- case EvalCallAsPure: {
- ProgramStateRef State = C.getState();
- const LocationContext *LC = C.getLocationContext();
- const auto *CE = cast<CallExpr>(Call.getOriginExpr());
- SVal V = C.getSValBuilder().conjureSymbolVal(
- CE, LC, CE->getType().getCanonicalType(), C.blockCount());
- State = State->BindExpr(CE, LC, V);
- C.addTransition(State);
- return true;
- }
- case NoEvalCall:
- // Summary tells us to avoid performing eval::Call. The function is possibly
- // evaluated by another checker, or evaluated conservatively.
- return false;
- }
- llvm_unreachable("Unknown invalidation kind!");
- }
- bool StdLibraryFunctionsChecker::Signature::matches(
- const FunctionDecl *FD) const {
- assert(!isInvalid());
- // Check the number of arguments.
- if (FD->param_size() != ArgTys.size())
- return false;
- // The "restrict" keyword is illegal in C++, however, many libc
- // implementations use the "__restrict" compiler intrinsic in functions
- // prototypes. The "__restrict" keyword qualifies a type as a restricted type
- // even in C++.
- // In case of any non-C99 languages, we don't want to match based on the
- // restrict qualifier because we cannot know if the given libc implementation
- // qualifies the paramter type or not.
- auto RemoveRestrict = [&FD](QualType T) {
- if (!FD->getASTContext().getLangOpts().C99)
- T.removeLocalRestrict();
- return T;
- };
- // Check the return type.
- if (!isIrrelevant(RetTy)) {
- QualType FDRetTy = RemoveRestrict(FD->getReturnType().getCanonicalType());
- if (RetTy != FDRetTy)
- return false;
- }
- // Check the argument types.
- for (size_t I = 0, E = ArgTys.size(); I != E; ++I) {
- QualType ArgTy = ArgTys[I];
- if (isIrrelevant(ArgTy))
- continue;
- QualType FDArgTy =
- RemoveRestrict(FD->getParamDecl(I)->getType().getCanonicalType());
- if (ArgTy != FDArgTy)
- return false;
- }
- return true;
- }
- Optional<StdLibraryFunctionsChecker::Summary>
- StdLibraryFunctionsChecker::findFunctionSummary(const FunctionDecl *FD,
- CheckerContext &C) const {
- if (!FD)
- return None;
- initFunctionSummaries(C);
- auto FSMI = FunctionSummaryMap.find(FD->getCanonicalDecl());
- if (FSMI == FunctionSummaryMap.end())
- return None;
- return FSMI->second;
- }
- Optional<StdLibraryFunctionsChecker::Summary>
- StdLibraryFunctionsChecker::findFunctionSummary(const CallEvent &Call,
- CheckerContext &C) const {
- const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
- if (!FD)
- return None;
- return findFunctionSummary(FD, C);
- }
- void StdLibraryFunctionsChecker::initFunctionSummaries(
- CheckerContext &C) const {
- if (SummariesInitialized)
- return;
- SValBuilder &SVB = C.getSValBuilder();
- BasicValueFactory &BVF = SVB.getBasicValueFactory();
- const ASTContext &ACtx = BVF.getContext();
- // 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<QualType> operator()(StringRef Name) {
- IdentifierInfo &II = ACtx.Idents.get(Name);
- auto LookupRes = ACtx.getTranslationUnitDecl()->lookup(&II);
- if (LookupRes.empty())
- 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<TypedefNameDecl>(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<TypeDecl>(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<QualType> operator()(Optional<QualType> Ty) {
- if (Ty)
- return operator()(*Ty);
- return None;
- }
- } getRestrictTy(ACtx);
- class GetPointerTy {
- const ASTContext &ACtx;
- public:
- GetPointerTy(const ASTContext &ACtx) : ACtx(ACtx) {}
- QualType operator()(QualType Ty) { return ACtx.getPointerType(Ty); }
- Optional<QualType> operator()(Optional<QualType> Ty) {
- if (Ty)
- return operator()(*Ty);
- return None;
- }
- } getPointerTy(ACtx);
- class {
- public:
- Optional<QualType> operator()(Optional<QualType> Ty) {
- return Ty ? Optional<QualType>(Ty->withConst()) : None;
- }
- QualType operator()(QualType Ty) { return Ty.withConst(); }
- } getConstTy;
- class GetMaxValue {
- BasicValueFactory &BVF;
- public:
- GetMaxValue(BasicValueFactory &BVF) : BVF(BVF) {}
- Optional<RangeInt> operator()(QualType Ty) {
- return BVF.getMaxValue(Ty).getLimitedValue();
- }
- Optional<RangeInt> operator()(Optional<QualType> 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.
- // Some types are hard to obtain from the AST, eg. "ssize_t".
- // In such cases it should be possible to provide multiple variants
- // of function summary for common cases (eg. ssize_t could be int or long
- // 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 SizeTy = ACtx.getSizeType();
- const QualType VoidPtrTy = getPointerTy(VoidTy); // void *
- const QualType IntPtrTy = getPointerTy(IntTy); // int *
- const QualType UnsignedIntPtrTy =
- getPointerTy(UnsignedIntTy); // unsigned int *
- const QualType VoidPtrRestrictTy = getRestrictTy(VoidPtrTy);
- const QualType ConstVoidPtrTy =
- getPointerTy(getConstTy(VoidTy)); // const void *
- const QualType CharPtrTy = getPointerTy(CharTy); // char *
- const QualType CharPtrRestrictTy = getRestrictTy(CharPtrTy);
- const QualType ConstCharPtrTy =
- getPointerTy(getConstTy(CharTy)); // const char *
- const QualType ConstCharPtrRestrictTy = getRestrictTy(ConstCharPtrTy);
- const QualType Wchar_tPtrTy = getPointerTy(WCharTy); // wchar_t *
- const QualType ConstWchar_tPtrTy =
- getPointerTy(getConstTy(WCharTy)); // const wchar_t *
- const QualType ConstVoidPtrRestrictTy = getRestrictTy(ConstVoidPtrTy);
- const QualType SizePtrTy = getPointerTy(SizeTy);
- const QualType SizePtrRestrictTy = getRestrictTy(SizePtrTy);
- const RangeInt IntMax = BVF.getMaxValue(IntTy).getLimitedValue();
- const RangeInt UnsignedIntMax =
- BVF.getMaxValue(UnsignedIntTy).getLimitedValue();
- const RangeInt LongMax = BVF.getMaxValue(LongTy).getLimitedValue();
- const RangeInt SizeMax = BVF.getMaxValue(SizeTy).getLimitedValue();
- // Set UCharRangeMax to min of int or uchar maximum value.
- // The C standard states that the arguments of functions like isalpha must
- // be representable as an unsigned char. Their type is 'int', so the max
- // value of the argument should be min(UCharMax, IntMax). This just happen
- // to be true for commonly used and well tested instruction set
- // architectures, but not for others.
- const RangeInt UCharRangeMax =
- std::min(BVF.getMaxValue(ACtx.UnsignedCharTy).getLimitedValue(), IntMax);
- // The platform dependent value of EOF.
- // Try our best to parse this from the Preprocessor, otherwise fallback to -1.
- const auto EOFv = [&C]() -> RangeInt {
- if (const llvm::Optional<int> OptInt =
- tryExpandAsInteger("EOF", C.getPreprocessor()))
- return *OptInt;
- return -1;
- }();
- // Auxiliary class to aid adding summaries to the summary map.
- struct AddToFunctionSummaryMap {
- const ASTContext &ACtx;
- FunctionSummaryMapType ⤅
- bool DisplayLoadedSummaries;
- AddToFunctionSummaryMap(const ASTContext &ACtx, FunctionSummaryMapType &FSM,
- bool DisplayLoadedSummaries)
- : ACtx(ACtx), Map(FSM), DisplayLoadedSummaries(DisplayLoadedSummaries) {
- }
- // 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.
- //
- // Returns true if the summary has been added, false otherwise.
- bool operator()(StringRef Name, Signature Sign, Summary Sum) {
- if (Sign.isInvalid())
- return false;
- IdentifierInfo &II = ACtx.Idents.get(Name);
- auto LookupRes = ACtx.getTranslationUnitDecl()->lookup(&II);
- if (LookupRes.empty())
- return false;
- for (Decl *D : LookupRes) {
- if (auto *FD = dyn_cast<FunctionDecl>(D)) {
- if (Sum.matchesAndSet(Sign, FD)) {
- auto Res = Map.insert({FD->getCanonicalDecl(), Sum});
- assert(Res.second && "Function already has a summary set!");
- (void)Res;
- if (DisplayLoadedSummaries) {
- llvm::errs() << "Loaded summary for: ";
- FD->print(llvm::errs());
- llvm::errs() << "\n";
- }
- return true;
- }
- }
- }
- return false;
- }
- // Add the same summary for different names with the Signature explicitly
- // given.
- void operator()(std::vector<StringRef> Names, Signature Sign, Summary Sum) {
- for (StringRef Name : Names)
- operator()(Name, Sign, Sum);
- }
- } addToFunctionSummaryMap(ACtx, FunctionSummaryMap, DisplayLoadedSummaries);
- // Below are helpers functions to create the summaries.
- auto ArgumentCondition = [](ArgNo ArgN, RangeKind Kind,
- IntRangeVector Ranges) {
- return std::make_shared<RangeConstraint>(ArgN, Kind, Ranges);
- };
- auto BufferSize = [](auto... Args) {
- return std::make_shared<BufferSizeConstraint>(Args...);
- };
- struct {
- auto operator()(RangeKind Kind, IntRangeVector Ranges) {
- return std::make_shared<RangeConstraint>(Ret, Kind, Ranges);
- }
- auto operator()(BinaryOperator::Opcode Op, ArgNo OtherArgN) {
- return std::make_shared<ComparisonConstraint>(Ret, Op, OtherArgN);
- }
- } ReturnValueCondition;
- struct {
- auto operator()(RangeInt b, RangeInt e) {
- return IntRangeVector{std::pair<RangeInt, RangeInt>{b, e}};
- }
- auto operator()(RangeInt b, Optional<RangeInt> e) {
- if (e)
- return IntRangeVector{std::pair<RangeInt, RangeInt>{b, *e}};
- return IntRangeVector{};
- }
- auto operator()(std::pair<RangeInt, RangeInt> i0,
- std::pair<RangeInt, Optional<RangeInt>> i1) {
- if (i1.second)
- return IntRangeVector{i0, {i1.first, *(i1.second)}};
- return IntRangeVector{i0};
- }
- } Range;
- auto SingleValue = [](RangeInt v) {
- return IntRangeVector{std::pair<RangeInt, RangeInt>{v, v}};
- };
- auto LessThanOrEq = BO_LE;
- auto NotNull = [&](ArgNo ArgN) {
- return std::make_shared<NotNullConstraint>(ArgN);
- };
- Optional<QualType> FileTy = lookupTy("FILE");
- Optional<QualType> FilePtrTy = getPointerTy(FileTy);
- Optional<QualType> FilePtrRestrictTy = getRestrictTy(FilePtrTy);
- // 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
- // 7.4.1.2 The isalpha function (p: 181-182).
- addToFunctionSummaryMap(
- "isalnum", Signature(ArgTypes{IntTy}, RetType{IntTy}),
- Summary(EvalCallAsPure)
- // Boils down to isupper() or islower() or isdigit().
- .Case({ArgumentCondition(0U, WithinRange,
- {{'0', '9'}, {'A', 'Z'}, {'a', 'z'}}),
- ReturnValueCondition(OutOfRange, SingleValue(0))})
- // The locale-specific range.
- // No post-condition. We are completely unaware of
- // locale-specific return values.
- .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})})
- .Case(
- {ArgumentCondition(
- 0U, OutOfRange,
- {{'0', '9'}, {'A', 'Z'}, {'a', 'z'}, {128, UCharRangeMax}}),
- ReturnValueCondition(WithinRange, SingleValue(0))})
- .ArgConstraint(ArgumentCondition(
- 0U, WithinRange, {{EOFv, EOFv}, {0, UCharRangeMax}})));
- addToFunctionSummaryMap(
- "isalpha", Signature(ArgTypes{IntTy}, RetType{IntTy}),
- Summary(EvalCallAsPure)
- .Case({ArgumentCondition(0U, WithinRange, {{'A', 'Z'}, {'a', 'z'}}),
- ReturnValueCondition(OutOfRange, SingleValue(0))})
- // The locale-specific range.
- .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})})
- .Case({ArgumentCondition(
- 0U, OutOfRange,
- {{'A', 'Z'}, {'a', 'z'}, {128, UCharRangeMax}}),
- ReturnValueCondition(WithinRange, SingleValue(0))}));
- addToFunctionSummaryMap(
- "isascii", Signature(ArgTypes{IntTy}, RetType{IntTy}),
- Summary(EvalCallAsPure)
- .Case({ArgumentCondition(0U, WithinRange, Range(0, 127)),
- ReturnValueCondition(OutOfRange, SingleValue(0))})
- .Case({ArgumentCondition(0U, OutOfRange, Range(0, 127)),
- ReturnValueCondition(WithinRange, SingleValue(0))}));
- addToFunctionSummaryMap(
- "isblank", Signature(ArgTypes{IntTy}, RetType{IntTy}),
- Summary(EvalCallAsPure)
- .Case({ArgumentCondition(0U, WithinRange, {{'\t', '\t'}, {' ', ' '}}),
- ReturnValueCondition(OutOfRange, SingleValue(0))})
- .Case({ArgumentCondition(0U, OutOfRange, {{'\t', '\t'}, {' ', ' '}}),
- ReturnValueCondition(WithinRange, SingleValue(0))}));
- addToFunctionSummaryMap(
- "iscntrl", Signature(ArgTypes{IntTy}, RetType{IntTy}),
- Summary(EvalCallAsPure)
- .Case({ArgumentCondition(0U, WithinRange, {{0, 32}, {127, 127}}),
- ReturnValueCondition(OutOfRange, SingleValue(0))})
- .Case({ArgumentCondition(0U, OutOfRange, {{0, 32}, {127, 127}}),
- ReturnValueCondition(WithinRange, SingleValue(0))}));
- addToFunctionSummaryMap(
- "isdigit", Signature(ArgTypes{IntTy}, RetType{IntTy}),
- Summary(EvalCallAsPure)
- .Case({ArgumentCondition(0U, WithinRange, Range('0', '9')),
- ReturnValueCondition(OutOfRange, SingleValue(0))})
- .Case({ArgumentCondition(0U, OutOfRange, Range('0', '9')),
- ReturnValueCondition(WithinRange, SingleValue(0))}));
- addToFunctionSummaryMap(
- "isgraph", Signature(ArgTypes{IntTy}, RetType{IntTy}),
- Summary(EvalCallAsPure)
- .Case({ArgumentCondition(0U, WithinRange, Range(33, 126)),
- ReturnValueCondition(OutOfRange, SingleValue(0))})
- .Case({ArgumentCondition(0U, OutOfRange, Range(33, 126)),
- ReturnValueCondition(WithinRange, SingleValue(0))}));
- addToFunctionSummaryMap(
- "islower", Signature(ArgTypes{IntTy}, RetType{IntTy}),
- Summary(EvalCallAsPure)
- // Is certainly lowercase.
- .Case({ArgumentCondition(0U, WithinRange, Range('a', 'z')),
- ReturnValueCondition(OutOfRange, SingleValue(0))})
- // Is ascii but not lowercase.
- .Case({ArgumentCondition(0U, WithinRange, Range(0, 127)),
- ArgumentCondition(0U, OutOfRange, Range('a', 'z')),
- ReturnValueCondition(WithinRange, SingleValue(0))})
- // The locale-specific range.
- .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})})
- // Is not an unsigned char.
- .Case({ArgumentCondition(0U, OutOfRange, Range(0, UCharRangeMax)),
- ReturnValueCondition(WithinRange, SingleValue(0))}));
- addToFunctionSummaryMap(
- "isprint", Signature(ArgTypes{IntTy}, RetType{IntTy}),
- Summary(EvalCallAsPure)
- .Case({ArgumentCondition(0U, WithinRange, Range(32, 126)),
- ReturnValueCondition(OutOfRange, SingleValue(0))})
- .Case({ArgumentCondition(0U, OutOfRange, Range(32, 126)),
- ReturnValueCondition(WithinRange, SingleValue(0))}));
- addToFunctionSummaryMap(
- "ispunct", Signature(ArgTypes{IntTy}, RetType{IntTy}),
- Summary(EvalCallAsPure)
- .Case({ArgumentCondition(
- 0U, WithinRange,
- {{'!', '/'}, {':', '@'}, {'[', '`'}, {'{', '~'}}),
- ReturnValueCondition(OutOfRange, SingleValue(0))})
- .Case({ArgumentCondition(
- 0U, OutOfRange,
- {{'!', '/'}, {':', '@'}, {'[', '`'}, {'{', '~'}}),
- ReturnValueCondition(WithinRange, SingleValue(0))}));
- addToFunctionSummaryMap(
- "isspace", Signature(ArgTypes{IntTy}, RetType{IntTy}),
- Summary(EvalCallAsPure)
- // Space, '\f', '\n', '\r', '\t', '\v'.
- .Case({ArgumentCondition(0U, WithinRange, {{9, 13}, {' ', ' '}}),
- ReturnValueCondition(OutOfRange, SingleValue(0))})
- // The locale-specific range.
- .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})})
- .Case({ArgumentCondition(0U, OutOfRange,
- {{9, 13}, {' ', ' '}, {128, UCharRangeMax}}),
- ReturnValueCondition(WithinRange, SingleValue(0))}));
- addToFunctionSummaryMap(
- "isupper", Signature(ArgTypes{IntTy}, RetType{IntTy}),
- Summary(EvalCallAsPure)
- // Is certainly uppercase.
- .Case({ArgumentCondition(0U, WithinRange, Range('A', 'Z')),
- ReturnValueCondition(OutOfRange, SingleValue(0))})
- // The locale-specific range.
- .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})})
- // Other.
- .Case({ArgumentCondition(0U, OutOfRange,
- {{'A', 'Z'}, {128, UCharRangeMax}}),
- ReturnValueCondition(WithinRange, SingleValue(0))}));
- addToFunctionSummaryMap(
- "isxdigit", Signature(ArgTypes{IntTy}, RetType{IntTy}),
- Summary(EvalCallAsPure)
- .Case({ArgumentCondition(0U, WithinRange,
- {{'0', '9'}, {'A', 'F'}, {'a', 'f'}}),
- ReturnValueCondition(OutOfRange, SingleValue(0))})
- .Case({ArgumentCondition(0U, OutOfRange,
- {{'0', '9'}, {'A', 'F'}, {'a', 'f'}}),
- ReturnValueCondition(WithinRange, SingleValue(0))}));
- addToFunctionSummaryMap(
- "toupper", Signature(ArgTypes{IntTy}, RetType{IntTy}),
- Summary(EvalCallAsPure)
- .ArgConstraint(ArgumentCondition(
- 0U, WithinRange, {{EOFv, EOFv}, {0, UCharRangeMax}})));
- addToFunctionSummaryMap(
- "tolower", Signature(ArgTypes{IntTy}, RetType{IntTy}),
- Summary(EvalCallAsPure)
- .ArgConstraint(ArgumentCondition(
- 0U, WithinRange, {{EOFv, EOFv}, {0, UCharRangeMax}})));
- addToFunctionSummaryMap(
- "toascii", Signature(ArgTypes{IntTy}, RetType{IntTy}),
- Summary(EvalCallAsPure)
- .ArgConstraint(ArgumentCondition(
- 0U, WithinRange, {{EOFv, EOFv}, {0, UCharRangeMax}})));
- // The getc() family of functions that returns either a char or an EOF.
- addToFunctionSummaryMap(
- {"getc", "fgetc"}, Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
- Summary(NoEvalCall)
- .Case({ReturnValueCondition(WithinRange,
- {{EOFv, EOFv}, {0, UCharRangeMax}})}));
- addToFunctionSummaryMap(
- "getchar", Signature(ArgTypes{}, RetType{IntTy}),
- Summary(NoEvalCall)
- .Case({ReturnValueCondition(WithinRange,
- {{EOFv, EOFv}, {0, UCharRangeMax}})}));
- // read()-like functions that never return more than buffer size.
- auto FreadSummary =
- Summary(NoEvalCall)
- .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)),
- ReturnValueCondition(WithinRange, Range(0, SizeMax))})
- .ArgConstraint(NotNull(ArgNo(0)))
- .ArgConstraint(NotNull(ArgNo(3)))
- .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1),
- /*BufSizeMultiplier=*/ArgNo(2)));
- // size_t fread(void *restrict ptr, size_t size, size_t nitems,
- // FILE *restrict stream);
- addToFunctionSummaryMap(
- "fread",
- Signature(ArgTypes{VoidPtrRestrictTy, SizeTy, SizeTy, FilePtrRestrictTy},
- RetType{SizeTy}),
- FreadSummary);
- // size_t fwrite(const void *restrict ptr, size_t size, size_t nitems,
- // FILE *restrict stream);
- addToFunctionSummaryMap("fwrite",
- Signature(ArgTypes{ConstVoidPtrRestrictTy, SizeTy,
- SizeTy, FilePtrRestrictTy},
- RetType{SizeTy}),
- FreadSummary);
- Optional<QualType> Ssize_tTy = lookupTy("ssize_t");
- Optional<RangeInt> Ssize_tMax = getMaxValue(Ssize_tTy);
- auto ReadSummary =
- Summary(NoEvalCall)
- .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)),
- ReturnValueCondition(WithinRange, Range(-1, Ssize_tMax))});
- // FIXME these are actually defined by POSIX and not by the C standard, we
- // should handle them together with the rest of the POSIX functions.
- // ssize_t read(int fildes, void *buf, size_t nbyte);
- addToFunctionSummaryMap(
- "read", Signature(ArgTypes{IntTy, VoidPtrTy, SizeTy}, RetType{Ssize_tTy}),
- ReadSummary);
- // ssize_t write(int fildes, const void *buf, size_t nbyte);
- addToFunctionSummaryMap(
- "write",
- Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTy}, RetType{Ssize_tTy}),
- ReadSummary);
- auto GetLineSummary =
- Summary(NoEvalCall)
- .Case({ReturnValueCondition(WithinRange,
- Range({-1, -1}, {1, Ssize_tMax}))});
- QualType CharPtrPtrRestrictTy = getRestrictTy(getPointerTy(CharPtrTy));
- // getline()-like functions either fail or read at least the delimiter.
- // FIXME these are actually defined by POSIX and not by the C standard, we
- // should handle them together with the rest of the POSIX functions.
- // ssize_t getline(char **restrict lineptr, size_t *restrict n,
- // FILE *restrict stream);
- addToFunctionSummaryMap(
- "getline",
- Signature(
- ArgTypes{CharPtrPtrRestrictTy, SizePtrRestrictTy, FilePtrRestrictTy},
- RetType{Ssize_tTy}),
- GetLineSummary);
- // ssize_t getdelim(char **restrict lineptr, size_t *restrict n,
- // int delimiter, FILE *restrict stream);
- addToFunctionSummaryMap(
- "getdelim",
- Signature(ArgTypes{CharPtrPtrRestrictTy, SizePtrRestrictTy, IntTy,
- FilePtrRestrictTy},
- RetType{Ssize_tTy}),
- GetLineSummary);
- {
- Summary GetenvSummary = Summary(NoEvalCall)
- .ArgConstraint(NotNull(ArgNo(0)))
- .Case({NotNull(Ret)});
- // In untrusted environments the envvar might not exist.
- if (!ShouldAssumeControlledEnvironment)
- GetenvSummary.Case({NotNull(Ret)->negate()});
- // char *getenv(const char *name);
- addToFunctionSummaryMap(
- "getenv", Signature(ArgTypes{ConstCharPtrTy}, RetType{CharPtrTy}),
- std::move(GetenvSummary));
- }
- if (ModelPOSIX) {
- // long a64l(const char *str64);
- addToFunctionSummaryMap(
- "a64l", Signature(ArgTypes{ConstCharPtrTy}, RetType{LongTy}),
- Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
- // char *l64a(long value);
- addToFunctionSummaryMap("l64a",
- Signature(ArgTypes{LongTy}, RetType{CharPtrTy}),
- Summary(NoEvalCall)
- .ArgConstraint(ArgumentCondition(
- 0, WithinRange, Range(0, LongMax))));
- const auto ReturnsZeroOrMinusOne =
- ConstraintSet{ReturnValueCondition(WithinRange, Range(-1, 0))};
- const auto ReturnsFileDescriptor =
- ConstraintSet{ReturnValueCondition(WithinRange, Range(-1, IntMax))};
- // int access(const char *pathname, int amode);
- addToFunctionSummaryMap(
- "access", Signature(ArgTypes{ConstCharPtrTy, IntTy}, RetType{IntTy}),
- Summary(NoEvalCall)
- .Case(ReturnsZeroOrMinusOne)
- .ArgConstraint(NotNull(ArgNo(0))));
- // int faccessat(int dirfd, const char *pathname, int mode, int flags);
- addToFunctionSummaryMap(
- "faccessat",
- Signature(ArgTypes{IntTy, ConstCharPtrTy, IntTy, IntTy},
- RetType{IntTy}),
- Summary(NoEvalCall)
- .Case(ReturnsZeroOrMinusOne)
- .ArgConstraint(NotNull(ArgNo(1))));
- // int dup(int fildes);
- addToFunctionSummaryMap("dup", Signature(ArgTypes{IntTy}, RetType{IntTy}),
- Summary(NoEvalCall)
- .Case(ReturnsFileDescriptor)
- .ArgConstraint(ArgumentCondition(
- 0, WithinRange, Range(0, IntMax))));
- // int dup2(int fildes1, int filedes2);
- addToFunctionSummaryMap(
- "dup2", Signature(ArgTypes{IntTy, IntTy}, RetType{IntTy}),
- Summary(NoEvalCall)
- .Case(ReturnsFileDescriptor)
- .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
- .ArgConstraint(
- ArgumentCondition(1, WithinRange, Range(0, IntMax))));
- // int fdatasync(int fildes);
- addToFunctionSummaryMap("fdatasync",
- Signature(ArgTypes{IntTy}, RetType{IntTy}),
- Summary(NoEvalCall)
- .Case(ReturnsZeroOrMinusOne)
- .ArgConstraint(ArgumentCondition(
- 0, WithinRange, Range(0, IntMax))));
- // int fnmatch(const char *pattern, const char *string, int flags);
- addToFunctionSummaryMap(
- "fnmatch",
- Signature(ArgTypes{ConstCharPtrTy, ConstCharPtrTy, IntTy},
- RetType{IntTy}),
- Summary(EvalCallAsPure)
- .ArgConstraint(NotNull(ArgNo(0)))
- .ArgConstraint(NotNull(ArgNo(1))));
- // int fsync(int fildes);
- addToFunctionSummaryMap("fsync", Signature(ArgTypes{IntTy}, RetType{IntTy}),
- Summary(NoEvalCall)
- .Case(ReturnsZeroOrMinusOne)
- .ArgConstraint(ArgumentCondition(
- 0, WithinRange, Range(0, IntMax))));
- Optional<QualType> Off_tTy = lookupTy("off_t");
- // int truncate(const char *path, off_t length);
- addToFunctionSummaryMap(
- "truncate",
- Signature(ArgTypes{ConstCharPtrTy, Off_tTy}, RetType{IntTy}),
- Summary(NoEvalCall)
- .Case(ReturnsZeroOrMinusOne)
- .ArgConstraint(NotNull(ArgNo(0))));
- // int symlink(const char *oldpath, const char *newpath);
- addToFunctionSummaryMap(
- "symlink",
- Signature(ArgTypes{ConstCharPtrTy, ConstCharPtrTy}, RetType{IntTy}),
- Summary(NoEvalCall)
- .Case(ReturnsZeroOrMinusOne)
- .ArgConstraint(NotNull(ArgNo(0)))
- .ArgConstraint(NotNull(ArgNo(1))));
- // int symlinkat(const char *oldpath, int newdirfd, const char *newpath);
- addToFunctionSummaryMap(
- "symlinkat",
- Signature(ArgTypes{ConstCharPtrTy, IntTy, ConstCharPtrTy},
- RetType{IntTy}),
- Summary(NoEvalCall)
- .Case(ReturnsZeroOrMinusOne)
- .ArgConstraint(NotNull(ArgNo(0)))
- .ArgConstraint(ArgumentCondition(1, WithinRange, Range(0, IntMax)))
- .ArgConstraint(NotNull(ArgNo(2))));
- // int lockf(int fd, int cmd, off_t len);
- addToFunctionSummaryMap(
- "lockf", Signature(ArgTypes{IntTy, IntTy, Off_tTy}, RetType{IntTy}),
- Summary(NoEvalCall)
- .Case(ReturnsZeroOrMinusOne)
- .ArgConstraint(
- ArgumentCondition(0, WithinRange, Range(0, IntMax))));
- Optional<QualType> Mode_tTy = lookupTy("mode_t");
- // int creat(const char *pathname, mode_t mode);
- addToFunctionSummaryMap(
- "creat", Signature(ArgTypes{ConstCharPtrTy, Mode_tTy}, RetType{IntTy}),
- Summary(NoEvalCall)
- .Case(ReturnsFileDescriptor)
- .ArgConstraint(NotNull(ArgNo(0))));
- // unsigned int sleep(unsigned int seconds);
- addToFunctionSummaryMap(
- "sleep", Signature(ArgTypes{UnsignedIntTy}, RetType{UnsignedIntTy}),
- Summary(NoEvalCall)
- .ArgConstraint(
- ArgumentCondition(0, WithinRange, Range(0, UnsignedIntMax))));
- Optional<QualType> DirTy = lookupTy("DIR");
- Optional<QualType> DirPtrTy = getPointerTy(DirTy);
- // int dirfd(DIR *dirp);
- addToFunctionSummaryMap("dirfd",
- Signature(ArgTypes{DirPtrTy}, RetType{IntTy}),
- Summary(NoEvalCall)
- .Case(ReturnsFileDescriptor)
- .ArgConstraint(NotNull(ArgNo(0))));
- // unsigned int alarm(unsigned int seconds);
- addToFunctionSummaryMap(
- "alarm", Signature(ArgTypes{UnsignedIntTy}, RetType{UnsignedIntTy}),
- Summary(NoEvalCall)
- .ArgConstraint(
- ArgumentCondition(0, WithinRange, Range(0, UnsignedIntMax))));
- // int closedir(DIR *dir);
- addToFunctionSummaryMap("closedir",
- Signature(ArgTypes{DirPtrTy}, RetType{IntTy}),
- Summary(NoEvalCall)
- .Case(ReturnsZeroOrMinusOne)
- .ArgConstraint(NotNull(ArgNo(0))));
- // char *strdup(const char *s);
- addToFunctionSummaryMap(
- "strdup", Signature(ArgTypes{ConstCharPtrTy}, RetType{CharPtrTy}),
- Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
- // char *strndup(const char *s, size_t n);
- addToFunctionSummaryMap(
- "strndup",
- Signature(ArgTypes{ConstCharPtrTy, SizeTy}, RetType{CharPtrTy}),
- Summary(NoEvalCall)
- .ArgConstraint(NotNull(ArgNo(0)))
- .ArgConstraint(
- ArgumentCondition(1, WithinRange, Range(0, SizeMax))));
- // wchar_t *wcsdup(const wchar_t *s);
- addToFunctionSummaryMap(
- "wcsdup", Signature(ArgTypes{ConstWchar_tPtrTy}, RetType{Wchar_tPtrTy}),
- Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
- // int mkstemp(char *template);
- addToFunctionSummaryMap("mkstemp",
- Signature(ArgTypes{CharPtrTy}, RetType{IntTy}),
- Summary(NoEvalCall)
- .Case(ReturnsFileDescriptor)
- .ArgConstraint(NotNull(ArgNo(0))));
- // char *mkdtemp(char *template);
- addToFunctionSummaryMap(
- "mkdtemp", Signature(ArgTypes{CharPtrTy}, RetType{CharPtrTy}),
- Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
- // char *getcwd(char *buf, size_t size);
- addToFunctionSummaryMap(
- "getcwd", Signature(ArgTypes{CharPtrTy, SizeTy}, RetType{CharPtrTy}),
- Summary(NoEvalCall)
- .ArgConstraint(
- ArgumentCondition(1, WithinRange, Range(0, SizeMax))));
- // int mkdir(const char *pathname, mode_t mode);
- addToFunctionSummaryMap(
- "mkdir", Signature(ArgTypes{ConstCharPtrTy, Mode_tTy}, RetType{IntTy}),
- Summary(NoEvalCall)
- .Case(ReturnsZeroOrMinusOne)
- .ArgConstraint(NotNull(ArgNo(0))));
- // int mkdirat(int dirfd, const char *pathname, mode_t mode);
- addToFunctionSummaryMap(
- "mkdirat",
- Signature(ArgTypes{IntTy, ConstCharPtrTy, Mode_tTy}, RetType{IntTy}),
- Summary(NoEvalCall)
- .Case(ReturnsZeroOrMinusOne)
- .ArgConstraint(NotNull(ArgNo(1))));
- Optional<QualType> Dev_tTy = lookupTy("dev_t");
- // int mknod(const char *pathname, mode_t mode, dev_t dev);
- addToFunctionSummaryMap(
- "mknod",
- Signature(ArgTypes{ConstCharPtrTy, Mode_tTy, Dev_tTy}, RetType{IntTy}),
- Summary(NoEvalCall)
- .Case(ReturnsZeroOrMinusOne)
- .ArgConstraint(NotNull(ArgNo(0))));
- // int mknodat(int dirfd, const char *pathname, mode_t mode, dev_t dev);
- addToFunctionSummaryMap(
- "mknodat",
- Signature(ArgTypes{IntTy, ConstCharPtrTy, Mode_tTy, Dev_tTy},
- RetType{IntTy}),
- Summary(NoEvalCall)
- .Case(ReturnsZeroOrMinusOne)
- .ArgConstraint(NotNull(ArgNo(1))));
- // int chmod(const char *path, mode_t mode);
- addToFunctionSummaryMap(
- "chmod", Signature(ArgTypes{ConstCharPtrTy, Mode_tTy}, RetType{IntTy}),
- Summary(NoEvalCall)
- .Case(ReturnsZeroOrMinusOne)
- .ArgConstraint(NotNull(ArgNo(0))));
- // int fchmodat(int dirfd, const char *pathname, mode_t mode, int flags);
- addToFunctionSummaryMap(
- "fchmodat",
- Signature(ArgTypes{IntTy, ConstCharPtrTy, Mode_tTy, IntTy},
- RetType{IntTy}),
- Summary(NoEvalCall)
- .Case(ReturnsZeroOrMinusOne)
- .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
- .ArgConstraint(NotNull(ArgNo(1))));
- // int fchmod(int fildes, mode_t mode);
- addToFunctionSummaryMap(
- "fchmod", Signature(ArgTypes{IntTy, Mode_tTy}, RetType{IntTy}),
- Summary(NoEvalCall)
- .Case(ReturnsZeroOrMinusOne)
- .ArgConstraint(
- ArgumentCondition(0, WithinRange, Range(0, IntMax))));
- Optional<QualType> Uid_tTy = lookupTy("uid_t");
- Optional<QualType> Gid_tTy = lookupTy("gid_t");
- // int fchownat(int dirfd, const char *pathname, uid_t owner, gid_t group,
- // int flags);
- addToFunctionSummaryMap(
- "fchownat",
- Signature(ArgTypes{IntTy, ConstCharPtrTy, Uid_tTy, Gid_tTy, IntTy},
- RetType{IntTy}),
- Summary(NoEvalCall)
- .Case(ReturnsZeroOrMinusOne)
- .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
- .ArgConstraint(NotNull(ArgNo(1))));
- // int chown(const char *path, uid_t owner, gid_t group);
- addToFunctionSummaryMap(
- "chown",
- Signature(ArgTypes{ConstCharPtrTy, Uid_tTy, Gid_tTy}, RetType{IntTy}),
- Summary(NoEvalCall)
- .Case(ReturnsZeroOrMinusOne)
- .ArgConstraint(NotNull(ArgNo(0))));
- // int lchown(const char *path, uid_t owner, gid_t group);
- addToFunctionSummaryMap(
- "lchown",
- Signature(ArgTypes{ConstCharPtrTy, Uid_tTy, Gid_tTy}, RetType{IntTy}),
- Summary(NoEvalCall)
- .Case(ReturnsZeroOrMinusOne)
- .ArgConstraint(NotNull(ArgNo(0))));
- // int fchown(int fildes, uid_t owner, gid_t group);
- addToFunctionSummaryMap(
- "fchown", Signature(ArgTypes{IntTy, Uid_tTy, Gid_tTy}, RetType{IntTy}),
- Summary(NoEvalCall)
- .Case(ReturnsZeroOrMinusOne)
- .ArgConstraint(
- ArgumentCondition(0, WithinRange, Range(0, IntMax))));
- // int rmdir(const char *pathname);
- addToFunctionSummaryMap("rmdir",
- Signature(ArgTypes{ConstCharPtrTy}, RetType{IntTy}),
- Summary(NoEvalCall)
- .Case(ReturnsZeroOrMinusOne)
- .ArgConstraint(NotNull(ArgNo(0))));
- // int chdir(const char *path);
- addToFunctionSummaryMap("chdir",
- Signature(ArgTypes{ConstCharPtrTy}, RetType{IntTy}),
- Summary(NoEvalCall)
- .Case(ReturnsZeroOrMinusOne)
- .ArgConstraint(NotNull(ArgNo(0))));
- // int link(const char *oldpath, const char *newpath);
- addToFunctionSummaryMap(
- "link",
- Signature(ArgTypes{ConstCharPtrTy, ConstCharPtrTy}, RetType{IntTy}),
- Summary(NoEvalCall)
- .Case(ReturnsZeroOrMinusOne)
- .ArgConstraint(NotNull(ArgNo(0)))
- .ArgConstraint(NotNull(ArgNo(1))));
- // int linkat(int fd1, const char *path1, int fd2, const char *path2,
- // int flag);
- addToFunctionSummaryMap(
- "linkat",
- Signature(ArgTypes{IntTy, ConstCharPtrTy, IntTy, ConstCharPtrTy, IntTy},
- RetType{IntTy}),
- Summary(NoEvalCall)
- .Case(ReturnsZeroOrMinusOne)
- .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
- .ArgConstraint(NotNull(ArgNo(1)))
- .ArgConstraint(ArgumentCondition(2, WithinRange, Range(0, IntMax)))
- .ArgConstraint(NotNull(ArgNo(3))));
- // int unlink(const char *pathname);
- addToFunctionSummaryMap("unlink",
- Signature(ArgTypes{ConstCharPtrTy}, RetType{IntTy}),
- Summary(NoEvalCall)
- .Case(ReturnsZeroOrMinusOne)
- .ArgConstraint(NotNull(ArgNo(0))));
- // int unlinkat(int fd, const char *path, int flag);
- addToFunctionSummaryMap(
- "unlinkat",
- Signature(ArgTypes{IntTy, ConstCharPtrTy, IntTy}, RetType{IntTy}),
- Summary(NoEvalCall)
- .Case(ReturnsZeroOrMinusOne)
- .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
- .ArgConstraint(NotNull(ArgNo(1))));
- Optional<QualType> StructStatTy = lookupTy("stat");
- Optional<QualType> StructStatPtrTy = getPointerTy(StructStatTy);
- Optional<QualType> StructStatPtrRestrictTy = getRestrictTy(StructStatPtrTy);
- // int fstat(int fd, struct stat *statbuf);
- addToFunctionSummaryMap(
- "fstat", Signature(ArgTypes{IntTy, StructStatPtrTy}, RetType{IntTy}),
- Summary(NoEvalCall)
- .Case(ReturnsZeroOrMinusOne)
- .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
- .ArgConstraint(NotNull(ArgNo(1))));
- // int stat(const char *restrict path, struct stat *restrict buf);
- addToFunctionSummaryMap(
- "stat",
- Signature(ArgTypes{ConstCharPtrRestrictTy, StructStatPtrRestrictTy},
- RetType{IntTy}),
- Summary(NoEvalCall)
- .Case(ReturnsZeroOrMinusOne)
- .ArgConstraint(NotNull(ArgNo(0)))
- .ArgConstraint(NotNull(ArgNo(1))));
- // int lstat(const char *restrict path, struct stat *restrict buf);
- addToFunctionSummaryMap(
- "lstat",
- Signature(ArgTypes{ConstCharPtrRestrictTy, StructStatPtrRestrictTy},
- RetType{IntTy}),
- Summary(NoEvalCall)
- .Case(ReturnsZeroOrMinusOne)
- .ArgConstraint(NotNull(ArgNo(0)))
- .ArgConstraint(NotNull(ArgNo(1))));
- // int fstatat(int fd, const char *restrict path,
- // struct stat *restrict buf, int flag);
- addToFunctionSummaryMap(
- "fstatat",
- Signature(ArgTypes{IntTy, ConstCharPtrRestrictTy,
- StructStatPtrRestrictTy, IntTy},
- RetType{IntTy}),
- Summary(NoEvalCall)
- .Case(ReturnsZeroOrMinusOne)
- .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
- .ArgConstraint(NotNull(ArgNo(1)))
- .ArgConstraint(NotNull(ArgNo(2))));
- // DIR *opendir(const char *name);
- addToFunctionSummaryMap(
- "opendir", Signature(ArgTypes{ConstCharPtrTy}, RetType{DirPtrTy}),
- Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
- // DIR *fdopendir(int fd);
- addToFunctionSummaryMap("fdopendir",
- Signature(ArgTypes{IntTy}, RetType{DirPtrTy}),
- Summary(NoEvalCall)
- .ArgConstraint(ArgumentCondition(
- 0, WithinRange, Range(0, IntMax))));
- // int isatty(int fildes);
- addToFunctionSummaryMap(
- "isatty", Signature(ArgTypes{IntTy}, RetType{IntTy}),
- Summary(NoEvalCall)
- .Case({ReturnValueCondition(WithinRange, Range(0, 1))})
- .ArgConstraint(
- ArgumentCondition(0, WithinRange, Range(0, IntMax))));
- // FILE *popen(const char *command, const char *type);
- addToFunctionSummaryMap(
- "popen",
- Signature(ArgTypes{ConstCharPtrTy, ConstCharPtrTy}, RetType{FilePtrTy}),
- Summary(NoEvalCall)
- .ArgConstraint(NotNull(ArgNo(0)))
- .ArgConstraint(NotNull(ArgNo(1))));
- // int pclose(FILE *stream);
- addToFunctionSummaryMap(
- "pclose", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
- Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
- // int close(int fildes);
- addToFunctionSummaryMap("close", Signature(ArgTypes{IntTy}, RetType{IntTy}),
- Summary(NoEvalCall)
- .Case(ReturnsZeroOrMinusOne)
- .ArgConstraint(ArgumentCondition(
- 0, WithinRange, Range(-1, IntMax))));
- // long fpathconf(int fildes, int name);
- addToFunctionSummaryMap("fpathconf",
- Signature(ArgTypes{IntTy, IntTy}, RetType{LongTy}),
- Summary(NoEvalCall)
- .ArgConstraint(ArgumentCondition(
- 0, WithinRange, Range(0, IntMax))));
- // long pathconf(const char *path, int name);
- addToFunctionSummaryMap(
- "pathconf", Signature(ArgTypes{ConstCharPtrTy, IntTy}, RetType{LongTy}),
- Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
- // FILE *fdopen(int fd, const char *mode);
- addToFunctionSummaryMap(
- "fdopen",
- Signature(ArgTypes{IntTy, ConstCharPtrTy}, RetType{FilePtrTy}),
- Summary(NoEvalCall)
- .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
- .ArgConstraint(NotNull(ArgNo(1))));
- // void rewinddir(DIR *dir);
- addToFunctionSummaryMap(
- "rewinddir", Signature(ArgTypes{DirPtrTy}, RetType{VoidTy}),
- Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
- // void seekdir(DIR *dirp, long loc);
- addToFunctionSummaryMap(
- "seekdir", Signature(ArgTypes{DirPtrTy, LongTy}, RetType{VoidTy}),
- Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
- // int rand_r(unsigned int *seedp);
- addToFunctionSummaryMap(
- "rand_r", Signature(ArgTypes{UnsignedIntPtrTy}, RetType{IntTy}),
- Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
- // int fileno(FILE *stream);
- addToFunctionSummaryMap("fileno",
- Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
- Summary(NoEvalCall)
- .Case(ReturnsFileDescriptor)
- .ArgConstraint(NotNull(ArgNo(0))));
- // int fseeko(FILE *stream, off_t offset, int whence);
- addToFunctionSummaryMap(
- "fseeko",
- Signature(ArgTypes{FilePtrTy, Off_tTy, IntTy}, RetType{IntTy}),
- Summary(NoEvalCall)
- .Case(ReturnsZeroOrMinusOne)
- .ArgConstraint(NotNull(ArgNo(0))));
- // off_t ftello(FILE *stream);
- addToFunctionSummaryMap(
- "ftello", Signature(ArgTypes{FilePtrTy}, RetType{Off_tTy}),
- Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
- // void *mmap(void *addr, size_t length, int prot, int flags, int fd,
- // off_t offset);
- addToFunctionSummaryMap(
- "mmap",
- Signature(ArgTypes{VoidPtrTy, SizeTy, IntTy, IntTy, IntTy, Off_tTy},
- RetType{VoidPtrTy}),
- Summary(NoEvalCall)
- .ArgConstraint(ArgumentCondition(1, WithinRange, Range(1, SizeMax)))
- .ArgConstraint(
- ArgumentCondition(4, WithinRange, Range(-1, IntMax))));
- Optional<QualType> Off64_tTy = lookupTy("off64_t");
- // void *mmap64(void *addr, size_t length, int prot, int flags, int fd,
- // off64_t offset);
- addToFunctionSummaryMap(
- "mmap64",
- Signature(ArgTypes{VoidPtrTy, SizeTy, IntTy, IntTy, IntTy, Off64_tTy},
- RetType{VoidPtrTy}),
- Summary(NoEvalCall)
- .ArgConstraint(ArgumentCondition(1, WithinRange, Range(1, SizeMax)))
- .ArgConstraint(
- ArgumentCondition(4, WithinRange, Range(-1, IntMax))));
- // int pipe(int fildes[2]);
- addToFunctionSummaryMap("pipe",
- Signature(ArgTypes{IntPtrTy}, RetType{IntTy}),
- Summary(NoEvalCall)
- .Case(ReturnsZeroOrMinusOne)
- .ArgConstraint(NotNull(ArgNo(0))));
- // off_t lseek(int fildes, off_t offset, int whence);
- addToFunctionSummaryMap(
- "lseek", Signature(ArgTypes{IntTy, Off_tTy, IntTy}, RetType{Off_tTy}),
- Summary(NoEvalCall)
- .ArgConstraint(
- ArgumentCondition(0, WithinRange, Range(0, IntMax))));
- // ssize_t readlink(const char *restrict path, char *restrict buf,
- // size_t bufsize);
- addToFunctionSummaryMap(
- "readlink",
- Signature(ArgTypes{ConstCharPtrRestrictTy, CharPtrRestrictTy, SizeTy},
- RetType{Ssize_tTy}),
- Summary(NoEvalCall)
- .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)),
- ReturnValueCondition(WithinRange, Range(-1, Ssize_tMax))})
- .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",
- Signature(
- ArgTypes{IntTy, ConstCharPtrRestrictTy, CharPtrRestrictTy, SizeTy},
- RetType{Ssize_tTy}),
- Summary(NoEvalCall)
- .Case({ReturnValueCondition(LessThanOrEq, ArgNo(3)),
- ReturnValueCondition(WithinRange, Range(-1, Ssize_tMax))})
- .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);
- addToFunctionSummaryMap(
- "renameat",
- Signature(ArgTypes{IntTy, ConstCharPtrTy, IntTy, ConstCharPtrTy},
- RetType{IntTy}),
- Summary(NoEvalCall)
- .Case(ReturnsZeroOrMinusOne)
- .ArgConstraint(NotNull(ArgNo(1)))
- .ArgConstraint(NotNull(ArgNo(3))));
- // char *realpath(const char *restrict file_name,
- // char *restrict resolved_name);
- addToFunctionSummaryMap(
- "realpath",
- Signature(ArgTypes{ConstCharPtrRestrictTy, CharPtrRestrictTy},
- RetType{CharPtrTy}),
- Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
- QualType CharPtrConstPtr = getPointerTy(getConstTy(CharPtrTy));
- // int execv(const char *path, char *const argv[]);
- addToFunctionSummaryMap(
- "execv",
- Signature(ArgTypes{ConstCharPtrTy, CharPtrConstPtr}, RetType{IntTy}),
- Summary(NoEvalCall)
- .Case({ReturnValueCondition(WithinRange, SingleValue(-1))})
- .ArgConstraint(NotNull(ArgNo(0))));
- // int execvp(const char *file, char *const argv[]);
- addToFunctionSummaryMap(
- "execvp",
- Signature(ArgTypes{ConstCharPtrTy, CharPtrConstPtr}, RetType{IntTy}),
- Summary(NoEvalCall)
- .Case({ReturnValueCondition(WithinRange, SingleValue(-1))})
- .ArgConstraint(NotNull(ArgNo(0))));
- // int getopt(int argc, char * const argv[], const char *optstring);
- addToFunctionSummaryMap(
- "getopt",
- Signature(ArgTypes{IntTy, CharPtrConstPtr, ConstCharPtrTy},
- RetType{IntTy}),
- Summary(NoEvalCall)
- .Case({ReturnValueCondition(WithinRange, Range(-1, UCharRangeMax))})
- .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
- .ArgConstraint(NotNull(ArgNo(1)))
- .ArgConstraint(NotNull(ArgNo(2))));
- Optional<QualType> StructSockaddrTy = lookupTy("sockaddr");
- Optional<QualType> StructSockaddrPtrTy = getPointerTy(StructSockaddrTy);
- Optional<QualType> ConstStructSockaddrPtrTy =
- getPointerTy(getConstTy(StructSockaddrTy));
- Optional<QualType> StructSockaddrPtrRestrictTy =
- getRestrictTy(StructSockaddrPtrTy);
- Optional<QualType> ConstStructSockaddrPtrRestrictTy =
- getRestrictTy(ConstStructSockaddrPtrTy);
- Optional<QualType> Socklen_tTy = lookupTy("socklen_t");
- Optional<QualType> Socklen_tPtrTy = getPointerTy(Socklen_tTy);
- Optional<QualType> Socklen_tPtrRestrictTy = getRestrictTy(Socklen_tPtrTy);
- Optional<RangeInt> 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
- // 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.
- auto Accept =
- Summary(NoEvalCall)
- .Case(ReturnsFileDescriptor)
- .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",
- Signature(ArgTypes{IntTy, ConstStructSockaddrPtrTy, Socklen_tTy},
- RetType{IntTy}),
- Summary(NoEvalCall)
- .Case(ReturnsZeroOrMinusOne)
- .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",
- Signature(ArgTypes{IntTy, Irrelevant, Socklen_tTy}, RetType{IntTy}),
- Summary(NoEvalCall)
- .Case(ReturnsZeroOrMinusOne)
- .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",
- Signature(ArgTypes{IntTy, StructSockaddrPtrRestrictTy,
- Socklen_tPtrRestrictTy},
- RetType{IntTy}),
- Summary(NoEvalCall)
- .Case(ReturnsZeroOrMinusOne)
- .ArgConstraint(
- ArgumentCondition(0, WithinRange, Range(0, IntMax)))
- .ArgConstraint(NotNull(ArgNo(1)))
- .ArgConstraint(NotNull(ArgNo(2)))))
- addToFunctionSummaryMap(
- "getpeername",
- Signature(ArgTypes{IntTy, Irrelevant, Socklen_tPtrRestrictTy},
- RetType{IntTy}),
- Summary(NoEvalCall)
- .Case(ReturnsZeroOrMinusOne)
- .ArgConstraint(
- ArgumentCondition(0, WithinRange, Range(0, IntMax))));
- // int getsockname(int socket, struct sockaddr *restrict address,
- // socklen_t *restrict address_len);
- if (!addToFunctionSummaryMap(
- "getsockname",
- Signature(ArgTypes{IntTy, StructSockaddrPtrRestrictTy,
- Socklen_tPtrRestrictTy},
- RetType{IntTy}),
- Summary(NoEvalCall)
- .Case(ReturnsZeroOrMinusOne)
- .ArgConstraint(
- ArgumentCondition(0, WithinRange, Range(0, IntMax)))
- .ArgConstraint(NotNull(ArgNo(1)))
- .ArgConstraint(NotNull(ArgNo(2)))))
- addToFunctionSummaryMap(
- "getsockname",
- Signature(ArgTypes{IntTy, Irrelevant, Socklen_tPtrRestrictTy},
- RetType{IntTy}),
- Summary(NoEvalCall)
- .Case(ReturnsZeroOrMinusOne)
- .ArgConstraint(
- ArgumentCondition(0, WithinRange, Range(0, IntMax))));
- // int connect(int socket, const struct sockaddr *address, socklen_t
- // address_len);
- if (!addToFunctionSummaryMap(
- "connect",
- Signature(ArgTypes{IntTy, ConstStructSockaddrPtrTy, Socklen_tTy},
- RetType{IntTy}),
- Summary(NoEvalCall)
- .Case(ReturnsZeroOrMinusOne)
- .ArgConstraint(
- ArgumentCondition(0, WithinRange, Range(0, IntMax)))
- .ArgConstraint(NotNull(ArgNo(1)))))
- addToFunctionSummaryMap(
- "connect",
- Signature(ArgTypes{IntTy, Irrelevant, Socklen_tTy}, RetType{IntTy}),
- Summary(NoEvalCall)
- .Case(ReturnsZeroOrMinusOne)
- .ArgConstraint(
- ArgumentCondition(0, WithinRange, Range(0, IntMax))));
- auto Recvfrom =
- Summary(NoEvalCall)
- .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)),
- ReturnValueCondition(WithinRange, Range(-1, Ssize_tMax))})
- .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,
- 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)
- .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)),
- ReturnValueCondition(WithinRange, Range(-1, Ssize_tMax))})
- .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
- .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
- /*BufSize=*/ArgNo(2)));
- if (!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",
- Signature(ArgTypes{IntTy, IntTy}, RetType{IntTy}),
- Summary(NoEvalCall)
- .Case(ReturnsZeroOrMinusOne)
- .ArgConstraint(ArgumentCondition(
- 0, WithinRange, Range(0, IntMax))));
- // ssize_t recv(int sockfd, void *buf, size_t len, int flags);
- addToFunctionSummaryMap(
- "recv",
- Signature(ArgTypes{IntTy, VoidPtrTy, SizeTy, IntTy},
- RetType{Ssize_tTy}),
- Summary(NoEvalCall)
- .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)),
- ReturnValueCondition(WithinRange, Range(-1, Ssize_tMax))})
- .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
- .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
- /*BufSize=*/ArgNo(2))));
- Optional<QualType> StructMsghdrTy = lookupTy("msghdr");
- Optional<QualType> StructMsghdrPtrTy = getPointerTy(StructMsghdrTy);
- Optional<QualType> ConstStructMsghdrPtrTy =
- getPointerTy(getConstTy(StructMsghdrTy));
- // ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);
- addToFunctionSummaryMap(
- "recvmsg",
- Signature(ArgTypes{IntTy, StructMsghdrPtrTy, IntTy},
- RetType{Ssize_tTy}),
- Summary(NoEvalCall)
- .Case({ReturnValueCondition(WithinRange, Range(-1, Ssize_tMax))})
- .ArgConstraint(
- ArgumentCondition(0, WithinRange, Range(0, IntMax))));
- // ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
- addToFunctionSummaryMap(
- "sendmsg",
- Signature(ArgTypes{IntTy, ConstStructMsghdrPtrTy, IntTy},
- RetType{Ssize_tTy}),
- Summary(NoEvalCall)
- .Case({ReturnValueCondition(WithinRange, Range(-1, Ssize_tMax))})
- .ArgConstraint(
- ArgumentCondition(0, WithinRange, Range(0, IntMax))));
- // int setsockopt(int socket, int level, int option_name,
- // const void *option_value, socklen_t option_len);
- addToFunctionSummaryMap(
- "setsockopt",
- Signature(ArgTypes{IntTy, IntTy, IntTy, ConstVoidPtrTy, Socklen_tTy},
- RetType{IntTy}),
- Summary(NoEvalCall)
- .Case(ReturnsZeroOrMinusOne)
- .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",
- Signature(ArgTypes{IntTy, IntTy, IntTy, VoidPtrRestrictTy,
- Socklen_tPtrRestrictTy},
- RetType{IntTy}),
- Summary(NoEvalCall)
- .Case(ReturnsZeroOrMinusOne)
- .ArgConstraint(NotNull(ArgNo(3)))
- .ArgConstraint(NotNull(ArgNo(4))));
- // ssize_t send(int sockfd, const void *buf, size_t len, int flags);
- addToFunctionSummaryMap(
- "send",
- Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTy, IntTy},
- RetType{Ssize_tTy}),
- Summary(NoEvalCall)
- .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)),
- ReturnValueCondition(WithinRange, Range(-1, Ssize_tMax))})
- .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",
- Signature(ArgTypes{IntTy, IntTy, IntTy, IntPtrTy}, RetType{IntTy}),
- Summary(NoEvalCall)
- .Case(ReturnsZeroOrMinusOne)
- .ArgConstraint(NotNull(ArgNo(3))));
- // 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",
- Signature(ArgTypes{ConstStructSockaddrPtrRestrictTy, Socklen_tTy,
- CharPtrRestrictTy, Socklen_tTy, CharPtrRestrictTy,
- Socklen_tTy, IntTy},
- RetType{IntTy}),
- Summary(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))));
- Optional<QualType> StructUtimbufTy = lookupTy("utimbuf");
- Optional<QualType> StructUtimbufPtrTy = getPointerTy(StructUtimbufTy);
- // int utime(const char *filename, struct utimbuf *buf);
- addToFunctionSummaryMap(
- "utime",
- Signature(ArgTypes{ConstCharPtrTy, StructUtimbufPtrTy}, RetType{IntTy}),
- Summary(NoEvalCall)
- .Case(ReturnsZeroOrMinusOne)
- .ArgConstraint(NotNull(ArgNo(0))));
- Optional<QualType> StructTimespecTy = lookupTy("timespec");
- Optional<QualType> StructTimespecPtrTy = getPointerTy(StructTimespecTy);
- Optional<QualType> ConstStructTimespecPtrTy =
- getPointerTy(getConstTy(StructTimespecTy));
- // int futimens(int fd, const struct timespec times[2]);
- addToFunctionSummaryMap(
- "futimens",
- Signature(ArgTypes{IntTy, ConstStructTimespecPtrTy}, RetType{IntTy}),
- Summary(NoEvalCall)
- .Case(ReturnsZeroOrMinusOne)
- .ArgConstraint(
- ArgumentCondition(0, WithinRange, Range(0, IntMax))));
- // int utimensat(int dirfd, const char *pathname,
- // const struct timespec times[2], int flags);
- addToFunctionSummaryMap("utimensat",
- Signature(ArgTypes{IntTy, ConstCharPtrTy,
- ConstStructTimespecPtrTy, IntTy},
- RetType{IntTy}),
- Summary(NoEvalCall)
- .Case(ReturnsZeroOrMinusOne)
- .ArgConstraint(NotNull(ArgNo(1))));
- Optional<QualType> StructTimevalTy = lookupTy("timeval");
- Optional<QualType> ConstStructTimevalPtrTy =
- getPointerTy(getConstTy(StructTimevalTy));
- // int utimes(const char *filename, const struct timeval times[2]);
- addToFunctionSummaryMap(
- "utimes",
- Signature(ArgTypes{ConstCharPtrTy, ConstStructTimevalPtrTy},
- RetType{IntTy}),
- Summary(NoEvalCall)
- .Case(ReturnsZeroOrMinusOne)
- .ArgConstraint(NotNull(ArgNo(0))));
- // int nanosleep(const struct timespec *rqtp, struct timespec *rmtp);
- addToFunctionSummaryMap(
- "nanosleep",
- Signature(ArgTypes{ConstStructTimespecPtrTy, StructTimespecPtrTy},
- RetType{IntTy}),
- Summary(NoEvalCall)
- .Case(ReturnsZeroOrMinusOne)
- .ArgConstraint(NotNull(ArgNo(0))));
- Optional<QualType> Time_tTy = lookupTy("time_t");
- Optional<QualType> ConstTime_tPtrTy = getPointerTy(getConstTy(Time_tTy));
- Optional<QualType> ConstTime_tPtrRestrictTy =
- getRestrictTy(ConstTime_tPtrTy);
- Optional<QualType> StructTmTy = lookupTy("tm");
- Optional<QualType> StructTmPtrTy = getPointerTy(StructTmTy);
- Optional<QualType> StructTmPtrRestrictTy = getRestrictTy(StructTmPtrTy);
- Optional<QualType> ConstStructTmPtrTy =
- getPointerTy(getConstTy(StructTmTy));
- Optional<QualType> ConstStructTmPtrRestrictTy =
- getRestrictTy(ConstStructTmPtrTy);
- // struct tm * localtime(const time_t *tp);
- addToFunctionSummaryMap(
- "localtime",
- Signature(ArgTypes{ConstTime_tPtrTy}, RetType{StructTmPtrTy}),
- Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
- // struct tm *localtime_r(const time_t *restrict timer,
- // struct tm *restrict result);
- addToFunctionSummaryMap(
- "localtime_r",
- Signature(ArgTypes{ConstTime_tPtrRestrictTy, StructTmPtrRestrictTy},
- RetType{StructTmPtrTy}),
- Summary(NoEvalCall)
- .ArgConstraint(NotNull(ArgNo(0)))
- .ArgConstraint(NotNull(ArgNo(1))));
- // char *asctime_r(const struct tm *restrict tm, char *restrict buf);
- addToFunctionSummaryMap(
- "asctime_r",
- Signature(ArgTypes{ConstStructTmPtrRestrictTy, CharPtrRestrictTy},
- RetType{CharPtrTy}),
- Summary(NoEvalCall)
- .ArgConstraint(NotNull(ArgNo(0)))
- .ArgConstraint(NotNull(ArgNo(1)))
- .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
- /*MinBufSize=*/BVF.getValue(26, IntTy))));
- // char *ctime_r(const time_t *timep, char *buf);
- addToFunctionSummaryMap(
- "ctime_r",
- Signature(ArgTypes{ConstTime_tPtrTy, CharPtrTy}, RetType{CharPtrTy}),
- Summary(NoEvalCall)
- .ArgConstraint(NotNull(ArgNo(0)))
- .ArgConstraint(NotNull(ArgNo(1)))
- .ArgConstraint(BufferSize(
- /*Buffer=*/ArgNo(1),
- /*MinBufSize=*/BVF.getValue(26, IntTy))));
- // struct tm *gmtime_r(const time_t *restrict timer,
- // struct tm *restrict result);
- addToFunctionSummaryMap(
- "gmtime_r",
- Signature(ArgTypes{ConstTime_tPtrRestrictTy, StructTmPtrRestrictTy},
- RetType{StructTmPtrTy}),
- Summary(NoEvalCall)
- .ArgConstraint(NotNull(ArgNo(0)))
- .ArgConstraint(NotNull(ArgNo(1))));
- // struct tm * gmtime(const time_t *tp);
- addToFunctionSummaryMap(
- "gmtime", Signature(ArgTypes{ConstTime_tPtrTy}, RetType{StructTmPtrTy}),
- Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
- Optional<QualType> Clockid_tTy = lookupTy("clockid_t");
- // int clock_gettime(clockid_t clock_id, struct timespec *tp);
- addToFunctionSummaryMap(
- "clock_gettime",
- Signature(ArgTypes{Clockid_tTy, StructTimespecPtrTy}, RetType{IntTy}),
- Summary(NoEvalCall)
- .Case(ReturnsZeroOrMinusOne)
- .ArgConstraint(NotNull(ArgNo(1))));
- Optional<QualType> StructItimervalTy = lookupTy("itimerval");
- Optional<QualType> StructItimervalPtrTy = getPointerTy(StructItimervalTy);
- // int getitimer(int which, struct itimerval *curr_value);
- addToFunctionSummaryMap(
- "getitimer",
- Signature(ArgTypes{IntTy, StructItimervalPtrTy}, RetType{IntTy}),
- Summary(NoEvalCall)
- .Case(ReturnsZeroOrMinusOne)
- .ArgConstraint(NotNull(ArgNo(1))));
- Optional<QualType> Pthread_cond_tTy = lookupTy("pthread_cond_t");
- Optional<QualType> Pthread_cond_tPtrTy = getPointerTy(Pthread_cond_tTy);
- Optional<QualType> Pthread_tTy = lookupTy("pthread_t");
- Optional<QualType> Pthread_tPtrTy = getPointerTy(Pthread_tTy);
- Optional<QualType> Pthread_tPtrRestrictTy = getRestrictTy(Pthread_tPtrTy);
- Optional<QualType> Pthread_mutex_tTy = lookupTy("pthread_mutex_t");
- Optional<QualType> Pthread_mutex_tPtrTy = getPointerTy(Pthread_mutex_tTy);
- Optional<QualType> Pthread_mutex_tPtrRestrictTy =
- getRestrictTy(Pthread_mutex_tPtrTy);
- Optional<QualType> Pthread_attr_tTy = lookupTy("pthread_attr_t");
- Optional<QualType> Pthread_attr_tPtrTy = getPointerTy(Pthread_attr_tTy);
- Optional<QualType> ConstPthread_attr_tPtrTy =
- getPointerTy(getConstTy(Pthread_attr_tTy));
- Optional<QualType> ConstPthread_attr_tPtrRestrictTy =
- getRestrictTy(ConstPthread_attr_tPtrTy);
- Optional<QualType> Pthread_mutexattr_tTy = lookupTy("pthread_mutexattr_t");
- Optional<QualType> ConstPthread_mutexattr_tPtrTy =
- getPointerTy(getConstTy(Pthread_mutexattr_tTy));
- Optional<QualType> ConstPthread_mutexattr_tPtrRestrictTy =
- getRestrictTy(ConstPthread_mutexattr_tPtrTy);
- QualType PthreadStartRoutineTy = getPointerTy(
- ACtx.getFunctionType(/*ResultTy=*/VoidPtrTy, /*Args=*/VoidPtrTy,
- FunctionProtoType::ExtProtoInfo()));
- // int pthread_cond_signal(pthread_cond_t *cond);
- // int pthread_cond_broadcast(pthread_cond_t *cond);
- addToFunctionSummaryMap(
- {"pthread_cond_signal", "pthread_cond_broadcast"},
- Signature(ArgTypes{Pthread_cond_tPtrTy}, RetType{IntTy}),
- Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
- // int pthread_create(pthread_t *restrict thread,
- // const pthread_attr_t *restrict attr,
- // void *(*start_routine)(void*), void *restrict arg);
- addToFunctionSummaryMap(
- "pthread_create",
- Signature(ArgTypes{Pthread_tPtrRestrictTy,
- ConstPthread_attr_tPtrRestrictTy,
- PthreadStartRoutineTy, VoidPtrRestrictTy},
- RetType{IntTy}),
- Summary(NoEvalCall)
- .ArgConstraint(NotNull(ArgNo(0)))
- .ArgConstraint(NotNull(ArgNo(2))));
- // int pthread_attr_destroy(pthread_attr_t *attr);
- // int pthread_attr_init(pthread_attr_t *attr);
- addToFunctionSummaryMap(
- {"pthread_attr_destroy", "pthread_attr_init"},
- Signature(ArgTypes{Pthread_attr_tPtrTy}, RetType{IntTy}),
- Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
- // int pthread_attr_getstacksize(const pthread_attr_t *restrict attr,
- // size_t *restrict stacksize);
- // int pthread_attr_getguardsize(const pthread_attr_t *restrict attr,
- // size_t *restrict guardsize);
- addToFunctionSummaryMap(
- {"pthread_attr_getstacksize", "pthread_attr_getguardsize"},
- Signature(ArgTypes{ConstPthread_attr_tPtrRestrictTy, SizePtrRestrictTy},
- RetType{IntTy}),
- Summary(NoEvalCall)
- .ArgConstraint(NotNull(ArgNo(0)))
- .ArgConstraint(NotNull(ArgNo(1))));
- // int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize);
- // int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize);
- addToFunctionSummaryMap(
- {"pthread_attr_setstacksize", "pthread_attr_setguardsize"},
- Signature(ArgTypes{Pthread_attr_tPtrTy, SizeTy}, RetType{IntTy}),
- Summary(NoEvalCall)
- .ArgConstraint(NotNull(ArgNo(0)))
- .ArgConstraint(
- ArgumentCondition(1, WithinRange, Range(0, SizeMax))));
- // int pthread_mutex_init(pthread_mutex_t *restrict mutex, const
- // pthread_mutexattr_t *restrict attr);
- addToFunctionSummaryMap(
- "pthread_mutex_init",
- Signature(ArgTypes{Pthread_mutex_tPtrRestrictTy,
- ConstPthread_mutexattr_tPtrRestrictTy},
- RetType{IntTy}),
- Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
- // int pthread_mutex_destroy(pthread_mutex_t *mutex);
- // int pthread_mutex_lock(pthread_mutex_t *mutex);
- // int pthread_mutex_trylock(pthread_mutex_t *mutex);
- // int pthread_mutex_unlock(pthread_mutex_t *mutex);
- addToFunctionSummaryMap(
- {"pthread_mutex_destroy", "pthread_mutex_lock", "pthread_mutex_trylock",
- "pthread_mutex_unlock"},
- Signature(ArgTypes{Pthread_mutex_tPtrTy}, RetType{IntTy}),
- Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
- }
- // Functions for testing.
- if (ChecksEnabled[CK_StdCLibraryFunctionsTesterChecker]) {
- addToFunctionSummaryMap(
- "__not_null", Signature(ArgTypes{IntPtrTy}, RetType{IntTy}),
- Summary(EvalCallAsPure).ArgConstraint(NotNull(ArgNo(0))));
- // Test range values.
- addToFunctionSummaryMap(
- "__single_val_1", Signature(ArgTypes{IntTy}, RetType{IntTy}),
- Summary(EvalCallAsPure)
- .ArgConstraint(ArgumentCondition(0U, WithinRange, SingleValue(1))));
- addToFunctionSummaryMap(
- "__range_1_2", Signature(ArgTypes{IntTy}, RetType{IntTy}),
- Summary(EvalCallAsPure)
- .ArgConstraint(ArgumentCondition(0U, WithinRange, Range(1, 2))));
- addToFunctionSummaryMap("__range_1_2__4_5",
- Signature(ArgTypes{IntTy}, RetType{IntTy}),
- Summary(EvalCallAsPure)
- .ArgConstraint(ArgumentCondition(
- 0U, WithinRange, Range({1, 2}, {4, 5}))));
- // Test range kind.
- addToFunctionSummaryMap(
- "__within", Signature(ArgTypes{IntTy}, RetType{IntTy}),
- Summary(EvalCallAsPure)
- .ArgConstraint(ArgumentCondition(0U, WithinRange, SingleValue(1))));
- addToFunctionSummaryMap(
- "__out_of", Signature(ArgTypes{IntTy}, RetType{IntTy}),
- Summary(EvalCallAsPure)
- .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(1))));
- addToFunctionSummaryMap(
- "__two_constrained_args",
- Signature(ArgTypes{IntTy, IntTy}, RetType{IntTy}),
- Summary(EvalCallAsPure)
- .ArgConstraint(ArgumentCondition(0U, WithinRange, SingleValue(1)))
- .ArgConstraint(ArgumentCondition(1U, WithinRange, SingleValue(1))));
- addToFunctionSummaryMap(
- "__arg_constrained_twice", Signature(ArgTypes{IntTy}, RetType{IntTy}),
- Summary(EvalCallAsPure)
- .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(1)))
- .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(2))));
- addToFunctionSummaryMap(
- "__defaultparam",
- Signature(ArgTypes{Irrelevant, IntTy}, RetType{IntTy}),
- Summary(EvalCallAsPure).ArgConstraint(NotNull(ArgNo(0))));
- addToFunctionSummaryMap(
- "__variadic",
- Signature(ArgTypes{VoidPtrTy, ConstCharPtrTy}, RetType{IntTy}),
- Summary(EvalCallAsPure)
- .ArgConstraint(NotNull(ArgNo(0)))
- .ArgConstraint(NotNull(ArgNo(1))));
- addToFunctionSummaryMap(
- "__buf_size_arg_constraint",
- Signature(ArgTypes{ConstVoidPtrTy, SizeTy}, RetType{IntTy}),
- Summary(EvalCallAsPure)
- .ArgConstraint(
- BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1))));
- addToFunctionSummaryMap(
- "__buf_size_arg_constraint_mul",
- Signature(ArgTypes{ConstVoidPtrTy, SizeTy, SizeTy}, RetType{IntTy}),
- Summary(EvalCallAsPure)
- .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1),
- /*BufSizeMultiplier=*/ArgNo(2))));
- addToFunctionSummaryMap(
- "__buf_size_arg_constraint_concrete",
- Signature(ArgTypes{ConstVoidPtrTy}, RetType{IntTy}),
- Summary(EvalCallAsPure)
- .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(0),
- /*BufSize=*/BVF.getValue(10, IntTy))));
- addToFunctionSummaryMap(
- {"__test_restrict_param_0", "__test_restrict_param_1",
- "__test_restrict_param_2"},
- Signature(ArgTypes{VoidPtrRestrictTy}, RetType{VoidTy}),
- Summary(EvalCallAsPure));
- }
- SummariesInitialized = true;
- }
- void ento::registerStdCLibraryFunctionsChecker(CheckerManager &mgr) {
- auto *Checker = mgr.registerChecker<StdLibraryFunctionsChecker>();
- const AnalyzerOptions &Opts = mgr.getAnalyzerOptions();
- Checker->DisplayLoadedSummaries =
- Opts.getCheckerBooleanOption(Checker, "DisplayLoadedSummaries");
- Checker->ModelPOSIX = Opts.getCheckerBooleanOption(Checker, "ModelPOSIX");
- Checker->ShouldAssumeControlledEnvironment =
- Opts.ShouldAssumeControlledEnvironment;
- }
- bool ento::shouldRegisterStdCLibraryFunctionsChecker(
- const CheckerManager &mgr) {
- return true;
- }
- #define REGISTER_CHECKER(name) \
- void ento::register##name(CheckerManager &mgr) { \
- StdLibraryFunctionsChecker *checker = \
- mgr.getChecker<StdLibraryFunctionsChecker>(); \
- checker->ChecksEnabled[StdLibraryFunctionsChecker::CK_##name] = true; \
- checker->CheckNames[StdLibraryFunctionsChecker::CK_##name] = \
- mgr.getCurrentCheckerName(); \
- } \
- \
- bool ento::shouldRegister##name(const CheckerManager &mgr) { return true; }
- REGISTER_CHECKER(StdCLibraryFunctionArgsChecker)
- REGISTER_CHECKER(StdCLibraryFunctionsTesterChecker)
|