brintos

brintos / llvm-project-archived public Read only

0
0
Text · 173.5 KiB · 844447f Raw
3978 lines · cpp
1//=== StdLibraryFunctionsChecker.cpp - Model standard functions -*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This checker improves modeling of a few simple library functions.10//11// This checker provides a specification format - `Summary' - and12// contains descriptions of some library functions in this format. Each13// specification contains a list of branches for splitting the program state14// upon call, and range constraints on argument and return-value symbols that15// are satisfied on each branch. This spec can be expanded to include more16// items, like external effects of the function.17//18// The main difference between this approach and the body farms technique is19// in more explicit control over how many branches are produced. For example,20// consider standard C function `ispunct(int x)', which returns a non-zero value21// iff `x' is a punctuation character, that is, when `x' is in range22//   ['!', '/']   [':', '@']  U  ['[', '\`']  U  ['{', '~'].23// `Summary' provides only two branches for this function. However,24// any attempt to describe this range with if-statements in the body farm25// would result in many more branches. Because each branch needs to be analyzed26// independently, this significantly reduces performance. Additionally,27// once we consider a branch on which `x' is in range, say, ['!', '/'],28// we assume that such branch is an important separate path through the program,29// which may lead to false positives because considering this particular path30// was not consciously intended, and therefore it might have been unreachable.31//32// This checker uses eval::Call for modeling pure functions (functions without33// side effects), for which their `Summary' is a precise model. This avoids34// unnecessary invalidation passes. Conflicts with other checkers are unlikely35// because if the function has no other effects, other checkers would probably36// never want to improve upon the modeling done by this checker.37//38// Non-pure functions, for which only partial improvement over the default39// behavior is expected, are modeled via check::PostCall, non-intrusively.40//41//===----------------------------------------------------------------------===//42 43#include "ErrnoModeling.h"44#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"45#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"46#include "clang/StaticAnalyzer/Core/Checker.h"47#include "clang/StaticAnalyzer/Core/CheckerManager.h"48#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"49#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"50#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h"51#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicExtent.h"52#include "llvm/ADT/STLExtras.h"53#include "llvm/ADT/SmallString.h"54#include "llvm/ADT/StringExtras.h"55#include "llvm/Support/FormatVariadic.h"56 57#include <optional>58#include <string>59 60using namespace clang;61using namespace clang::ento;62 63namespace {64class StdLibraryFunctionsChecker65    : public Checker<check::PreCall, check::PostCall, eval::Call> {66 67  class Summary;68 69  /// Specify how much the analyzer engine should entrust modeling this function70  /// to us.71  enum InvalidationKind {72    /// No \c eval::Call for the function, it can be modeled elsewhere.73    /// This checker checks only pre and post conditions.74    NoEvalCall,75    /// The function is modeled completely in this checker.76    EvalCallAsPure77  };78 79  /// Given a range, should the argument stay inside or outside this range?80  enum RangeKind { OutOfRange, WithinRange };81 82  static RangeKind negateKind(RangeKind K) {83    switch (K) {84    case OutOfRange:85      return WithinRange;86    case WithinRange:87      return OutOfRange;88    }89    llvm_unreachable("Unknown range kind");90  }91 92  /// The universal integral type to use in value range descriptions.93  /// Unsigned to make sure overflows are well-defined.94  typedef uint64_t RangeInt;95 96  /// Describes a single range constraint. Eg. {{0, 1}, {3, 4}} is97  /// a non-negative integer, which less than 5 and not equal to 2.98  typedef std::vector<std::pair<RangeInt, RangeInt>> IntRangeVector;99 100  /// A reference to an argument or return value by its number.101  /// ArgNo in CallExpr and CallEvent is defined as Unsigned, but102  /// obviously uint32_t should be enough for all practical purposes.103  typedef uint32_t ArgNo;104  /// Special argument number for specifying the return value.105  static const ArgNo Ret;106 107  /// Get a string representation of an argument index.108  /// E.g.: (1) -> '1st arg', (2) - > '2nd arg'109  static void printArgDesc(ArgNo, llvm::raw_ostream &Out);110  /// Print value X of the argument in form " (which is X)",111  /// if the value is a fixed known value, otherwise print nothing.112  /// This is used as simple explanation of values if possible.113  static void printArgValueInfo(ArgNo ArgN, ProgramStateRef State,114                                const CallEvent &Call, llvm::raw_ostream &Out);115  /// Append textual description of a numeric range [RMin,RMax] to116  /// \p Out.117  static void appendInsideRangeDesc(llvm::APSInt RMin, llvm::APSInt RMax,118                                    QualType ArgT, BasicValueFactory &BVF,119                                    llvm::raw_ostream &Out);120  /// Append textual description of a numeric range out of [RMin,RMax] to121  /// \p Out.122  static void appendOutOfRangeDesc(llvm::APSInt RMin, llvm::APSInt RMax,123                                   QualType ArgT, BasicValueFactory &BVF,124                                   llvm::raw_ostream &Out);125 126  class ValueConstraint;127 128  /// Pointer to the ValueConstraint. We need a copyable, polymorphic and129  /// default initializable type (vector needs that). A raw pointer was good,130  /// however, we cannot default initialize that. unique_ptr makes the Summary131  /// class non-copyable, therefore not an option. Releasing the copyability132  /// requirement would render the initialization of the Summary map infeasible.133  /// Mind that a pointer to a new value constraint is created when the negate134  /// function is used.135  using ValueConstraintPtr = std::shared_ptr<ValueConstraint>;136 137  /// Polymorphic base class that represents a constraint on a given argument138  /// (or return value) of a function. Derived classes implement different kind139  /// of constraints, e.g range constraints or correlation between two140  /// arguments.141  /// These are used as argument constraints (preconditions) of functions, in142  /// which case a bug report may be emitted if the constraint is not satisfied.143  /// Another use is as conditions for summary cases, to create different144  /// classes of behavior for a function. In this case no description of the145  /// constraint is needed because the summary cases have an own (not generated)146  /// description string.147  class ValueConstraint {148  public:149    ValueConstraint(ArgNo ArgN) : ArgN(ArgN) {}150    virtual ~ValueConstraint() {}151 152    /// Apply the effects of the constraint on the given program state. If null153    /// is returned then the constraint is not feasible.154    virtual ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,155                                  const Summary &Summary,156                                  CheckerContext &C) const = 0;157 158    /// Represents that in which context do we require a description of the159    /// constraint.160    enum DescriptionKind {161      /// Describe a constraint that was violated.162      /// Description should start with something like "should be".163      Violation,164      /// Describe a constraint that was assumed to be true.165      /// This can be used when a precondition is satisfied, or when a summary166      /// case is applied.167      /// Description should start with something like "is".168      Assumption169    };170 171    /// Give a description that explains the constraint to the user. Used when172    /// a bug is reported or when the constraint is applied and displayed as a173    /// note. The description should not mention the argument (getArgNo).174    /// See StdLibraryFunctionsChecker::reportBug about how this function is175    /// used (this function is used not only there).176    virtual void describe(DescriptionKind DK, const CallEvent &Call,177                          ProgramStateRef State, const Summary &Summary,178                          llvm::raw_ostream &Out) const {179      // There are some descendant classes that are not used as argument180      // constraints, e.g. ComparisonConstraint. In that case we can safely181      // ignore the implementation of this function.182      llvm_unreachable(183          "Description not implemented for summary case constraints");184    }185 186    /// Give a description that explains the actual argument value (where the187    /// current ValueConstraint applies to) to the user. This function should be188    /// called only when the current constraint is satisfied by the argument.189    /// It should produce a more precise description than the constraint itself.190    /// The actual value of the argument and the program state can be used to191    /// make the description more precise. In the most simple case, if the192    /// argument has a fixed known value this value can be printed into \p Out,193    /// this is done by default.194    /// The function should return true if a description was printed to \p Out,195    /// otherwise false.196    /// See StdLibraryFunctionsChecker::reportBug about how this function is197    /// used.198    virtual bool describeArgumentValue(const CallEvent &Call,199                                       ProgramStateRef State,200                                       const Summary &Summary,201                                       llvm::raw_ostream &Out) const {202      if (auto N = getArgSVal(Call, getArgNo()).getAs<NonLoc>()) {203        if (const llvm::APSInt *Int = N->getAsInteger()) {204          Out << *Int;205          return true;206        }207      }208      return false;209    }210 211    /// Return those arguments that should be tracked when we report a bug about212    /// argument constraint violation. By default it is the argument that is213    /// constrained, however, in some special cases we need to track other214    /// arguments as well. E.g. a buffer size might be encoded in another215    /// argument.216    /// The "return value" argument number can not occur as returned value.217    virtual std::vector<ArgNo> getArgsToTrack() const { return {ArgN}; }218 219    /// Get a constraint that represents exactly the opposite of the current.220    virtual ValueConstraintPtr negate() const {221      llvm_unreachable("Not implemented");222    };223 224    /// Check whether the constraint is malformed or not. It is malformed if the225    /// specified argument has a mismatch with the given FunctionDecl (e.g. the226    /// arg number is out-of-range of the function's argument list).227    /// This condition can indicate if a probably wrong or unexpected function228    /// was found where the constraint is to be applied.229    bool checkValidity(const FunctionDecl *FD) const {230      const bool ValidArg = ArgN == Ret || ArgN < FD->getNumParams();231      assert(ValidArg && "Arg out of range!");232      if (!ValidArg)233        return false;234      // Subclasses may further refine the validation.235      return checkSpecificValidity(FD);236    }237 238    /// Return the argument number (may be placeholder for "return value").239    ArgNo getArgNo() const { return ArgN; }240 241  protected:242    /// Argument to which to apply the constraint. It can be a real argument of243    /// the function to check, or a special value to indicate the return value244    /// of the function.245    /// Every constraint is assigned to one main argument, even if other246    /// arguments are involved.247    ArgNo ArgN;248 249    /// Do constraint-specific validation check.250    virtual bool checkSpecificValidity(const FunctionDecl *FD) const {251      return true;252    }253  };254 255  /// Check if a single argument falls into a specific "range".256  /// A range is formed as a set of intervals.257  /// E.g. \code {['A', 'Z'], ['a', 'z'], ['_', '_']} \endcode258  /// The intervals are closed intervals that contain one or more values.259  ///260  /// The default constructed RangeConstraint has an empty range, applying261  /// such constraint does not involve any assumptions, thus the State remains262  /// unchanged. This is meaningful, if the range is dependent on a looked up263  /// type (e.g. [0, Socklen_tMax]). If the type is not found, then the range264  /// is default initialized to be empty.265  class RangeConstraint : public ValueConstraint {266    /// The constraint can be specified by allowing or disallowing the range.267    /// WithinRange indicates allowing the range, OutOfRange indicates268    /// disallowing it (allowing the complementary range).269    RangeKind Kind;270 271    /// A set of intervals.272    IntRangeVector Ranges;273 274    /// A textual description of this constraint for the specific case where the275    /// constraint is used. If empty a generated description will be used that276    /// is built from the range of the constraint.277    StringRef Description;278 279  public:280    RangeConstraint(ArgNo ArgN, RangeKind Kind, const IntRangeVector &Ranges,281                    StringRef Desc = "")282        : ValueConstraint(ArgN), Kind(Kind), Ranges(Ranges), Description(Desc) {283    }284 285    const IntRangeVector &getRanges() const { return Ranges; }286 287    ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,288                          const Summary &Summary,289                          CheckerContext &C) const override;290 291    void describe(DescriptionKind DK, const CallEvent &Call,292                  ProgramStateRef State, const Summary &Summary,293                  llvm::raw_ostream &Out) const override;294 295    bool describeArgumentValue(const CallEvent &Call, ProgramStateRef State,296                               const Summary &Summary,297                               llvm::raw_ostream &Out) const override;298 299    ValueConstraintPtr negate() const override {300      RangeConstraint Tmp(*this);301      Tmp.Kind = negateKind(Kind);302      return std::make_shared<RangeConstraint>(Tmp);303    }304 305  protected:306    bool checkSpecificValidity(const FunctionDecl *FD) const override {307      const bool ValidArg =308          getArgType(FD, ArgN)->isIntegralType(FD->getASTContext());309      assert(ValidArg &&310             "This constraint should be applied on an integral type");311      return ValidArg;312    }313 314  private:315    /// A callback function that is used when iterating over the range316    /// intervals. It gets the begin and end (inclusive) of one interval.317    /// This is used to make any kind of task possible that needs an iteration318    /// over the intervals.319    using RangeApplyFunction =320        std::function<bool(const llvm::APSInt &Min, const llvm::APSInt &Max)>;321 322    /// Call a function on the intervals of the range.323    /// The function is called with all intervals in the range.324    void applyOnWithinRange(BasicValueFactory &BVF, QualType ArgT,325                            const RangeApplyFunction &F) const;326    /// Call a function on all intervals in the complementary range.327    /// The function is called with all intervals that fall out of the range.328    /// E.g. consider an interval list [A, B] and [C, D]329    /// \code330    /// -------+--------+------------------+------------+----------->331    ///        A        B                  C            D332    /// \endcode333    /// We get the ranges [-inf, A - 1], [D + 1, +inf], [B + 1, C - 1].334    /// The \p ArgT is used to determine the min and max of the type that is335    /// used as "-inf" and "+inf".336    void applyOnOutOfRange(BasicValueFactory &BVF, QualType ArgT,337                           const RangeApplyFunction &F) const;338    /// Call a function on the intervals of the range or the complementary339    /// range.340    void applyOnRange(RangeKind Kind, BasicValueFactory &BVF, QualType ArgT,341                      const RangeApplyFunction &F) const {342      switch (Kind) {343      case OutOfRange:344        applyOnOutOfRange(BVF, ArgT, F);345        break;346      case WithinRange:347        applyOnWithinRange(BVF, ArgT, F);348        break;349      };350    }351  };352 353  /// Check relation of an argument to another.354  class ComparisonConstraint : public ValueConstraint {355    BinaryOperator::Opcode Opcode;356    ArgNo OtherArgN;357 358  public:359    ComparisonConstraint(ArgNo ArgN, BinaryOperator::Opcode Opcode,360                         ArgNo OtherArgN)361        : ValueConstraint(ArgN), Opcode(Opcode), OtherArgN(OtherArgN) {}362    ArgNo getOtherArgNo() const { return OtherArgN; }363    BinaryOperator::Opcode getOpcode() const { return Opcode; }364    ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,365                          const Summary &Summary,366                          CheckerContext &C) const override;367  };368 369  /// Check null or non-null-ness of an argument that is of pointer type.370  class NullnessConstraint : public ValueConstraint {371    using ValueConstraint::ValueConstraint;372    // This variable has a role when we negate the constraint.373    bool CannotBeNull = true;374 375  public:376    NullnessConstraint(ArgNo ArgN, bool CannotBeNull = true)377        : ValueConstraint(ArgN), CannotBeNull(CannotBeNull) {}378 379    ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,380                          const Summary &Summary,381                          CheckerContext &C) const override;382 383    void describe(DescriptionKind DK, const CallEvent &Call,384                  ProgramStateRef State, const Summary &Summary,385                  llvm::raw_ostream &Out) const override;386 387    bool describeArgumentValue(const CallEvent &Call, ProgramStateRef State,388                               const Summary &Summary,389                               llvm::raw_ostream &Out) const override;390 391    ValueConstraintPtr negate() const override {392      NullnessConstraint Tmp(*this);393      Tmp.CannotBeNull = !this->CannotBeNull;394      return std::make_shared<NullnessConstraint>(Tmp);395    }396 397  protected:398    bool checkSpecificValidity(const FunctionDecl *FD) const override {399      const bool ValidArg = getArgType(FD, ArgN)->isPointerType();400      assert(ValidArg &&401             "This constraint should be applied only on a pointer type");402      return ValidArg;403    }404  };405 406  /// Check null or non-null-ness of an argument that is of pointer type.407  /// The argument is meant to be a buffer that has a size constraint, and it408  /// is allowed to have a NULL value if the size is 0. The size can depend on409  /// 1 or 2 additional arguments, if one of these is 0 the buffer is allowed to410  /// be NULL. Otherwise, the buffer pointer must be non-null. This is useful411  /// for functions like `fread` which have this special property.412  class BufferNullnessConstraint : public ValueConstraint {413    using ValueConstraint::ValueConstraint;414    ArgNo SizeArg1N;415    std::optional<ArgNo> SizeArg2N;416    // This variable has a role when we negate the constraint.417    bool CannotBeNull = true;418 419  public:420    BufferNullnessConstraint(ArgNo ArgN, ArgNo SizeArg1N,421                             std::optional<ArgNo> SizeArg2N,422                             bool CannotBeNull = true)423        : ValueConstraint(ArgN), SizeArg1N(SizeArg1N), SizeArg2N(SizeArg2N),424          CannotBeNull(CannotBeNull) {}425 426    ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,427                          const Summary &Summary,428                          CheckerContext &C) const override;429 430    void describe(DescriptionKind DK, const CallEvent &Call,431                  ProgramStateRef State, const Summary &Summary,432                  llvm::raw_ostream &Out) const override;433 434    bool describeArgumentValue(const CallEvent &Call, ProgramStateRef State,435                               const Summary &Summary,436                               llvm::raw_ostream &Out) const override;437 438    ValueConstraintPtr negate() const override {439      BufferNullnessConstraint Tmp(*this);440      Tmp.CannotBeNull = !this->CannotBeNull;441      return std::make_shared<BufferNullnessConstraint>(Tmp);442    }443 444  protected:445    bool checkSpecificValidity(const FunctionDecl *FD) const override {446      const bool ValidArg = getArgType(FD, ArgN)->isPointerType();447      assert(ValidArg &&448             "This constraint should be applied only on a pointer type");449      return ValidArg;450    }451  };452 453  // Represents a buffer argument with an additional size constraint. The454  // constraint may be a concrete value, or a symbolic value in an argument.455  // Example 1. Concrete value as the minimum buffer size.456  //   char *asctime_r(const struct tm *restrict tm, char *restrict buf);457  //   // `buf` size must be at least 26 bytes according the POSIX standard.458  // Example 2. Argument as a buffer size.459  //   ctime_s(char *buffer, rsize_t bufsz, const time_t *time);460  // Example 3. The size is computed as a multiplication of other args.461  //   size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);462  //   // Here, ptr is the buffer, and its minimum size is `size * nmemb`.463  class BufferSizeConstraint : public ValueConstraint {464    // The concrete value which is the minimum size for the buffer.465    std::optional<llvm::APSInt> ConcreteSize;466    // The argument which holds the size of the buffer.467    std::optional<ArgNo> SizeArgN;468    // The argument which is a multiplier to size. This is set in case of469    // `fread` like functions where the size is computed as a multiplication of470    // two arguments.471    std::optional<ArgNo> SizeMultiplierArgN;472    // The operator we use in apply. This is negated in negate().473    BinaryOperator::Opcode Op = BO_LE;474 475  public:476    BufferSizeConstraint(ArgNo Buffer, llvm::APSInt BufMinSize)477        : ValueConstraint(Buffer), ConcreteSize(BufMinSize) {}478    BufferSizeConstraint(ArgNo Buffer, ArgNo BufSize)479        : ValueConstraint(Buffer), SizeArgN(BufSize) {}480    BufferSizeConstraint(ArgNo Buffer, ArgNo BufSize, ArgNo BufSizeMultiplier)481        : ValueConstraint(Buffer), SizeArgN(BufSize),482          SizeMultiplierArgN(BufSizeMultiplier) {}483 484    ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,485                          const Summary &Summary,486                          CheckerContext &C) const override;487 488    void describe(DescriptionKind DK, const CallEvent &Call,489                  ProgramStateRef State, const Summary &Summary,490                  llvm::raw_ostream &Out) const override;491 492    bool describeArgumentValue(const CallEvent &Call, ProgramStateRef State,493                               const Summary &Summary,494                               llvm::raw_ostream &Out) const override;495 496    std::vector<ArgNo> getArgsToTrack() const override {497      std::vector<ArgNo> Result{ArgN};498      if (SizeArgN)499        Result.push_back(*SizeArgN);500      if (SizeMultiplierArgN)501        Result.push_back(*SizeMultiplierArgN);502      return Result;503    }504 505    ValueConstraintPtr negate() const override {506      BufferSizeConstraint Tmp(*this);507      Tmp.Op = BinaryOperator::negateComparisonOp(Op);508      return std::make_shared<BufferSizeConstraint>(Tmp);509    }510 511  protected:512    bool checkSpecificValidity(const FunctionDecl *FD) const override {513      const bool ValidArg = getArgType(FD, ArgN)->isPointerType();514      assert(ValidArg &&515             "This constraint should be applied only on a pointer type");516      return ValidArg;517    }518  };519 520  /// The complete list of constraints that defines a single branch.521  using ConstraintSet = std::vector<ValueConstraintPtr>;522 523  /// Define how a function affects the system variable 'errno'.524  /// This works together with the \c ErrnoModeling and \c ErrnoChecker classes.525  /// Currently 3 use cases exist: success, failure, irrelevant.526  /// In the future the failure case can be customized to set \c errno to a527  /// more specific constraint (for example > 0), or new case can be added528  /// for functions which require check of \c errno in both success and failure529  /// case.530  class ErrnoConstraintBase {531  public:532    /// Apply specific state changes related to the errno variable.533    virtual ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,534                                  const Summary &Summary,535                                  CheckerContext &C) const = 0;536    /// Get a description about what happens with 'errno' here and how it causes537    /// a later bug report created by ErrnoChecker.538    /// Empty return value means that 'errno' related bug may not happen from539    /// the current analyzed function.540    virtual std::string describe(CheckerContext &C) const { return ""; }541 542    virtual ~ErrnoConstraintBase() {}543 544  protected:545    ErrnoConstraintBase() = default;546 547    /// This is used for conjure symbol for errno to differentiate from the548    /// original call expression (same expression is used for the errno symbol).549    static int Tag;550  };551 552  /// Reset errno constraints to irrelevant.553  /// This is applicable to functions that may change 'errno' and are not554  /// modeled elsewhere.555  class ResetErrnoConstraint : public ErrnoConstraintBase {556  public:557    ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,558                          const Summary &Summary,559                          CheckerContext &C) const override {560      return errno_modeling::setErrnoState(State, errno_modeling::Irrelevant);561    }562  };563 564  /// Do not change errno constraints.565  /// This is applicable to functions that are modeled in another checker566  /// and the already set errno constraints should not be changed in the567  /// post-call event.568  class NoErrnoConstraint : public ErrnoConstraintBase {569  public:570    ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,571                          const Summary &Summary,572                          CheckerContext &C) const override {573      return State;574    }575  };576 577  /// Set errno constraint at failure cases of standard functions.578  /// Failure case: 'errno' becomes not equal to 0 and may or may not be checked579  /// by the program. \c ErrnoChecker does not emit a bug report after such a580  /// function call.581  class FailureErrnoConstraint : public ErrnoConstraintBase {582  public:583    ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,584                          const Summary &Summary,585                          CheckerContext &C) const override {586      SValBuilder &SVB = C.getSValBuilder();587      NonLoc ErrnoSVal = SVB.conjureSymbolVal(Call, C.getASTContext().IntTy,588                                              C.blockCount(), &Tag)589                             .castAs<NonLoc>();590      return errno_modeling::setErrnoForStdFailure(State, C, ErrnoSVal);591    }592  };593 594  /// Set errno constraint at success cases of standard functions.595  /// Success case: 'errno' is not allowed to be used because the value is596  /// undefined after successful call.597  /// \c ErrnoChecker can emit bug report after such a function call if errno598  /// is used.599  class SuccessErrnoConstraint : public ErrnoConstraintBase {600  public:601    ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,602                          const Summary &Summary,603                          CheckerContext &C) const override {604      return errno_modeling::setErrnoForStdSuccess(State, C);605    }606 607    std::string describe(CheckerContext &C) const override {608      return "'errno' becomes undefined after the call";609    }610  };611 612  /// Set errno constraint at functions that indicate failure only with 'errno'.613  /// In this case 'errno' is required to be observed.614  /// \c ErrnoChecker can emit bug report after such a function call if errno615  /// is overwritten without a read before.616  class ErrnoMustBeCheckedConstraint : public ErrnoConstraintBase {617  public:618    ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,619                          const Summary &Summary,620                          CheckerContext &C) const override {621      return errno_modeling::setErrnoStdMustBeChecked(State, C,622                                                      Call.getCFGElementRef());623    }624 625    std::string describe(CheckerContext &C) const override {626      return "reading 'errno' is required to find out if the call has failed";627    }628  };629 630  /// A single branch of a function summary.631  ///632  /// A branch is defined by a series of constraints - "assumptions" -633  /// that together form a single possible outcome of invoking the function.634  /// When static analyzer considers a branch, it tries to introduce635  /// a child node in the Exploded Graph. The child node has to include636  /// constraints that define the branch. If the constraints contradict637  /// existing constraints in the state, the node is not created and the branch638  /// is dropped; otherwise it's queued for future exploration.639  /// The branch is accompanied by a note text that may be displayed640  /// to the user when a bug is found on a path that takes this branch.641  ///642  /// For example, consider the branches in `isalpha(x)`:643  ///   Branch 1)644  ///     x is in range ['A', 'Z'] or in ['a', 'z']645  ///     then the return value is not 0. (I.e. out-of-range [0, 0])646  ///     and the note may say "Assuming the character is alphabetical"647  ///   Branch 2)648  ///     x is out-of-range ['A', 'Z'] and out-of-range ['a', 'z']649  ///     then the return value is 0650  ///     and the note may say "Assuming the character is non-alphabetical".651  class SummaryCase {652    ConstraintSet Constraints;653    const ErrnoConstraintBase &ErrnoConstraint;654    StringRef Note;655 656  public:657    SummaryCase(ConstraintSet &&Constraints, const ErrnoConstraintBase &ErrnoC,658                StringRef Note)659        : Constraints(std::move(Constraints)), ErrnoConstraint(ErrnoC),660          Note(Note) {}661 662    SummaryCase(const ConstraintSet &Constraints,663                const ErrnoConstraintBase &ErrnoC, StringRef Note)664        : Constraints(Constraints), ErrnoConstraint(ErrnoC), Note(Note) {}665 666    const ConstraintSet &getConstraints() const { return Constraints; }667    const ErrnoConstraintBase &getErrnoConstraint() const {668      return ErrnoConstraint;669    }670    StringRef getNote() const { return Note; }671  };672 673  using ArgTypes = ArrayRef<std::optional<QualType>>;674  using RetType = std::optional<QualType>;675 676  // A placeholder type, we use it whenever we do not care about the concrete677  // type in a Signature.678  const QualType Irrelevant{};679  bool static isIrrelevant(QualType T) { return T.isNull(); }680 681  // The signature of a function we want to describe with a summary. This is a682  // concessive signature, meaning there may be irrelevant types in the683  // signature which we do not check against a function with concrete types.684  // All types in the spec need to be canonical.685  class Signature {686    using ArgQualTypes = std::vector<QualType>;687    ArgQualTypes ArgTys;688    QualType RetTy;689    // True if any component type is not found by lookup.690    bool Invalid = false;691 692  public:693    // Construct a signature from optional types. If any of the optional types694    // are not set then the signature will be invalid.695    Signature(ArgTypes ArgTys, RetType RetTy) {696      for (std::optional<QualType> Arg : ArgTys) {697        if (!Arg) {698          Invalid = true;699          return;700        } else {701          assertArgTypeSuitableForSignature(*Arg);702          this->ArgTys.push_back(*Arg);703        }704      }705      if (!RetTy) {706        Invalid = true;707        return;708      } else {709        assertRetTypeSuitableForSignature(*RetTy);710        this->RetTy = *RetTy;711      }712    }713 714    bool isInvalid() const { return Invalid; }715    bool matches(const FunctionDecl *FD) const;716 717  private:718    static void assertArgTypeSuitableForSignature(QualType T) {719      assert((T.isNull() || !T->isVoidType()) &&720             "We should have no void types in the spec");721      assert((T.isNull() || T.isCanonical()) &&722             "We should only have canonical types in the spec");723    }724    static void assertRetTypeSuitableForSignature(QualType T) {725      assert((T.isNull() || T.isCanonical()) &&726             "We should only have canonical types in the spec");727    }728  };729 730  static QualType getArgType(const FunctionDecl *FD, ArgNo ArgN) {731    assert(FD && "Function must be set");732    QualType T = (ArgN == Ret)733                     ? FD->getReturnType().getCanonicalType()734                     : FD->getParamDecl(ArgN)->getType().getCanonicalType();735    return T;736  }737 738  using SummaryCases = std::vector<SummaryCase>;739 740  /// A summary includes information about741  ///   * function prototype (signature)742  ///   * approach to invalidation,743  ///   * a list of branches - so, a list of list of ranges,744  ///   * a list of argument constraints, that must be true on every branch.745  ///     If these constraints are not satisfied that means a fatal error746  ///     usually resulting in undefined behaviour.747  ///748  /// Application of a summary:749  ///   The signature and argument constraints together contain information750  ///   about which functions are handled by the summary. The signature can use751  ///   "wildcards", i.e. Irrelevant types. Irrelevant type of a parameter in752  ///   a signature means that type is not compared to the type of the parameter753  ///   in the found FunctionDecl. Argument constraints may specify additional754  ///   rules for the given parameter's type, those rules are checked once the755  ///   signature is matched.756  class Summary {757    const InvalidationKind InvalidationKd;758    SummaryCases Cases;759    ConstraintSet ArgConstraints;760 761    // The function to which the summary applies. This is set after lookup and762    // match to the signature.763    const FunctionDecl *FD = nullptr;764 765  public:766    Summary(InvalidationKind InvalidationKd) : InvalidationKd(InvalidationKd) {}767 768    Summary &Case(ConstraintSet &&CS, const ErrnoConstraintBase &ErrnoC,769                  StringRef Note = "") {770      Cases.push_back(SummaryCase(std::move(CS), ErrnoC, Note));771      return *this;772    }773    Summary &Case(const ConstraintSet &CS, const ErrnoConstraintBase &ErrnoC,774                  StringRef Note = "") {775      Cases.push_back(SummaryCase(CS, ErrnoC, Note));776      return *this;777    }778    Summary &ArgConstraint(ValueConstraintPtr VC) {779      assert(VC->getArgNo() != Ret &&780             "Arg constraint should not refer to the return value");781      ArgConstraints.push_back(VC);782      return *this;783    }784 785    InvalidationKind getInvalidationKd() const { return InvalidationKd; }786    const SummaryCases &getCases() const { return Cases; }787    const ConstraintSet &getArgConstraints() const { return ArgConstraints; }788 789    QualType getArgType(ArgNo ArgN) const {790      return StdLibraryFunctionsChecker::getArgType(FD, ArgN);791    }792 793    // Returns true if the summary should be applied to the given function.794    // And if yes then store the function declaration.795    bool matchesAndSet(const Signature &Sign, const FunctionDecl *FD) {796      bool Result = Sign.matches(FD) && validateByConstraints(FD);797      if (Result) {798        assert(!this->FD && "FD must not be set more than once");799        this->FD = FD;800      }801      return Result;802    }803 804  private:805    // Once we know the exact type of the function then do validation check on806    // all the given constraints.807    bool validateByConstraints(const FunctionDecl *FD) const {808      for (const SummaryCase &Case : Cases)809        for (const ValueConstraintPtr &Constraint : Case.getConstraints())810          if (!Constraint->checkValidity(FD))811            return false;812      for (const ValueConstraintPtr &Constraint : ArgConstraints)813        if (!Constraint->checkValidity(FD))814          return false;815      return true;816    }817  };818 819  // The map of all functions supported by the checker. It is initialized820  // lazily, and it doesn't change after initialization.821  using FunctionSummaryMapType = llvm::DenseMap<const FunctionDecl *, Summary>;822  mutable FunctionSummaryMapType FunctionSummaryMap;823 824  const BugType BT_InvalidArg{this, "Function call with invalid argument"};825  mutable bool SummariesInitialized = false;826 827  static SVal getArgSVal(const CallEvent &Call, ArgNo ArgN) {828    return ArgN == Ret ? Call.getReturnValue() : Call.getArgSVal(ArgN);829  }830  static std::string getFunctionName(const CallEvent &Call) {831    assert(Call.getDecl() &&832           "Call was found by a summary, should have declaration");833    return cast<NamedDecl>(Call.getDecl())->getNameAsString();834  }835 836public:837  void checkPreCall(const CallEvent &Call, CheckerContext &C) const;838  void checkPostCall(const CallEvent &Call, CheckerContext &C) const;839  bool evalCall(const CallEvent &Call, CheckerContext &C) const;840 841  CheckerNameRef CheckName;842  bool AddTestFunctions = false;843 844  bool DisplayLoadedSummaries = false;845  bool ModelPOSIX = false;846  bool ShouldAssumeControlledEnvironment = false;847 848private:849  std::optional<Summary> findFunctionSummary(const FunctionDecl *FD,850                                             CheckerContext &C) const;851  std::optional<Summary> findFunctionSummary(const CallEvent &Call,852                                             CheckerContext &C) const;853 854  void initFunctionSummaries(CheckerContext &C) const;855 856  void reportBug(const CallEvent &Call, ExplodedNode *N,857                 const ValueConstraint *VC, const ValueConstraint *NegatedVC,858                 const Summary &Summary, CheckerContext &C) const {859    assert(Call.getDecl() &&860           "Function found in summary must have a declaration available");861    SmallString<256> Msg;862    llvm::raw_svector_ostream MsgOs(Msg);863 864    MsgOs << "The ";865    printArgDesc(VC->getArgNo(), MsgOs);866    MsgOs << " to '" << getFunctionName(Call) << "' ";867    bool ValuesPrinted =868        NegatedVC->describeArgumentValue(Call, N->getState(), Summary, MsgOs);869    if (ValuesPrinted)870      MsgOs << " but ";871    else872      MsgOs << "is out of the accepted range; It ";873    VC->describe(ValueConstraint::Violation, Call, C.getState(), Summary,874                 MsgOs);875    Msg[0] = toupper(Msg[0]);876    auto R = std::make_unique<PathSensitiveBugReport>(BT_InvalidArg, Msg, N);877 878    for (ArgNo ArgN : VC->getArgsToTrack()) {879      bugreporter::trackExpressionValue(N, Call.getArgExpr(ArgN), *R);880      R->markInteresting(Call.getArgSVal(ArgN));881      // All tracked arguments are important, highlight them.882      R->addRange(Call.getArgSourceRange(ArgN));883    }884 885    C.emitReport(std::move(R));886  }887 888  /// These are the errno constraints that can be passed to summary cases.889  /// One of these should fit for a single summary case.890  /// Usually if a failure return value exists for function, that function891  /// needs different cases for success and failure with different errno892  /// constraints (and different return value constraints).893  const NoErrnoConstraint ErrnoUnchanged{};894  const ResetErrnoConstraint ErrnoIrrelevant{};895  const ErrnoMustBeCheckedConstraint ErrnoMustBeChecked{};896  const SuccessErrnoConstraint ErrnoMustNotBeChecked{};897  const FailureErrnoConstraint ErrnoNEZeroIrrelevant{};898};899 900int StdLibraryFunctionsChecker::ErrnoConstraintBase::Tag = 0;901 902const StdLibraryFunctionsChecker::ArgNo StdLibraryFunctionsChecker::Ret =903    std::numeric_limits<ArgNo>::max();904 905static BasicValueFactory &getBVF(ProgramStateRef State) {906  ProgramStateManager &Mgr = State->getStateManager();907  SValBuilder &SVB = Mgr.getSValBuilder();908  return SVB.getBasicValueFactory();909}910 911} // end of anonymous namespace912 913void StdLibraryFunctionsChecker::printArgDesc(914    StdLibraryFunctionsChecker::ArgNo ArgN, llvm::raw_ostream &Out) {915  Out << std::to_string(ArgN + 1);916  Out << llvm::getOrdinalSuffix(ArgN + 1);917  Out << " argument";918}919 920void StdLibraryFunctionsChecker::printArgValueInfo(ArgNo ArgN,921                                                   ProgramStateRef State,922                                                   const CallEvent &Call,923                                                   llvm::raw_ostream &Out) {924  if (const llvm::APSInt *Val =925          State->getStateManager().getSValBuilder().getKnownValue(926              State, getArgSVal(Call, ArgN)))927    Out << " (which is " << *Val << ")";928}929 930void StdLibraryFunctionsChecker::appendInsideRangeDesc(llvm::APSInt RMin,931                                                       llvm::APSInt RMax,932                                                       QualType ArgT,933                                                       BasicValueFactory &BVF,934                                                       llvm::raw_ostream &Out) {935  if (RMin.isZero() && RMax.isZero())936    Out << "zero";937  else if (RMin == RMax)938    Out << RMin;939  else if (RMin == BVF.getMinValue(ArgT)) {940    if (RMax == -1)941      Out << "< 0";942    else943      Out << "<= " << RMax;944  } else if (RMax == BVF.getMaxValue(ArgT)) {945    if (RMin.isOne())946      Out << "> 0";947    else948      Out << ">= " << RMin;949  } else if (RMin.isNegative() == RMax.isNegative() &&950             RMin.getLimitedValue() == RMax.getLimitedValue() - 1) {951    Out << RMin << " or " << RMax;952  } else {953    Out << "between " << RMin << " and " << RMax;954  }955}956 957void StdLibraryFunctionsChecker::appendOutOfRangeDesc(llvm::APSInt RMin,958                                                      llvm::APSInt RMax,959                                                      QualType ArgT,960                                                      BasicValueFactory &BVF,961                                                      llvm::raw_ostream &Out) {962  if (RMin.isZero() && RMax.isZero())963    Out << "nonzero";964  else if (RMin == RMax) {965    Out << "not equal to " << RMin;966  } else if (RMin == BVF.getMinValue(ArgT)) {967    if (RMax == -1)968      Out << ">= 0";969    else970      Out << "> " << RMax;971  } else if (RMax == BVF.getMaxValue(ArgT)) {972    if (RMin.isOne())973      Out << "<= 0";974    else975      Out << "< " << RMin;976  } else if (RMin.isNegative() == RMax.isNegative() &&977             RMin.getLimitedValue() == RMax.getLimitedValue() - 1) {978    Out << "not " << RMin << " and not " << RMax;979  } else {980    Out << "not between " << RMin << " and " << RMax;981  }982}983 984void StdLibraryFunctionsChecker::RangeConstraint::applyOnWithinRange(985    BasicValueFactory &BVF, QualType ArgT, const RangeApplyFunction &F) const {986  if (Ranges.empty())987    return;988 989  for (auto [Start, End] : getRanges()) {990    const llvm::APSInt &Min = BVF.getValue(Start, ArgT);991    const llvm::APSInt &Max = BVF.getValue(End, ArgT);992    assert(Min <= Max);993    if (!F(Min, Max))994      return;995  }996}997 998void StdLibraryFunctionsChecker::RangeConstraint::applyOnOutOfRange(999    BasicValueFactory &BVF, QualType ArgT, const RangeApplyFunction &F) const {1000  if (Ranges.empty())1001    return;1002 1003  const IntRangeVector &R = getRanges();1004  size_t E = R.size();1005 1006  const llvm::APSInt &MinusInf = BVF.getMinValue(ArgT);1007  const llvm::APSInt &PlusInf = BVF.getMaxValue(ArgT);1008 1009  const llvm::APSInt &RangeLeft = BVF.getValue(R[0].first - 1ULL, ArgT);1010  const llvm::APSInt &RangeRight = BVF.getValue(R[E - 1].second + 1ULL, ArgT);1011 1012  // Iterate over the "holes" between intervals.1013  for (size_t I = 1; I != E; ++I) {1014    const llvm::APSInt &Min = BVF.getValue(R[I - 1].second + 1ULL, ArgT);1015    const llvm::APSInt &Max = BVF.getValue(R[I].first - 1ULL, ArgT);1016    if (Min <= Max) {1017      if (!F(Min, Max))1018        return;1019    }1020  }1021  // Check the interval [T_MIN, min(R) - 1].1022  if (RangeLeft != PlusInf) {1023    assert(MinusInf <= RangeLeft);1024    if (!F(MinusInf, RangeLeft))1025      return;1026  }1027  // Check the interval [max(R) + 1, T_MAX],1028  if (RangeRight != MinusInf) {1029    assert(RangeRight <= PlusInf);1030    if (!F(RangeRight, PlusInf))1031      return;1032  }1033}1034 1035ProgramStateRef StdLibraryFunctionsChecker::RangeConstraint::apply(1036    ProgramStateRef State, const CallEvent &Call, const Summary &Summary,1037    CheckerContext &C) const {1038  ConstraintManager &CM = C.getConstraintManager();1039  SVal V = getArgSVal(Call, getArgNo());1040  QualType T = Summary.getArgType(getArgNo());1041 1042  if (auto N = V.getAs<NonLoc>()) {1043    auto ExcludeRangeFromArg = [&](const llvm::APSInt &Min,1044                                   const llvm::APSInt &Max) {1045      State = CM.assumeInclusiveRange(State, *N, Min, Max, false);1046      return static_cast<bool>(State);1047    };1048    // "OutOfRange R" is handled by excluding all ranges in R.1049    // "WithinRange R" is treated as "OutOfRange [T_MIN, T_MAX] \ R".1050    applyOnRange(negateKind(Kind), C.getSValBuilder().getBasicValueFactory(), T,1051                 ExcludeRangeFromArg);1052  }1053 1054  return State;1055}1056 1057void StdLibraryFunctionsChecker::RangeConstraint::describe(1058    DescriptionKind DK, const CallEvent &Call, ProgramStateRef State,1059    const Summary &Summary, llvm::raw_ostream &Out) const {1060 1061  BasicValueFactory &BVF = getBVF(State);1062  QualType T = Summary.getArgType(getArgNo());1063 1064  Out << ((DK == Violation) ? "should be " : "is ");1065  if (!Description.empty()) {1066    Out << Description;1067  } else {1068    unsigned I = Ranges.size();1069    if (Kind == WithinRange) {1070      for (const std::pair<RangeInt, RangeInt> &R : Ranges) {1071        appendInsideRangeDesc(BVF.getValue(R.first, T),1072                              BVF.getValue(R.second, T), T, BVF, Out);1073        if (--I > 0)1074          Out << " or ";1075      }1076    } else {1077      for (const std::pair<RangeInt, RangeInt> &R : Ranges) {1078        appendOutOfRangeDesc(BVF.getValue(R.first, T),1079                             BVF.getValue(R.second, T), T, BVF, Out);1080        if (--I > 0)1081          Out << " and ";1082      }1083    }1084  }1085}1086 1087bool StdLibraryFunctionsChecker::RangeConstraint::describeArgumentValue(1088    const CallEvent &Call, ProgramStateRef State, const Summary &Summary,1089    llvm::raw_ostream &Out) const {1090  unsigned int NRanges = 0;1091  bool HaveAllRanges = true;1092 1093  ProgramStateManager &Mgr = State->getStateManager();1094  BasicValueFactory &BVF = Mgr.getSValBuilder().getBasicValueFactory();1095  ConstraintManager &CM = Mgr.getConstraintManager();1096  SVal V = getArgSVal(Call, getArgNo());1097 1098  if (auto N = V.getAs<NonLoc>()) {1099    if (const llvm::APSInt *Int = N->getAsInteger()) {1100      Out << "is ";1101      Out << *Int;1102      return true;1103    }1104    QualType T = Summary.getArgType(getArgNo());1105    SmallString<128> MoreInfo;1106    llvm::raw_svector_ostream MoreInfoOs(MoreInfo);1107    auto ApplyF = [&](const llvm::APSInt &Min, const llvm::APSInt &Max) {1108      if (CM.assumeInclusiveRange(State, *N, Min, Max, true)) {1109        if (NRanges > 0)1110          MoreInfoOs << " or ";1111        appendInsideRangeDesc(Min, Max, T, BVF, MoreInfoOs);1112        ++NRanges;1113      } else {1114        HaveAllRanges = false;1115      }1116      return true;1117    };1118 1119    applyOnRange(Kind, BVF, T, ApplyF);1120    assert(NRanges > 0);1121    if (!HaveAllRanges || NRanges == 1) {1122      Out << "is ";1123      Out << MoreInfo;1124      return true;1125    }1126  }1127  return false;1128}1129 1130ProgramStateRef StdLibraryFunctionsChecker::ComparisonConstraint::apply(1131    ProgramStateRef State, const CallEvent &Call, const Summary &Summary,1132    CheckerContext &C) const {1133 1134  ProgramStateManager &Mgr = State->getStateManager();1135  SValBuilder &SVB = Mgr.getSValBuilder();1136  QualType CondT = SVB.getConditionType();1137  QualType T = Summary.getArgType(getArgNo());1138  SVal V = getArgSVal(Call, getArgNo());1139 1140  BinaryOperator::Opcode Op = getOpcode();1141  ArgNo OtherArg = getOtherArgNo();1142  SVal OtherV = getArgSVal(Call, OtherArg);1143  QualType OtherT = Summary.getArgType(OtherArg);1144  // Note: we avoid integral promotion for comparison.1145  OtherV = SVB.evalCast(OtherV, T, OtherT);1146  if (auto CompV = SVB.evalBinOp(State, Op, V, OtherV, CondT)1147                       .getAs<DefinedOrUnknownSVal>())1148    State = State->assume(*CompV, true);1149  return State;1150}1151 1152ProgramStateRef StdLibraryFunctionsChecker::NullnessConstraint::apply(1153    ProgramStateRef State, const CallEvent &Call, const Summary &Summary,1154    CheckerContext &C) const {1155  SVal V = getArgSVal(Call, getArgNo());1156  if (V.isUndef())1157    return State;1158 1159  DefinedOrUnknownSVal L = V.castAs<DefinedOrUnknownSVal>();1160  if (!isa<Loc>(L))1161    return State;1162 1163  return State->assume(L, CannotBeNull);1164}1165 1166void StdLibraryFunctionsChecker::NullnessConstraint::describe(1167    DescriptionKind DK, const CallEvent &Call, ProgramStateRef State,1168    const Summary &Summary, llvm::raw_ostream &Out) const {1169  assert(CannotBeNull &&1170         "'describe' is not implemented when the value must be NULL");1171  if (DK == Violation)1172    Out << "should not be NULL";1173  else1174    Out << "is not NULL";1175}1176 1177bool StdLibraryFunctionsChecker::NullnessConstraint::describeArgumentValue(1178    const CallEvent &Call, ProgramStateRef State, const Summary &Summary,1179    llvm::raw_ostream &Out) const {1180  assert(!CannotBeNull && "'describeArgumentValue' is not implemented when the "1181                          "value must be non-NULL");1182  Out << "is NULL";1183  return true;1184}1185 1186ProgramStateRef StdLibraryFunctionsChecker::BufferNullnessConstraint::apply(1187    ProgramStateRef State, const CallEvent &Call, const Summary &Summary,1188    CheckerContext &C) const {1189  SVal V = getArgSVal(Call, getArgNo());1190  if (V.isUndef())1191    return State;1192  DefinedOrUnknownSVal L = V.castAs<DefinedOrUnknownSVal>();1193  if (!isa<Loc>(L))1194    return State;1195 1196  std::optional<DefinedOrUnknownSVal> SizeArg1 =1197      getArgSVal(Call, SizeArg1N).getAs<DefinedOrUnknownSVal>();1198  std::optional<DefinedOrUnknownSVal> SizeArg2;1199  if (SizeArg2N)1200    SizeArg2 = getArgSVal(Call, *SizeArg2N).getAs<DefinedOrUnknownSVal>();1201 1202  auto IsArgZero = [State](std::optional<DefinedOrUnknownSVal> Val) {1203    if (!Val)1204      return false;1205    auto [IsNonNull, IsNull] = State->assume(*Val);1206    return IsNull && !IsNonNull;1207  };1208 1209  if (IsArgZero(SizeArg1) || IsArgZero(SizeArg2))1210    return State;1211 1212  return State->assume(L, CannotBeNull);1213}1214 1215void StdLibraryFunctionsChecker::BufferNullnessConstraint::describe(1216    DescriptionKind DK, const CallEvent &Call, ProgramStateRef State,1217    const Summary &Summary, llvm::raw_ostream &Out) const {1218  assert(CannotBeNull &&1219         "'describe' is not implemented when the buffer must be NULL");1220  if (DK == Violation)1221    Out << "should not be NULL";1222  else1223    Out << "is not NULL";1224}1225 1226bool StdLibraryFunctionsChecker::BufferNullnessConstraint::1227    describeArgumentValue(const CallEvent &Call, ProgramStateRef State,1228                          const Summary &Summary,1229                          llvm::raw_ostream &Out) const {1230  assert(!CannotBeNull && "'describeArgumentValue' is not implemented when the "1231                          "buffer must be non-NULL");1232  Out << "is NULL";1233  return true;1234}1235 1236ProgramStateRef StdLibraryFunctionsChecker::BufferSizeConstraint::apply(1237    ProgramStateRef State, const CallEvent &Call, const Summary &Summary,1238    CheckerContext &C) const {1239  SValBuilder &SvalBuilder = C.getSValBuilder();1240  // The buffer argument.1241  SVal BufV = getArgSVal(Call, getArgNo());1242 1243  // Get the size constraint.1244  const SVal SizeV = [this, &State, &Call, &Summary, &SvalBuilder]() {1245    if (ConcreteSize) {1246      return SVal(SvalBuilder.makeIntVal(*ConcreteSize));1247    }1248    assert(SizeArgN && "The constraint must be either a concrete value or "1249                       "encoded in an argument.");1250    // The size argument.1251    SVal SizeV = getArgSVal(Call, *SizeArgN);1252    // Multiply with another argument if given.1253    if (SizeMultiplierArgN) {1254      SVal SizeMulV = getArgSVal(Call, *SizeMultiplierArgN);1255      SizeV = SvalBuilder.evalBinOp(State, BO_Mul, SizeV, SizeMulV,1256                                    Summary.getArgType(*SizeArgN));1257    }1258    return SizeV;1259  }();1260 1261  // The dynamic size of the buffer argument, got from the analyzer engine.1262  SVal BufDynSize = getDynamicExtentWithOffset(State, BufV);1263 1264  SVal Feasible = SvalBuilder.evalBinOp(State, Op, SizeV, BufDynSize,1265                                        SvalBuilder.getContext().BoolTy);1266  if (auto F = Feasible.getAs<DefinedOrUnknownSVal>())1267    return State->assume(*F, true);1268 1269  // We can get here only if the size argument or the dynamic size is1270  // undefined. But the dynamic size should never be undefined, only1271  // unknown. So, here, the size of the argument is undefined, i.e. we1272  // cannot apply the constraint. Actually, other checkers like1273  // CallAndMessage should catch this situation earlier, because we call a1274  // function with an uninitialized argument.1275  llvm_unreachable("Size argument or the dynamic size is Undefined");1276}1277 1278void StdLibraryFunctionsChecker::BufferSizeConstraint::describe(1279    DescriptionKind DK, const CallEvent &Call, ProgramStateRef State,1280    const Summary &Summary, llvm::raw_ostream &Out) const {1281  Out << ((DK == Violation) ? "should be " : "is ");1282  Out << "a buffer with size equal to or greater than ";1283  if (ConcreteSize) {1284    Out << *ConcreteSize;1285  } else if (SizeArgN) {1286    Out << "the value of the ";1287    printArgDesc(*SizeArgN, Out);1288    printArgValueInfo(*SizeArgN, State, Call, Out);1289    if (SizeMultiplierArgN) {1290      Out << " times the ";1291      printArgDesc(*SizeMultiplierArgN, Out);1292      printArgValueInfo(*SizeMultiplierArgN, State, Call, Out);1293    }1294  }1295}1296 1297bool StdLibraryFunctionsChecker::BufferSizeConstraint::describeArgumentValue(1298    const CallEvent &Call, ProgramStateRef State, const Summary &Summary,1299    llvm::raw_ostream &Out) const {1300  SVal BufV = getArgSVal(Call, getArgNo());1301  SVal BufDynSize = getDynamicExtentWithOffset(State, BufV);1302  if (const llvm::APSInt *Val =1303          State->getStateManager().getSValBuilder().getKnownValue(State,1304                                                                  BufDynSize)) {1305    Out << "is a buffer with size " << *Val;1306    return true;1307  }1308  return false;1309}1310 1311void StdLibraryFunctionsChecker::checkPreCall(const CallEvent &Call,1312                                              CheckerContext &C) const {1313  std::optional<Summary> FoundSummary = findFunctionSummary(Call, C);1314  if (!FoundSummary)1315    return;1316 1317  const Summary &Summary = *FoundSummary;1318  ProgramStateRef State = C.getState();1319 1320  ProgramStateRef NewState = State;1321  ExplodedNode *NewNode = C.getPredecessor();1322  for (const ValueConstraintPtr &Constraint : Summary.getArgConstraints()) {1323    ValueConstraintPtr NegatedConstraint = Constraint->negate();1324    ProgramStateRef SuccessSt = Constraint->apply(NewState, Call, Summary, C);1325    ProgramStateRef FailureSt =1326        NegatedConstraint->apply(NewState, Call, Summary, C);1327    // The argument constraint is not satisfied.1328    if (FailureSt && !SuccessSt) {1329      if (ExplodedNode *N = C.generateErrorNode(State, NewNode))1330        reportBug(Call, N, Constraint.get(), NegatedConstraint.get(), Summary,1331                  C);1332      break;1333    }1334    // We will apply the constraint even if we cannot reason about the1335    // argument. This means both SuccessSt and FailureSt can be true. If we1336    // weren't applying the constraint that would mean that symbolic1337    // execution continues on a code whose behaviour is undefined.1338    assert(SuccessSt);1339    NewState = SuccessSt;1340    if (NewState != State) {1341      SmallString<128> Msg;1342      llvm::raw_svector_ostream Os(Msg);1343      Os << "Assuming that the ";1344      printArgDesc(Constraint->getArgNo(), Os);1345      Os << " to '";1346      Os << getFunctionName(Call);1347      Os << "' ";1348      Constraint->describe(ValueConstraint::Assumption, Call, NewState, Summary,1349                           Os);1350      const auto ArgSVal = Call.getArgSVal(Constraint->getArgNo());1351      NewNode = C.addTransition(1352          NewState, NewNode,1353          C.getNoteTag([Msg = std::move(Msg), ArgSVal](1354                           PathSensitiveBugReport &BR, llvm::raw_ostream &OS) {1355            if (BR.isInteresting(ArgSVal))1356              OS << Msg;1357          }));1358    }1359  }1360}1361 1362void StdLibraryFunctionsChecker::checkPostCall(const CallEvent &Call,1363                                               CheckerContext &C) const {1364  std::optional<Summary> FoundSummary = findFunctionSummary(Call, C);1365  if (!FoundSummary)1366    return;1367 1368  // Now apply the constraints.1369  const Summary &Summary = *FoundSummary;1370  ProgramStateRef State = C.getState();1371  ExplodedNode *Node = C.getPredecessor();1372 1373  // Apply case/branch specifications.1374  for (const SummaryCase &Case : Summary.getCases()) {1375    ProgramStateRef NewState = State;1376    for (const ValueConstraintPtr &Constraint : Case.getConstraints()) {1377      NewState = Constraint->apply(NewState, Call, Summary, C);1378      if (!NewState)1379        break;1380    }1381 1382    if (NewState)1383      NewState = Case.getErrnoConstraint().apply(NewState, Call, Summary, C);1384 1385    if (!NewState)1386      continue;1387 1388    // Here it's possible that NewState == State, e.g. when other checkers1389    // already applied the same constraints (or stricter ones).1390    // Still add these note tags, the other checker should add only its1391    // specialized note tags. These general note tags are handled always by1392    // StdLibraryFunctionsChecker.1393 1394    ExplodedNode *Pred = Node;1395    DeclarationName FunctionName =1396        cast<NamedDecl>(Call.getDecl())->getDeclName();1397 1398    std::string ErrnoNote = Case.getErrnoConstraint().describe(C);1399    std::string CaseNote;1400    if (Case.getNote().empty()) {1401      if (!ErrnoNote.empty())1402        ErrnoNote =1403            llvm::formatv("After calling '{0}' {1}", FunctionName, ErrnoNote);1404    } else {1405      // Disable formatv() validation as the case note may not always have the1406      // {0} placeholder for function name.1407      CaseNote =1408          llvm::formatv(false, Case.getNote().str().c_str(), FunctionName);1409    }1410    const SVal RV = Call.getReturnValue();1411 1412    if (Summary.getInvalidationKd() == EvalCallAsPure) {1413      // Do not expect that errno is interesting (the "pure" functions do not1414      // affect it).1415      if (!CaseNote.empty()) {1416        const NoteTag *Tag = C.getNoteTag(1417            [Node, CaseNote, RV](PathSensitiveBugReport &BR) -> std::string {1418              // Try to omit the note if we know in advance which branch is1419              // taken (this means, only one branch exists).1420              // This check is performed inside the lambda, after other1421              // (or this) checkers had a chance to add other successors.1422              // Dereferencing the saved node object is valid because it's part1423              // of a bug report call sequence.1424              // FIXME: This check is not exact. We may be here after a state1425              // split that was performed by another checker (and can not find1426              // the successors). This is why this check is only used in the1427              // EvalCallAsPure case.1428              if (BR.isInteresting(RV) && Node->succ_size() > 1)1429                return CaseNote;1430              return "";1431            });1432        Pred = C.addTransition(NewState, Pred, Tag);1433      }1434    } else {1435      if (!CaseNote.empty() || !ErrnoNote.empty()) {1436        const NoteTag *Tag =1437            C.getNoteTag([CaseNote, ErrnoNote,1438                          RV](PathSensitiveBugReport &BR) -> std::string {1439              // If 'errno' is interesting, show the user a note about the case1440              // (what happened at the function call) and about how 'errno'1441              // causes the problem. ErrnoChecker sets the errno (but not RV) to1442              // interesting.1443              // If only the return value is interesting, show only the case1444              // note.1445              std::optional<Loc> ErrnoLoc =1446                  errno_modeling::getErrnoLoc(BR.getErrorNode()->getState());1447              bool ErrnoImportant = !ErrnoNote.empty() && ErrnoLoc &&1448                                    BR.isInteresting(ErrnoLoc->getAsRegion());1449              if (ErrnoImportant) {1450                BR.markNotInteresting(ErrnoLoc->getAsRegion());1451                if (CaseNote.empty())1452                  return ErrnoNote;1453                return llvm::formatv("{0}; {1}", CaseNote, ErrnoNote);1454              } else {1455                if (BR.isInteresting(RV))1456                  return CaseNote;1457              }1458              return "";1459            });1460        Pred = C.addTransition(NewState, Pred, Tag);1461      }1462    }1463 1464    // Add the transition if no note tag was added.1465    if (Pred == Node && NewState != State)1466      C.addTransition(NewState);1467  }1468}1469 1470bool StdLibraryFunctionsChecker::evalCall(const CallEvent &Call,1471                                          CheckerContext &C) const {1472  std::optional<Summary> FoundSummary = findFunctionSummary(Call, C);1473  if (!FoundSummary)1474    return false;1475 1476  const Summary &Summary = *FoundSummary;1477  switch (Summary.getInvalidationKd()) {1478  case EvalCallAsPure: {1479    ProgramStateRef State = C.getState();1480    const LocationContext *LC = C.getLocationContext();1481    const auto *CE = cast<CallExpr>(Call.getOriginExpr());1482    SVal V = C.getSValBuilder().conjureSymbolVal(Call, C.blockCount());1483    State = State->BindExpr(CE, LC, V);1484 1485    C.addTransition(State);1486 1487    return true;1488  }1489  case NoEvalCall:1490    // Summary tells us to avoid performing eval::Call. The function is possibly1491    // evaluated by another checker, or evaluated conservatively.1492    return false;1493  }1494  llvm_unreachable("Unknown invalidation kind!");1495}1496 1497bool StdLibraryFunctionsChecker::Signature::matches(1498    const FunctionDecl *FD) const {1499  assert(!isInvalid());1500  // Check the number of arguments.1501  if (FD->param_size() != ArgTys.size())1502    return false;1503 1504  // The "restrict" keyword is illegal in C++, however, many libc1505  // implementations use the "__restrict" compiler intrinsic in functions1506  // prototypes. The "__restrict" keyword qualifies a type as a restricted type1507  // even in C++.1508  // In case of any non-C99 languages, we don't want to match based on the1509  // restrict qualifier because we cannot know if the given libc implementation1510  // qualifies the paramter type or not.1511  auto RemoveRestrict = [&FD](QualType T) {1512    if (!FD->getASTContext().getLangOpts().C99)1513      T.removeLocalRestrict();1514    return T;1515  };1516 1517  // Check the return type.1518  if (!isIrrelevant(RetTy)) {1519    QualType FDRetTy = RemoveRestrict(FD->getReturnType().getCanonicalType());1520    if (RetTy != FDRetTy)1521      return false;1522  }1523 1524  // Check the argument types.1525  for (auto [Idx, ArgTy] : llvm::enumerate(ArgTys)) {1526    if (isIrrelevant(ArgTy))1527      continue;1528    QualType FDArgTy =1529        RemoveRestrict(FD->getParamDecl(Idx)->getType().getCanonicalType());1530    if (ArgTy != FDArgTy)1531      return false;1532  }1533 1534  return true;1535}1536 1537std::optional<StdLibraryFunctionsChecker::Summary>1538StdLibraryFunctionsChecker::findFunctionSummary(const FunctionDecl *FD,1539                                                CheckerContext &C) const {1540  if (!FD)1541    return std::nullopt;1542 1543  initFunctionSummaries(C);1544 1545  auto FSMI = FunctionSummaryMap.find(FD->getCanonicalDecl());1546  if (FSMI == FunctionSummaryMap.end())1547    return std::nullopt;1548  return FSMI->second;1549}1550 1551std::optional<StdLibraryFunctionsChecker::Summary>1552StdLibraryFunctionsChecker::findFunctionSummary(const CallEvent &Call,1553                                                CheckerContext &C) const {1554  const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(Call.getDecl());1555  if (!FD)1556    return std::nullopt;1557  return findFunctionSummary(FD, C);1558}1559 1560void StdLibraryFunctionsChecker::initFunctionSummaries(1561    CheckerContext &C) const {1562  if (SummariesInitialized)1563    return;1564  SummariesInitialized = true;1565 1566  SValBuilder &SVB = C.getSValBuilder();1567  BasicValueFactory &BVF = SVB.getBasicValueFactory();1568  const ASTContext &ACtx = BVF.getContext();1569  Preprocessor &PP = C.getPreprocessor();1570 1571  // Helper class to lookup a type by its name.1572  class LookupType {1573    const ASTContext &ACtx;1574 1575  public:1576    LookupType(const ASTContext &ACtx) : ACtx(ACtx) {}1577 1578    // Find the type. If not found then the optional is not set.1579    std::optional<QualType> operator()(StringRef Name) {1580      IdentifierInfo &II = ACtx.Idents.get(Name);1581      auto LookupRes = ACtx.getTranslationUnitDecl()->lookup(&II);1582      if (LookupRes.empty())1583        return std::nullopt;1584 1585      // Prioritize typedef declarations.1586      // This is needed in case of C struct typedefs. E.g.:1587      //   typedef struct FILE FILE;1588      // In this case, we have a RecordDecl 'struct FILE' with the name 'FILE'1589      // and we have a TypedefDecl with the name 'FILE'.1590      for (Decl *D : LookupRes)1591        if (auto *TD = dyn_cast<TypedefNameDecl>(D))1592          return ACtx.getCanonicalTypeDeclType(TD);1593 1594      // Find the first TypeDecl.1595      // There maybe cases when a function has the same name as a struct.1596      // E.g. in POSIX: `struct stat` and the function `stat()`:1597      //   int stat(const char *restrict path, struct stat *restrict buf);1598      for (Decl *D : LookupRes)1599        if (auto *TD = dyn_cast<TypeDecl>(D))1600          return ACtx.getCanonicalTypeDeclType(TD);1601      return std::nullopt;1602    }1603  } lookupTy(ACtx);1604 1605  // Below are auxiliary classes to handle optional types that we get as a1606  // result of the lookup.1607  class GetRestrictTy {1608    const ASTContext &ACtx;1609 1610  public:1611    GetRestrictTy(const ASTContext &ACtx) : ACtx(ACtx) {}1612    QualType operator()(QualType Ty) {1613      return ACtx.getLangOpts().C99 ? ACtx.getRestrictType(Ty) : Ty;1614    }1615    std::optional<QualType> operator()(std::optional<QualType> Ty) {1616      if (Ty)1617        return operator()(*Ty);1618      return std::nullopt;1619    }1620  } getRestrictTy(ACtx);1621  class GetPointerTy {1622    const ASTContext &ACtx;1623 1624  public:1625    GetPointerTy(const ASTContext &ACtx) : ACtx(ACtx) {}1626    QualType operator()(QualType Ty) { return ACtx.getPointerType(Ty); }1627    std::optional<QualType> operator()(std::optional<QualType> Ty) {1628      if (Ty)1629        return operator()(*Ty);1630      return std::nullopt;1631    }1632  } getPointerTy(ACtx);1633  class {1634  public:1635    std::optional<QualType> operator()(std::optional<QualType> Ty) {1636      return Ty ? std::optional<QualType>(Ty->withConst()) : std::nullopt;1637    }1638    QualType operator()(QualType Ty) { return Ty.withConst(); }1639  } getConstTy;1640  class GetMaxValue {1641    BasicValueFactory &BVF;1642 1643  public:1644    GetMaxValue(BasicValueFactory &BVF) : BVF(BVF) {}1645    std::optional<RangeInt> operator()(QualType Ty) {1646      return BVF.getMaxValue(Ty)->getLimitedValue();1647    }1648    std::optional<RangeInt> operator()(std::optional<QualType> Ty) {1649      if (Ty) {1650        return operator()(*Ty);1651      }1652      return std::nullopt;1653    }1654  } getMaxValue(BVF);1655 1656  // These types are useful for writing specifications quickly,1657  // New specifications should probably introduce more types.1658  // Some types are hard to obtain from the AST, eg. "ssize_t".1659  // In such cases it should be possible to provide multiple variants1660  // of function summary for common cases (eg. ssize_t could be int or long1661  // or long long, so three summary variants would be enough).1662  // Of course, function variants are also useful for C++ overloads.1663  const QualType VoidTy = ACtx.VoidTy;1664  const QualType CharTy = ACtx.CharTy;1665  const QualType WCharTy = ACtx.WCharTy;1666  const QualType IntTy = ACtx.IntTy;1667  const QualType UnsignedIntTy = ACtx.UnsignedIntTy;1668  const QualType LongTy = ACtx.LongTy;1669  const QualType SizeTyCanonTy = ACtx.getCanonicalSizeType();1670 1671  const QualType VoidPtrTy = getPointerTy(VoidTy); // void *1672  const QualType IntPtrTy = getPointerTy(IntTy);   // int *1673  const QualType UnsignedIntPtrTy =1674      getPointerTy(UnsignedIntTy); // unsigned int *1675  const QualType VoidPtrRestrictTy = getRestrictTy(VoidPtrTy);1676  const QualType ConstVoidPtrTy =1677      getPointerTy(getConstTy(VoidTy));            // const void *1678  const QualType CharPtrTy = getPointerTy(CharTy); // char *1679  const QualType CharPtrRestrictTy = getRestrictTy(CharPtrTy);1680  const QualType ConstCharPtrTy =1681      getPointerTy(getConstTy(CharTy)); // const char *1682  const QualType ConstCharPtrRestrictTy = getRestrictTy(ConstCharPtrTy);1683  const QualType Wchar_tPtrTy = getPointerTy(WCharTy); // wchar_t *1684  const QualType ConstWchar_tPtrTy =1685      getPointerTy(getConstTy(WCharTy)); // const wchar_t *1686  const QualType ConstVoidPtrRestrictTy = getRestrictTy(ConstVoidPtrTy);1687  const QualType SizePtrTy = getPointerTy(SizeTyCanonTy);1688  const QualType SizePtrRestrictTy = getRestrictTy(SizePtrTy);1689 1690  const RangeInt IntMax = BVF.getMaxValue(IntTy)->getLimitedValue();1691  const RangeInt UnsignedIntMax =1692      BVF.getMaxValue(UnsignedIntTy)->getLimitedValue();1693  const RangeInt LongMax = BVF.getMaxValue(LongTy)->getLimitedValue();1694  const RangeInt SizeMax = BVF.getMaxValue(SizeTyCanonTy)->getLimitedValue();1695 1696  // Set UCharRangeMax to min of int or uchar maximum value.1697  // The C standard states that the arguments of functions like isalpha must1698  // be representable as an unsigned char. Their type is 'int', so the max1699  // value of the argument should be min(UCharMax, IntMax). This just happen1700  // to be true for commonly used and well tested instruction set1701  // architectures, but not for others.1702  const RangeInt UCharRangeMax =1703      std::min(BVF.getMaxValue(ACtx.UnsignedCharTy)->getLimitedValue(), IntMax);1704 1705  // Get platform dependent values of some macros.1706  // Try our best to parse this from the Preprocessor, otherwise fallback to a1707  // default value (what is found in a library header).1708  const auto EOFv = tryExpandAsInteger("EOF", PP).value_or(-1);1709  const auto AT_FDCWDv = tryExpandAsInteger("AT_FDCWD", PP).value_or(-100);1710 1711  // Auxiliary class to aid adding summaries to the summary map.1712  struct AddToFunctionSummaryMap {1713    const ASTContext &ACtx;1714    FunctionSummaryMapType &Map;1715    bool DisplayLoadedSummaries;1716    AddToFunctionSummaryMap(const ASTContext &ACtx, FunctionSummaryMapType &FSM,1717                            bool DisplayLoadedSummaries)1718        : ACtx(ACtx), Map(FSM), DisplayLoadedSummaries(DisplayLoadedSummaries) {1719    }1720 1721    // Add a summary to a FunctionDecl found by lookup. The lookup is performed1722    // by the given Name, and in the global scope. The summary will be attached1723    // to the found FunctionDecl only if the signatures match.1724    //1725    // Returns true if the summary has been added, false otherwise.1726    bool operator()(StringRef Name, Signature Sign, Summary Sum) {1727      if (Sign.isInvalid())1728        return false;1729      IdentifierInfo &II = ACtx.Idents.get(Name);1730      auto LookupRes = ACtx.getTranslationUnitDecl()->lookup(&II);1731      if (LookupRes.empty())1732        return false;1733      for (Decl *D : LookupRes) {1734        if (auto *FD = dyn_cast<FunctionDecl>(D)) {1735          if (Sum.matchesAndSet(Sign, FD)) {1736            auto Res = Map.insert({FD->getCanonicalDecl(), Sum});1737            assert(Res.second && "Function already has a summary set!");1738            (void)Res;1739            if (DisplayLoadedSummaries) {1740              llvm::errs() << "Loaded summary for: ";1741              FD->print(llvm::errs());1742              llvm::errs() << "\n";1743            }1744            return true;1745          }1746        }1747      }1748      return false;1749    }1750    // Add the same summary for different names with the Signature explicitly1751    // given.1752    void operator()(ArrayRef<StringRef> Names, Signature Sign, Summary Sum) {1753      for (StringRef Name : Names)1754        operator()(Name, Sign, Sum);1755    }1756  } addToFunctionSummaryMap(ACtx, FunctionSummaryMap, DisplayLoadedSummaries);1757 1758  // Below are helpers functions to create the summaries.1759  auto ArgumentCondition = [](ArgNo ArgN, RangeKind Kind, IntRangeVector Ranges,1760                              StringRef Desc = "") {1761    return std::make_shared<RangeConstraint>(ArgN, Kind, Ranges, Desc);1762  };1763  auto BufferSize = [](auto... Args) {1764    return std::make_shared<BufferSizeConstraint>(Args...);1765  };1766  struct {1767    auto operator()(RangeKind Kind, IntRangeVector Ranges) {1768      return std::make_shared<RangeConstraint>(Ret, Kind, Ranges);1769    }1770    auto operator()(BinaryOperator::Opcode Op, ArgNo OtherArgN) {1771      return std::make_shared<ComparisonConstraint>(Ret, Op, OtherArgN);1772    }1773  } ReturnValueCondition;1774  struct {1775    auto operator()(RangeInt b, RangeInt e) {1776      return IntRangeVector{std::pair<RangeInt, RangeInt>{b, e}};1777    }1778    auto operator()(RangeInt b, std::optional<RangeInt> e) {1779      if (e)1780        return IntRangeVector{std::pair<RangeInt, RangeInt>{b, *e}};1781      return IntRangeVector{};1782    }1783    auto operator()(std::pair<RangeInt, RangeInt> i0,1784                    std::pair<RangeInt, std::optional<RangeInt>> i1) {1785      if (i1.second)1786        return IntRangeVector{i0, {i1.first, *(i1.second)}};1787      return IntRangeVector{i0};1788    }1789  } Range;1790  auto SingleValue = [](RangeInt v) {1791    return IntRangeVector{std::pair<RangeInt, RangeInt>{v, v}};1792  };1793  auto LessThanOrEq = BO_LE;1794  auto NotNull = [&](ArgNo ArgN) {1795    return std::make_shared<NullnessConstraint>(ArgN);1796  };1797  auto IsNull = [&](ArgNo ArgN) {1798    return std::make_shared<NullnessConstraint>(ArgN, false);1799  };1800  auto NotNullBuffer = [&](ArgNo ArgN, ArgNo SizeArg1N,1801                           std::optional<ArgNo> SizeArg2N = std::nullopt) {1802    return std::make_shared<BufferNullnessConstraint>(ArgN, SizeArg1N,1803                                                      SizeArg2N);1804  };1805 1806  std::optional<QualType> FileTy = lookupTy("FILE");1807  std::optional<QualType> FilePtrTy = getPointerTy(FileTy);1808  std::optional<QualType> FilePtrRestrictTy = getRestrictTy(FilePtrTy);1809 1810  std::optional<QualType> FPosTTy = lookupTy("fpos_t");1811  std::optional<QualType> FPosTPtrTy = getPointerTy(FPosTTy);1812  std::optional<QualType> ConstFPosTPtrTy = getPointerTy(getConstTy(FPosTTy));1813  std::optional<QualType> FPosTPtrRestrictTy = getRestrictTy(FPosTPtrTy);1814 1815  constexpr llvm::StringLiteral GenericSuccessMsg(1816      "Assuming that '{0}' is successful");1817  constexpr llvm::StringLiteral GenericFailureMsg("Assuming that '{0}' fails");1818 1819  // We are finally ready to define specifications for all supported functions.1820  //1821  // Argument ranges should always cover all variants. If return value1822  // is completely unknown, omit it from the respective range set.1823  //1824  // Every item in the list of range sets represents a particular1825  // execution path the analyzer would need to explore once1826  // the call is modeled - a new program state is constructed1827  // for every range set, and each range line in the range set1828  // corresponds to a specific constraint within this state.1829 1830  // The isascii() family of functions.1831  // The behavior is undefined if the value of the argument is not1832  // representable as unsigned char or is not equal to EOF. See e.g. C991833  // 7.4.1.2 The isalpha function (p: 181-182).1834  addToFunctionSummaryMap(1835      "isalnum", Signature(ArgTypes{IntTy}, RetType{IntTy}),1836      Summary(EvalCallAsPure)1837          // Boils down to isupper() or islower() or isdigit().1838          .Case({ArgumentCondition(0U, WithinRange,1839                                   {{'0', '9'}, {'A', 'Z'}, {'a', 'z'}}),1840                 ReturnValueCondition(OutOfRange, SingleValue(0))},1841                ErrnoIrrelevant, "Assuming the character is alphanumeric")1842          // The locale-specific range.1843          // No post-condition. We are completely unaware of1844          // locale-specific return values.1845          .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})},1846                ErrnoIrrelevant)1847          .Case(1848              {ArgumentCondition(1849                   0U, OutOfRange,1850                   {{'0', '9'}, {'A', 'Z'}, {'a', 'z'}, {128, UCharRangeMax}}),1851               ReturnValueCondition(WithinRange, SingleValue(0))},1852              ErrnoIrrelevant, "Assuming the character is non-alphanumeric")1853          .ArgConstraint(ArgumentCondition(0U, WithinRange,1854                                           {{EOFv, EOFv}, {0, UCharRangeMax}},1855                                           "an unsigned char value or EOF")));1856  addToFunctionSummaryMap(1857      "isalpha", Signature(ArgTypes{IntTy}, RetType{IntTy}),1858      Summary(EvalCallAsPure)1859          .Case({ArgumentCondition(0U, WithinRange, {{'A', 'Z'}, {'a', 'z'}}),1860                 ReturnValueCondition(OutOfRange, SingleValue(0))},1861                ErrnoIrrelevant, "Assuming the character is alphabetical")1862          // The locale-specific range.1863          .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})},1864                ErrnoIrrelevant)1865          .Case({ArgumentCondition(1866                     0U, OutOfRange,1867                     {{'A', 'Z'}, {'a', 'z'}, {128, UCharRangeMax}}),1868                 ReturnValueCondition(WithinRange, SingleValue(0))},1869                ErrnoIrrelevant, "Assuming the character is non-alphabetical"));1870  addToFunctionSummaryMap(1871      "isascii", Signature(ArgTypes{IntTy}, RetType{IntTy}),1872      Summary(EvalCallAsPure)1873          .Case({ArgumentCondition(0U, WithinRange, Range(0, 127)),1874                 ReturnValueCondition(OutOfRange, SingleValue(0))},1875                ErrnoIrrelevant, "Assuming the character is an ASCII character")1876          .Case({ArgumentCondition(0U, OutOfRange, Range(0, 127)),1877                 ReturnValueCondition(WithinRange, SingleValue(0))},1878                ErrnoIrrelevant,1879                "Assuming the character is not an ASCII character"));1880  addToFunctionSummaryMap(1881      "isblank", Signature(ArgTypes{IntTy}, RetType{IntTy}),1882      Summary(EvalCallAsPure)1883          .Case({ArgumentCondition(0U, WithinRange, {{'\t', '\t'}, {' ', ' '}}),1884                 ReturnValueCondition(OutOfRange, SingleValue(0))},1885                ErrnoIrrelevant, "Assuming the character is a blank character")1886          .Case({ArgumentCondition(0U, OutOfRange, {{'\t', '\t'}, {' ', ' '}}),1887                 ReturnValueCondition(WithinRange, SingleValue(0))},1888                ErrnoIrrelevant,1889                "Assuming the character is not a blank character"));1890  addToFunctionSummaryMap(1891      "iscntrl", Signature(ArgTypes{IntTy}, RetType{IntTy}),1892      Summary(EvalCallAsPure)1893          .Case({ArgumentCondition(0U, WithinRange, {{0, 32}, {127, 127}}),1894                 ReturnValueCondition(OutOfRange, SingleValue(0))},1895                ErrnoIrrelevant,1896                "Assuming the character is a control character")1897          .Case({ArgumentCondition(0U, OutOfRange, {{0, 32}, {127, 127}}),1898                 ReturnValueCondition(WithinRange, SingleValue(0))},1899                ErrnoIrrelevant,1900                "Assuming the character is not a control character"));1901  addToFunctionSummaryMap(1902      "isdigit", Signature(ArgTypes{IntTy}, RetType{IntTy}),1903      Summary(EvalCallAsPure)1904          .Case({ArgumentCondition(0U, WithinRange, Range('0', '9')),1905                 ReturnValueCondition(OutOfRange, SingleValue(0))},1906                ErrnoIrrelevant, "Assuming the character is a digit")1907          .Case({ArgumentCondition(0U, OutOfRange, Range('0', '9')),1908                 ReturnValueCondition(WithinRange, SingleValue(0))},1909                ErrnoIrrelevant, "Assuming the character is not a digit"));1910  addToFunctionSummaryMap(1911      "isgraph", Signature(ArgTypes{IntTy}, RetType{IntTy}),1912      Summary(EvalCallAsPure)1913          .Case({ArgumentCondition(0U, WithinRange, Range(33, 126)),1914                 ReturnValueCondition(OutOfRange, SingleValue(0))},1915                ErrnoIrrelevant,1916                "Assuming the character has graphical representation")1917          .Case(1918              {ArgumentCondition(0U, OutOfRange, Range(33, 126)),1919               ReturnValueCondition(WithinRange, SingleValue(0))},1920              ErrnoIrrelevant,1921              "Assuming the character does not have graphical representation"));1922  addToFunctionSummaryMap(1923      "islower", Signature(ArgTypes{IntTy}, RetType{IntTy}),1924      Summary(EvalCallAsPure)1925          // Is certainly lowercase.1926          .Case({ArgumentCondition(0U, WithinRange, Range('a', 'z')),1927                 ReturnValueCondition(OutOfRange, SingleValue(0))},1928                ErrnoIrrelevant, "Assuming the character is a lowercase letter")1929          // Is ascii but not lowercase.1930          .Case({ArgumentCondition(0U, WithinRange, Range(0, 127)),1931                 ArgumentCondition(0U, OutOfRange, Range('a', 'z')),1932                 ReturnValueCondition(WithinRange, SingleValue(0))},1933                ErrnoIrrelevant,1934                "Assuming the character is not a lowercase letter")1935          // The locale-specific range.1936          .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})},1937                ErrnoIrrelevant)1938          // Is not an unsigned char.1939          .Case({ArgumentCondition(0U, OutOfRange, Range(0, UCharRangeMax)),1940                 ReturnValueCondition(WithinRange, SingleValue(0))},1941                ErrnoIrrelevant));1942  addToFunctionSummaryMap(1943      "isprint", Signature(ArgTypes{IntTy}, RetType{IntTy}),1944      Summary(EvalCallAsPure)1945          .Case({ArgumentCondition(0U, WithinRange, Range(32, 126)),1946                 ReturnValueCondition(OutOfRange, SingleValue(0))},1947                ErrnoIrrelevant, "Assuming the character is printable")1948          .Case({ArgumentCondition(0U, OutOfRange, Range(32, 126)),1949                 ReturnValueCondition(WithinRange, SingleValue(0))},1950                ErrnoIrrelevant, "Assuming the character is non-printable"));1951  addToFunctionSummaryMap(1952      "ispunct", Signature(ArgTypes{IntTy}, RetType{IntTy}),1953      Summary(EvalCallAsPure)1954          .Case({ArgumentCondition(1955                     0U, WithinRange,1956                     {{'!', '/'}, {':', '@'}, {'[', '`'}, {'{', '~'}}),1957                 ReturnValueCondition(OutOfRange, SingleValue(0))},1958                ErrnoIrrelevant, "Assuming the character is a punctuation mark")1959          .Case({ArgumentCondition(1960                     0U, OutOfRange,1961                     {{'!', '/'}, {':', '@'}, {'[', '`'}, {'{', '~'}}),1962                 ReturnValueCondition(WithinRange, SingleValue(0))},1963                ErrnoIrrelevant,1964                "Assuming the character is not a punctuation mark"));1965  addToFunctionSummaryMap(1966      "isspace", Signature(ArgTypes{IntTy}, RetType{IntTy}),1967      Summary(EvalCallAsPure)1968          // Space, '\f', '\n', '\r', '\t', '\v'.1969          .Case({ArgumentCondition(0U, WithinRange, {{9, 13}, {' ', ' '}}),1970                 ReturnValueCondition(OutOfRange, SingleValue(0))},1971                ErrnoIrrelevant,1972                "Assuming the character is a whitespace character")1973          // The locale-specific range.1974          .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})},1975                ErrnoIrrelevant)1976          .Case({ArgumentCondition(0U, OutOfRange,1977                                   {{9, 13}, {' ', ' '}, {128, UCharRangeMax}}),1978                 ReturnValueCondition(WithinRange, SingleValue(0))},1979                ErrnoIrrelevant,1980                "Assuming the character is not a whitespace character"));1981  addToFunctionSummaryMap(1982      "isupper", Signature(ArgTypes{IntTy}, RetType{IntTy}),1983      Summary(EvalCallAsPure)1984          // Is certainly uppercase.1985          .Case({ArgumentCondition(0U, WithinRange, Range('A', 'Z')),1986                 ReturnValueCondition(OutOfRange, SingleValue(0))},1987                ErrnoIrrelevant,1988                "Assuming the character is an uppercase letter")1989          // The locale-specific range.1990          .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})},1991                ErrnoIrrelevant)1992          // Other.1993          .Case({ArgumentCondition(0U, OutOfRange,1994                                   {{'A', 'Z'}, {128, UCharRangeMax}}),1995                 ReturnValueCondition(WithinRange, SingleValue(0))},1996                ErrnoIrrelevant,1997                "Assuming the character is not an uppercase letter"));1998  addToFunctionSummaryMap(1999      "isxdigit", Signature(ArgTypes{IntTy}, RetType{IntTy}),2000      Summary(EvalCallAsPure)2001          .Case({ArgumentCondition(0U, WithinRange,2002                                   {{'0', '9'}, {'A', 'F'}, {'a', 'f'}}),2003                 ReturnValueCondition(OutOfRange, SingleValue(0))},2004                ErrnoIrrelevant,2005                "Assuming the character is a hexadecimal digit")2006          .Case({ArgumentCondition(0U, OutOfRange,2007                                   {{'0', '9'}, {'A', 'F'}, {'a', 'f'}}),2008                 ReturnValueCondition(WithinRange, SingleValue(0))},2009                ErrnoIrrelevant,2010                "Assuming the character is not a hexadecimal digit"));2011  addToFunctionSummaryMap(2012      "toupper", Signature(ArgTypes{IntTy}, RetType{IntTy}),2013      Summary(EvalCallAsPure)2014          .ArgConstraint(ArgumentCondition(0U, WithinRange,2015                                           {{EOFv, EOFv}, {0, UCharRangeMax}},2016                                           "an unsigned char value or EOF")));2017  addToFunctionSummaryMap(2018      "tolower", Signature(ArgTypes{IntTy}, RetType{IntTy}),2019      Summary(EvalCallAsPure)2020          .ArgConstraint(ArgumentCondition(0U, WithinRange,2021                                           {{EOFv, EOFv}, {0, UCharRangeMax}},2022                                           "an unsigned char value or EOF")));2023  addToFunctionSummaryMap(2024      "toascii", Signature(ArgTypes{IntTy}, RetType{IntTy}),2025      Summary(EvalCallAsPure)2026          .ArgConstraint(ArgumentCondition(0U, WithinRange,2027                                           {{EOFv, EOFv}, {0, UCharRangeMax}},2028                                           "an unsigned char value or EOF")));2029 2030  addToFunctionSummaryMap(2031      "getchar", Signature(ArgTypes{}, RetType{IntTy}),2032      Summary(NoEvalCall)2033          .Case({ReturnValueCondition(WithinRange,2034                                      {{EOFv, EOFv}, {0, UCharRangeMax}})},2035                ErrnoIrrelevant));2036 2037  // read()-like functions that never return more than buffer size.2038  auto FreadSummary =2039      Summary(NoEvalCall)2040          .Case({ArgumentCondition(1U, WithinRange, Range(1, SizeMax)),2041                 ArgumentCondition(2U, WithinRange, Range(1, SizeMax)),2042                 ReturnValueCondition(BO_LT, ArgNo(2)),2043                 ReturnValueCondition(WithinRange, Range(0, SizeMax))},2044                ErrnoNEZeroIrrelevant, GenericFailureMsg)2045          .Case({ArgumentCondition(1U, WithinRange, Range(1, SizeMax)),2046                 ReturnValueCondition(BO_EQ, ArgNo(2)),2047                 ReturnValueCondition(WithinRange, Range(0, SizeMax))},2048                ErrnoMustNotBeChecked, GenericSuccessMsg)2049          .Case({ArgumentCondition(1U, WithinRange, SingleValue(0)),2050                 ReturnValueCondition(WithinRange, SingleValue(0))},2051                ErrnoMustNotBeChecked,2052                "Assuming that argument 'size' to '{0}' is 0")2053          .ArgConstraint(NotNullBuffer(ArgNo(0), ArgNo(1), ArgNo(2)))2054          .ArgConstraint(NotNull(ArgNo(3)))2055          .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1),2056                                    /*BufSizeMultiplier=*/ArgNo(2)));2057 2058  // size_t fread(void *restrict ptr, size_t size, size_t nitems,2059  //              FILE *restrict stream);2060  addToFunctionSummaryMap("fread",2061                          Signature(ArgTypes{VoidPtrRestrictTy, SizeTyCanonTy,2062                                             SizeTyCanonTy, FilePtrRestrictTy},2063                                    RetType{SizeTyCanonTy}),2064                          FreadSummary);2065  // size_t fwrite(const void *restrict ptr, size_t size, size_t nitems,2066  //               FILE *restrict stream);2067  addToFunctionSummaryMap(2068      "fwrite",2069      Signature(ArgTypes{ConstVoidPtrRestrictTy, SizeTyCanonTy, SizeTyCanonTy,2070                         FilePtrRestrictTy},2071                RetType{SizeTyCanonTy}),2072      FreadSummary);2073 2074  std::optional<QualType> Ssize_tTy = lookupTy("ssize_t");2075  std::optional<RangeInt> Ssize_tMax = getMaxValue(Ssize_tTy);2076 2077  auto ReadSummary =2078      Summary(NoEvalCall)2079          .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)),2080                 ReturnValueCondition(WithinRange, Range(-1, Ssize_tMax))},2081                ErrnoIrrelevant);2082 2083  // FIXME these are actually defined by POSIX and not by the C standard, we2084  // should handle them together with the rest of the POSIX functions.2085  // ssize_t read(int fildes, void *buf, size_t nbyte);2086  addToFunctionSummaryMap(2087      "read",2088      Signature(ArgTypes{IntTy, VoidPtrTy, SizeTyCanonTy}, RetType{Ssize_tTy}),2089      ReadSummary);2090  // ssize_t write(int fildes, const void *buf, size_t nbyte);2091  addToFunctionSummaryMap(2092      "write",2093      Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTyCanonTy},2094                RetType{Ssize_tTy}),2095      ReadSummary);2096 2097  auto GetLineSummary =2098      Summary(NoEvalCall)2099          .Case({ReturnValueCondition(WithinRange,2100                                      Range({-1, -1}, {1, Ssize_tMax}))},2101                ErrnoIrrelevant);2102 2103  QualType CharPtrPtrRestrictTy = getRestrictTy(getPointerTy(CharPtrTy));2104 2105  // getline()-like functions either fail or read at least the delimiter.2106  // FIXME these are actually defined by POSIX and not by the C standard, we2107  // should handle them together with the rest of the POSIX functions.2108  // ssize_t getline(char **restrict lineptr, size_t *restrict n,2109  //                 FILE *restrict stream);2110  addToFunctionSummaryMap(2111      "getline",2112      Signature(2113          ArgTypes{CharPtrPtrRestrictTy, SizePtrRestrictTy, FilePtrRestrictTy},2114          RetType{Ssize_tTy}),2115      GetLineSummary);2116  // ssize_t getdelim(char **restrict lineptr, size_t *restrict n,2117  //                  int delimiter, FILE *restrict stream);2118  addToFunctionSummaryMap(2119      "getdelim",2120      Signature(ArgTypes{CharPtrPtrRestrictTy, SizePtrRestrictTy, IntTy,2121                         FilePtrRestrictTy},2122                RetType{Ssize_tTy}),2123      GetLineSummary);2124 2125  {2126    Summary GetenvSummary =2127        Summary(NoEvalCall)2128            .ArgConstraint(NotNull(ArgNo(0)))2129            .Case({NotNull(Ret)}, ErrnoIrrelevant,2130                  "Assuming the environment variable exists");2131    // In untrusted environments the envvar might not exist.2132    if (!ShouldAssumeControlledEnvironment)2133      GetenvSummary.Case({NotNull(Ret)->negate()}, ErrnoIrrelevant,2134                         "Assuming the environment variable does not exist");2135 2136    // char *getenv(const char *name);2137    addToFunctionSummaryMap(2138        "getenv", Signature(ArgTypes{ConstCharPtrTy}, RetType{CharPtrTy}),2139        std::move(GetenvSummary));2140  }2141 2142  if (!ModelPOSIX) {2143    // Without POSIX use of 'errno' is not specified (in these cases).2144    // Add these functions without 'errno' checks.2145    addToFunctionSummaryMap(2146        {"getc", "fgetc"}, Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),2147        Summary(NoEvalCall)2148            .Case({ReturnValueCondition(WithinRange,2149                                        {{EOFv, EOFv}, {0, UCharRangeMax}})},2150                  ErrnoIrrelevant)2151            .ArgConstraint(NotNull(ArgNo(0))));2152  } else {2153    const auto ReturnsZeroOrMinusOne =2154        ConstraintSet{ReturnValueCondition(WithinRange, Range(-1, 0))};2155    const auto ReturnsZero =2156        ConstraintSet{ReturnValueCondition(WithinRange, SingleValue(0))};2157    const auto ReturnsMinusOne =2158        ConstraintSet{ReturnValueCondition(WithinRange, SingleValue(-1))};2159    const auto ReturnsEOF =2160        ConstraintSet{ReturnValueCondition(WithinRange, SingleValue(EOFv))};2161    const auto ReturnsNonnegative =2162        ConstraintSet{ReturnValueCondition(WithinRange, Range(0, IntMax))};2163    const auto ReturnsNonZero =2164        ConstraintSet{ReturnValueCondition(OutOfRange, SingleValue(0))};2165    const auto ReturnsFileDescriptor =2166        ConstraintSet{ReturnValueCondition(WithinRange, Range(-1, IntMax))};2167    const auto &ReturnsValidFileDescriptor = ReturnsNonnegative;2168 2169    auto ValidFileDescriptorOrAtFdcwd = [&](ArgNo ArgN) {2170      return std::make_shared<RangeConstraint>(2171          ArgN, WithinRange, Range({AT_FDCWDv, AT_FDCWDv}, {0, IntMax}),2172          "a valid file descriptor or AT_FDCWD");2173    };2174 2175    // FILE *fopen(const char *restrict pathname, const char *restrict mode);2176    addToFunctionSummaryMap(2177        "fopen",2178        Signature(ArgTypes{ConstCharPtrRestrictTy, ConstCharPtrRestrictTy},2179                  RetType{FilePtrTy}),2180        Summary(NoEvalCall)2181            .Case({NotNull(Ret)}, ErrnoMustNotBeChecked, GenericSuccessMsg)2182            .Case({IsNull(Ret)}, ErrnoNEZeroIrrelevant, GenericFailureMsg)2183            .ArgConstraint(NotNull(ArgNo(0)))2184            .ArgConstraint(NotNull(ArgNo(1))));2185 2186    // FILE *fdopen(int fd, const char *mode);2187    addToFunctionSummaryMap(2188        "fdopen",2189        Signature(ArgTypes{IntTy, ConstCharPtrTy}, RetType{FilePtrTy}),2190        Summary(NoEvalCall)2191            .Case({NotNull(Ret)}, ErrnoMustNotBeChecked, GenericSuccessMsg)2192            .Case({IsNull(Ret)}, ErrnoNEZeroIrrelevant, GenericFailureMsg)2193            .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))2194            .ArgConstraint(NotNull(ArgNo(1))));2195 2196    // FILE *tmpfile(void);2197    addToFunctionSummaryMap(2198        "tmpfile", Signature(ArgTypes{}, RetType{FilePtrTy}),2199        Summary(NoEvalCall)2200            .Case({NotNull(Ret)}, ErrnoMustNotBeChecked, GenericSuccessMsg)2201            .Case({IsNull(Ret)}, ErrnoNEZeroIrrelevant, GenericFailureMsg));2202 2203    // FILE *freopen(const char *restrict pathname, const char *restrict mode,2204    //               FILE *restrict stream);2205    addToFunctionSummaryMap(2206        "freopen",2207        Signature(ArgTypes{ConstCharPtrRestrictTy, ConstCharPtrRestrictTy,2208                           FilePtrRestrictTy},2209                  RetType{FilePtrTy}),2210        Summary(NoEvalCall)2211            .Case({ReturnValueCondition(BO_EQ, ArgNo(2))},2212                  ErrnoMustNotBeChecked, GenericSuccessMsg)2213            .Case({IsNull(Ret)}, ErrnoNEZeroIrrelevant, GenericFailureMsg)2214            .ArgConstraint(NotNull(ArgNo(1)))2215            .ArgConstraint(NotNull(ArgNo(2))));2216 2217    // FILE *popen(const char *command, const char *type);2218    addToFunctionSummaryMap(2219        "popen",2220        Signature(ArgTypes{ConstCharPtrTy, ConstCharPtrTy}, RetType{FilePtrTy}),2221        Summary(NoEvalCall)2222            .Case({NotNull(Ret)}, ErrnoMustNotBeChecked, GenericSuccessMsg)2223            .Case({IsNull(Ret)}, ErrnoNEZeroIrrelevant, GenericFailureMsg)2224            .ArgConstraint(NotNull(ArgNo(0)))2225            .ArgConstraint(NotNull(ArgNo(1))));2226 2227    // int fclose(FILE *stream);2228    addToFunctionSummaryMap(2229        "fclose", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),2230        Summary(NoEvalCall)2231            .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)2232            .Case(ReturnsEOF, ErrnoNEZeroIrrelevant, GenericFailureMsg)2233            .ArgConstraint(NotNull(ArgNo(0))));2234 2235    // int pclose(FILE *stream);2236    addToFunctionSummaryMap(2237        "pclose", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),2238        Summary(NoEvalCall)2239            .Case({ReturnValueCondition(WithinRange, {{0, IntMax}})},2240                  ErrnoMustNotBeChecked, GenericSuccessMsg)2241            .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)2242            .ArgConstraint(NotNull(ArgNo(0))));2243 2244    std::optional<QualType> Off_tTy = lookupTy("off_t");2245    std::optional<RangeInt> Off_tMax = getMaxValue(Off_tTy);2246 2247    // int fgetc(FILE *stream);2248    // 'getc' is the same as 'fgetc' but may be a macro2249    addToFunctionSummaryMap(2250        {"getc", "fgetc"}, Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),2251        Summary(NoEvalCall)2252            .Case({ReturnValueCondition(WithinRange, {{0, UCharRangeMax}})},2253                  ErrnoMustNotBeChecked, GenericSuccessMsg)2254            .Case({ReturnValueCondition(WithinRange, SingleValue(EOFv))},2255                  ErrnoIrrelevant, GenericFailureMsg)2256            .ArgConstraint(NotNull(ArgNo(0))));2257 2258    // int fputc(int c, FILE *stream);2259    // 'putc' is the same as 'fputc' but may be a macro2260    addToFunctionSummaryMap(2261        {"putc", "fputc"},2262        Signature(ArgTypes{IntTy, FilePtrTy}, RetType{IntTy}),2263        Summary(NoEvalCall)2264            .Case({ArgumentCondition(0, WithinRange, Range(0, UCharRangeMax)),2265                   ReturnValueCondition(BO_EQ, ArgNo(0))},2266                  ErrnoMustNotBeChecked, GenericSuccessMsg)2267            .Case({ArgumentCondition(0, OutOfRange, Range(0, UCharRangeMax)),2268                   ReturnValueCondition(WithinRange, Range(0, UCharRangeMax))},2269                  ErrnoMustNotBeChecked, GenericSuccessMsg)2270            .Case({ReturnValueCondition(WithinRange, SingleValue(EOFv))},2271                  ErrnoNEZeroIrrelevant, GenericFailureMsg)2272            .ArgConstraint(NotNull(ArgNo(1))));2273 2274    // char *fgets(char *restrict s, int n, FILE *restrict stream);2275    addToFunctionSummaryMap(2276        "fgets",2277        Signature(ArgTypes{CharPtrRestrictTy, IntTy, FilePtrRestrictTy},2278                  RetType{CharPtrTy}),2279        Summary(NoEvalCall)2280            .Case({ReturnValueCondition(BO_EQ, ArgNo(0))},2281                  ErrnoMustNotBeChecked, GenericSuccessMsg)2282            .Case({IsNull(Ret)}, ErrnoIrrelevant, GenericFailureMsg)2283            .ArgConstraint(NotNull(ArgNo(0)))2284            .ArgConstraint(ArgumentCondition(1, WithinRange, Range(0, IntMax)))2285            .ArgConstraint(2286                BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1)))2287            .ArgConstraint(NotNull(ArgNo(2))));2288 2289    // int fputs(const char *restrict s, FILE *restrict stream);2290    addToFunctionSummaryMap(2291        "fputs",2292        Signature(ArgTypes{ConstCharPtrRestrictTy, FilePtrRestrictTy},2293                  RetType{IntTy}),2294        Summary(NoEvalCall)2295            .Case(ReturnsNonnegative, ErrnoMustNotBeChecked, GenericSuccessMsg)2296            .Case({ReturnValueCondition(WithinRange, SingleValue(EOFv))},2297                  ErrnoNEZeroIrrelevant, GenericFailureMsg)2298            .ArgConstraint(NotNull(ArgNo(0)))2299            .ArgConstraint(NotNull(ArgNo(1))));2300 2301    // int ungetc(int c, FILE *stream);2302    addToFunctionSummaryMap(2303        "ungetc", Signature(ArgTypes{IntTy, FilePtrTy}, RetType{IntTy}),2304        Summary(NoEvalCall)2305            .Case({ReturnValueCondition(BO_EQ, ArgNo(0)),2306                   ArgumentCondition(0, WithinRange, {{0, UCharRangeMax}})},2307                  ErrnoMustNotBeChecked, GenericSuccessMsg)2308            .Case({ReturnValueCondition(WithinRange, SingleValue(EOFv)),2309                   ArgumentCondition(0, WithinRange, SingleValue(EOFv))},2310                  ErrnoNEZeroIrrelevant,2311                  "Assuming that 'ungetc' fails because EOF was passed as "2312                  "character")2313            .Case({ReturnValueCondition(WithinRange, SingleValue(EOFv)),2314                   ArgumentCondition(0, WithinRange, {{0, UCharRangeMax}})},2315                  ErrnoNEZeroIrrelevant, GenericFailureMsg)2316            .ArgConstraint(ArgumentCondition(2317                0, WithinRange, {{EOFv, EOFv}, {0, UCharRangeMax}}))2318            .ArgConstraint(NotNull(ArgNo(1))));2319 2320    // int fseek(FILE *stream, long offset, int whence);2321    // FIXME: It can be possible to get the 'SEEK_' values (like EOFv) and use2322    // these for condition of arg 2.2323    // Now the range [0,2] is used (the `SEEK_*` constants are usually 0,1,2).2324    addToFunctionSummaryMap(2325        "fseek", Signature(ArgTypes{FilePtrTy, LongTy, IntTy}, RetType{IntTy}),2326        Summary(NoEvalCall)2327            .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)2328            .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)2329            .ArgConstraint(NotNull(ArgNo(0)))2330            .ArgConstraint(ArgumentCondition(2, WithinRange, {{0, 2}})));2331 2332    // int fseeko(FILE *stream, off_t offset, int whence);2333    addToFunctionSummaryMap(2334        "fseeko",2335        Signature(ArgTypes{FilePtrTy, Off_tTy, IntTy}, RetType{IntTy}),2336        Summary(NoEvalCall)2337            .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)2338            .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)2339            .ArgConstraint(NotNull(ArgNo(0)))2340            .ArgConstraint(ArgumentCondition(2, WithinRange, {{0, 2}})));2341 2342    // int fgetpos(FILE *restrict stream, fpos_t *restrict pos);2343    // From 'The Open Group Base Specifications Issue 7, 2018 edition':2344    // "The fgetpos() function shall not change the setting of errno if2345    // successful."2346    addToFunctionSummaryMap(2347        "fgetpos",2348        Signature(ArgTypes{FilePtrRestrictTy, FPosTPtrRestrictTy},2349                  RetType{IntTy}),2350        Summary(NoEvalCall)2351            .Case(ReturnsZero, ErrnoUnchanged, GenericSuccessMsg)2352            .Case(ReturnsNonZero, ErrnoNEZeroIrrelevant, GenericFailureMsg)2353            .ArgConstraint(NotNull(ArgNo(0)))2354            .ArgConstraint(NotNull(ArgNo(1))));2355 2356    // int fsetpos(FILE *stream, const fpos_t *pos);2357    // From 'The Open Group Base Specifications Issue 7, 2018 edition':2358    // "The fsetpos() function shall not change the setting of errno if2359    // successful."2360    addToFunctionSummaryMap(2361        "fsetpos",2362        Signature(ArgTypes{FilePtrTy, ConstFPosTPtrTy}, RetType{IntTy}),2363        Summary(NoEvalCall)2364            .Case(ReturnsZero, ErrnoUnchanged, GenericSuccessMsg)2365            .Case(ReturnsNonZero, ErrnoNEZeroIrrelevant, GenericFailureMsg)2366            .ArgConstraint(NotNull(ArgNo(0)))2367            .ArgConstraint(NotNull(ArgNo(1))));2368 2369    // int fflush(FILE *stream);2370    addToFunctionSummaryMap(2371        "fflush", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),2372        Summary(NoEvalCall)2373            .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)2374            .Case(ReturnsEOF, ErrnoNEZeroIrrelevant, GenericFailureMsg));2375 2376    // long ftell(FILE *stream);2377    // From 'The Open Group Base Specifications Issue 7, 2018 edition':2378    // "The ftell() function shall not change the setting of errno if2379    // successful."2380    addToFunctionSummaryMap(2381        "ftell", Signature(ArgTypes{FilePtrTy}, RetType{LongTy}),2382        Summary(NoEvalCall)2383            .Case({ReturnValueCondition(WithinRange, Range(0, LongMax))},2384                  ErrnoUnchanged, GenericSuccessMsg)2385            .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)2386            .ArgConstraint(NotNull(ArgNo(0))));2387 2388    // off_t ftello(FILE *stream);2389    addToFunctionSummaryMap(2390        "ftello", Signature(ArgTypes{FilePtrTy}, RetType{Off_tTy}),2391        Summary(NoEvalCall)2392            .Case({ReturnValueCondition(WithinRange, Range(0, Off_tMax))},2393                  ErrnoMustNotBeChecked, GenericSuccessMsg)2394            .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)2395            .ArgConstraint(NotNull(ArgNo(0))));2396 2397    // int fileno(FILE *stream);2398    // According to POSIX 'fileno' may fail and set 'errno'.2399    // But in Linux it may fail only if the specified file pointer is invalid.2400    // At many places 'fileno' is used without check for failure and a failure2401    // case here would produce a large amount of likely false positive warnings.2402    // To avoid this, we assume here that it does not fail.2403    addToFunctionSummaryMap(2404        "fileno", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),2405        Summary(NoEvalCall)2406            .Case(ReturnsValidFileDescriptor, ErrnoUnchanged, GenericSuccessMsg)2407            .ArgConstraint(NotNull(ArgNo(0))));2408 2409    // void rewind(FILE *stream);2410    // This function indicates error only by setting of 'errno'.2411    addToFunctionSummaryMap("rewind",2412                            Signature(ArgTypes{FilePtrTy}, RetType{VoidTy}),2413                            Summary(NoEvalCall)2414                                .Case({}, ErrnoMustBeChecked)2415                                .ArgConstraint(NotNull(ArgNo(0))));2416 2417    // void clearerr(FILE *stream);2418    addToFunctionSummaryMap(2419        "clearerr", Signature(ArgTypes{FilePtrTy}, RetType{VoidTy}),2420        Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));2421 2422    // int feof(FILE *stream);2423    addToFunctionSummaryMap(2424        "feof", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),2425        Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));2426 2427    // int ferror(FILE *stream);2428    addToFunctionSummaryMap(2429        "ferror", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),2430        Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));2431 2432    // long a64l(const char *str64);2433    addToFunctionSummaryMap(2434        "a64l", Signature(ArgTypes{ConstCharPtrTy}, RetType{LongTy}),2435        Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));2436 2437    // char *l64a(long value);2438    addToFunctionSummaryMap("l64a",2439                            Signature(ArgTypes{LongTy}, RetType{CharPtrTy}),2440                            Summary(NoEvalCall)2441                                .ArgConstraint(ArgumentCondition(2442                                    0, WithinRange, Range(0, LongMax))));2443 2444    // int open(const char *path, int oflag, ...);2445    addToFunctionSummaryMap(2446        "open", Signature(ArgTypes{ConstCharPtrTy, IntTy}, RetType{IntTy}),2447        Summary(NoEvalCall)2448            .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked,2449                  GenericSuccessMsg)2450            .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)2451            .ArgConstraint(NotNull(ArgNo(0))));2452 2453    // int openat(int fd, const char *path, int oflag, ...);2454    addToFunctionSummaryMap(2455        "openat",2456        Signature(ArgTypes{IntTy, ConstCharPtrTy, IntTy}, RetType{IntTy}),2457        Summary(NoEvalCall)2458            .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked,2459                  GenericSuccessMsg)2460            .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)2461            .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))2462            .ArgConstraint(NotNull(ArgNo(1))));2463 2464    // int access(const char *pathname, int amode);2465    addToFunctionSummaryMap(2466        "access", Signature(ArgTypes{ConstCharPtrTy, IntTy}, RetType{IntTy}),2467        Summary(NoEvalCall)2468            .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)2469            .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)2470            .ArgConstraint(NotNull(ArgNo(0))));2471 2472    // int faccessat(int dirfd, const char *pathname, int mode, int flags);2473    addToFunctionSummaryMap(2474        "faccessat",2475        Signature(ArgTypes{IntTy, ConstCharPtrTy, IntTy, IntTy},2476                  RetType{IntTy}),2477        Summary(NoEvalCall)2478            .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)2479            .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)2480            .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))2481            .ArgConstraint(NotNull(ArgNo(1))));2482 2483    // int dup(int fildes);2484    addToFunctionSummaryMap(2485        "dup", Signature(ArgTypes{IntTy}, RetType{IntTy}),2486        Summary(NoEvalCall)2487            .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked,2488                  GenericSuccessMsg)2489            .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)2490            .ArgConstraint(2491                ArgumentCondition(0, WithinRange, Range(0, IntMax))));2492 2493    // int dup2(int fildes1, int filedes2);2494    addToFunctionSummaryMap(2495        "dup2", Signature(ArgTypes{IntTy, IntTy}, RetType{IntTy}),2496        Summary(NoEvalCall)2497            .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked,2498                  GenericSuccessMsg)2499            .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)2500            .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))2501            .ArgConstraint(2502                ArgumentCondition(1, WithinRange, Range(0, IntMax))));2503 2504    // int fdatasync(int fildes);2505    addToFunctionSummaryMap(2506        "fdatasync", Signature(ArgTypes{IntTy}, RetType{IntTy}),2507        Summary(NoEvalCall)2508            .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)2509            .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)2510            .ArgConstraint(2511                ArgumentCondition(0, WithinRange, Range(0, IntMax))));2512 2513    // int fnmatch(const char *pattern, const char *string, int flags);2514    addToFunctionSummaryMap(2515        "fnmatch",2516        Signature(ArgTypes{ConstCharPtrTy, ConstCharPtrTy, IntTy},2517                  RetType{IntTy}),2518        Summary(NoEvalCall)2519            .ArgConstraint(NotNull(ArgNo(0)))2520            .ArgConstraint(NotNull(ArgNo(1))));2521 2522    // int fsync(int fildes);2523    addToFunctionSummaryMap(2524        "fsync", Signature(ArgTypes{IntTy}, RetType{IntTy}),2525        Summary(NoEvalCall)2526            .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)2527            .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)2528            .ArgConstraint(2529                ArgumentCondition(0, WithinRange, Range(0, IntMax))));2530 2531    // int truncate(const char *path, off_t length);2532    addToFunctionSummaryMap(2533        "truncate",2534        Signature(ArgTypes{ConstCharPtrTy, Off_tTy}, RetType{IntTy}),2535        Summary(NoEvalCall)2536            .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)2537            .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)2538            .ArgConstraint(NotNull(ArgNo(0))));2539 2540    // int symlink(const char *oldpath, const char *newpath);2541    addToFunctionSummaryMap(2542        "symlink",2543        Signature(ArgTypes{ConstCharPtrTy, ConstCharPtrTy}, RetType{IntTy}),2544        Summary(NoEvalCall)2545            .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)2546            .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)2547            .ArgConstraint(NotNull(ArgNo(0)))2548            .ArgConstraint(NotNull(ArgNo(1))));2549 2550    // int symlinkat(const char *oldpath, int newdirfd, const char *newpath);2551    addToFunctionSummaryMap(2552        "symlinkat",2553        Signature(ArgTypes{ConstCharPtrTy, IntTy, ConstCharPtrTy},2554                  RetType{IntTy}),2555        Summary(NoEvalCall)2556            .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)2557            .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)2558            .ArgConstraint(NotNull(ArgNo(0)))2559            .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(1)))2560            .ArgConstraint(NotNull(ArgNo(2))));2561 2562    // int lockf(int fd, int cmd, off_t len);2563    addToFunctionSummaryMap(2564        "lockf", Signature(ArgTypes{IntTy, IntTy, Off_tTy}, RetType{IntTy}),2565        Summary(NoEvalCall)2566            .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)2567            .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)2568            .ArgConstraint(2569                ArgumentCondition(0, WithinRange, Range(0, IntMax))));2570 2571    std::optional<QualType> Mode_tTy = lookupTy("mode_t");2572 2573    // int creat(const char *pathname, mode_t mode);2574    addToFunctionSummaryMap(2575        "creat", Signature(ArgTypes{ConstCharPtrTy, Mode_tTy}, RetType{IntTy}),2576        Summary(NoEvalCall)2577            .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked,2578                  GenericSuccessMsg)2579            .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)2580            .ArgConstraint(NotNull(ArgNo(0))));2581 2582    // unsigned int sleep(unsigned int seconds);2583    addToFunctionSummaryMap(2584        "sleep", Signature(ArgTypes{UnsignedIntTy}, RetType{UnsignedIntTy}),2585        Summary(NoEvalCall)2586            .ArgConstraint(2587                ArgumentCondition(0, WithinRange, Range(0, UnsignedIntMax))));2588 2589    std::optional<QualType> DirTy = lookupTy("DIR");2590    std::optional<QualType> DirPtrTy = getPointerTy(DirTy);2591 2592    // int dirfd(DIR *dirp);2593    addToFunctionSummaryMap(2594        "dirfd", Signature(ArgTypes{DirPtrTy}, RetType{IntTy}),2595        Summary(NoEvalCall)2596            .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked,2597                  GenericSuccessMsg)2598            .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)2599            .ArgConstraint(NotNull(ArgNo(0))));2600 2601    // unsigned int alarm(unsigned int seconds);2602    addToFunctionSummaryMap(2603        "alarm", Signature(ArgTypes{UnsignedIntTy}, RetType{UnsignedIntTy}),2604        Summary(NoEvalCall)2605            .ArgConstraint(2606                ArgumentCondition(0, WithinRange, Range(0, UnsignedIntMax))));2607 2608    // int closedir(DIR *dir);2609    addToFunctionSummaryMap(2610        "closedir", Signature(ArgTypes{DirPtrTy}, RetType{IntTy}),2611        Summary(NoEvalCall)2612            .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)2613            .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)2614            .ArgConstraint(NotNull(ArgNo(0))));2615 2616    // char *strdup(const char *s);2617    addToFunctionSummaryMap(2618        "strdup", Signature(ArgTypes{ConstCharPtrTy}, RetType{CharPtrTy}),2619        Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));2620 2621    // char *strndup(const char *s, size_t n);2622    addToFunctionSummaryMap(2623        "strndup",2624        Signature(ArgTypes{ConstCharPtrTy, SizeTyCanonTy}, RetType{CharPtrTy}),2625        Summary(NoEvalCall)2626            .ArgConstraint(NotNull(ArgNo(0)))2627            .ArgConstraint(2628                ArgumentCondition(1, WithinRange, Range(0, SizeMax))));2629 2630    // wchar_t *wcsdup(const wchar_t *s);2631    addToFunctionSummaryMap(2632        "wcsdup", Signature(ArgTypes{ConstWchar_tPtrTy}, RetType{Wchar_tPtrTy}),2633        Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));2634 2635    // int mkstemp(char *template);2636    addToFunctionSummaryMap(2637        "mkstemp", Signature(ArgTypes{CharPtrTy}, RetType{IntTy}),2638        Summary(NoEvalCall)2639            .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked,2640                  GenericSuccessMsg)2641            .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)2642            .ArgConstraint(NotNull(ArgNo(0))));2643 2644    // char *mkdtemp(char *template);2645    addToFunctionSummaryMap(2646        "mkdtemp", Signature(ArgTypes{CharPtrTy}, RetType{CharPtrTy}),2647        Summary(NoEvalCall)2648            .Case({ReturnValueCondition(BO_EQ, ArgNo(0))},2649                  ErrnoMustNotBeChecked, GenericSuccessMsg)2650            .Case({IsNull(Ret)}, ErrnoNEZeroIrrelevant, GenericFailureMsg)2651            .ArgConstraint(NotNull(ArgNo(0))));2652 2653    // char *getcwd(char *buf, size_t size);2654    addToFunctionSummaryMap(2655        "getcwd",2656        Signature(ArgTypes{CharPtrTy, SizeTyCanonTy}, RetType{CharPtrTy}),2657        Summary(NoEvalCall)2658            .Case({NotNull(0),2659                   ArgumentCondition(1, WithinRange, Range(1, SizeMax)),2660                   ReturnValueCondition(BO_EQ, ArgNo(0))},2661                  ErrnoMustNotBeChecked, GenericSuccessMsg)2662            .Case({NotNull(0),2663                   ArgumentCondition(1, WithinRange, SingleValue(0)),2664                   IsNull(Ret)},2665                  ErrnoNEZeroIrrelevant, "Assuming that argument 'size' is 0")2666            .Case({NotNull(0),2667                   ArgumentCondition(1, WithinRange, Range(1, SizeMax)),2668                   IsNull(Ret)},2669                  ErrnoNEZeroIrrelevant, GenericFailureMsg)2670            .Case({IsNull(0), NotNull(Ret)}, ErrnoMustNotBeChecked,2671                  GenericSuccessMsg)2672            .Case({IsNull(0), IsNull(Ret)}, ErrnoNEZeroIrrelevant,2673                  GenericFailureMsg)2674            .ArgConstraint(2675                BufferSize(/*Buffer*/ ArgNo(0), /*BufSize*/ ArgNo(1)))2676            .ArgConstraint(2677                ArgumentCondition(1, WithinRange, Range(0, SizeMax))));2678 2679    // int mkdir(const char *pathname, mode_t mode);2680    addToFunctionSummaryMap(2681        "mkdir", Signature(ArgTypes{ConstCharPtrTy, Mode_tTy}, RetType{IntTy}),2682        Summary(NoEvalCall)2683            .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)2684            .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)2685            .ArgConstraint(NotNull(ArgNo(0))));2686 2687    // int mkdirat(int dirfd, const char *pathname, mode_t mode);2688    addToFunctionSummaryMap(2689        "mkdirat",2690        Signature(ArgTypes{IntTy, ConstCharPtrTy, Mode_tTy}, RetType{IntTy}),2691        Summary(NoEvalCall)2692            .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)2693            .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)2694            .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))2695            .ArgConstraint(NotNull(ArgNo(1))));2696 2697    std::optional<QualType> Dev_tTy = lookupTy("dev_t");2698 2699    // int mknod(const char *pathname, mode_t mode, dev_t dev);2700    addToFunctionSummaryMap(2701        "mknod",2702        Signature(ArgTypes{ConstCharPtrTy, Mode_tTy, Dev_tTy}, RetType{IntTy}),2703        Summary(NoEvalCall)2704            .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)2705            .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)2706            .ArgConstraint(NotNull(ArgNo(0))));2707 2708    // int mknodat(int dirfd, const char *pathname, mode_t mode, dev_t dev);2709    addToFunctionSummaryMap(2710        "mknodat",2711        Signature(ArgTypes{IntTy, ConstCharPtrTy, Mode_tTy, Dev_tTy},2712                  RetType{IntTy}),2713        Summary(NoEvalCall)2714            .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)2715            .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)2716            .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))2717            .ArgConstraint(NotNull(ArgNo(1))));2718 2719    // int chmod(const char *path, mode_t mode);2720    addToFunctionSummaryMap(2721        "chmod", Signature(ArgTypes{ConstCharPtrTy, Mode_tTy}, RetType{IntTy}),2722        Summary(NoEvalCall)2723            .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)2724            .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)2725            .ArgConstraint(NotNull(ArgNo(0))));2726 2727    // int fchmodat(int dirfd, const char *pathname, mode_t mode, int flags);2728    addToFunctionSummaryMap(2729        "fchmodat",2730        Signature(ArgTypes{IntTy, ConstCharPtrTy, Mode_tTy, IntTy},2731                  RetType{IntTy}),2732        Summary(NoEvalCall)2733            .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)2734            .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)2735            .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))2736            .ArgConstraint(NotNull(ArgNo(1))));2737 2738    // int fchmod(int fildes, mode_t mode);2739    addToFunctionSummaryMap(2740        "fchmod", Signature(ArgTypes{IntTy, Mode_tTy}, RetType{IntTy}),2741        Summary(NoEvalCall)2742            .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)2743            .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)2744            .ArgConstraint(2745                ArgumentCondition(0, WithinRange, Range(0, IntMax))));2746 2747    std::optional<QualType> Uid_tTy = lookupTy("uid_t");2748    std::optional<QualType> Gid_tTy = lookupTy("gid_t");2749 2750    // int fchownat(int dirfd, const char *pathname, uid_t owner, gid_t group,2751    //              int flags);2752    addToFunctionSummaryMap(2753        "fchownat",2754        Signature(ArgTypes{IntTy, ConstCharPtrTy, Uid_tTy, Gid_tTy, IntTy},2755                  RetType{IntTy}),2756        Summary(NoEvalCall)2757            .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)2758            .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)2759            .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))2760            .ArgConstraint(NotNull(ArgNo(1))));2761 2762    // int chown(const char *path, uid_t owner, gid_t group);2763    addToFunctionSummaryMap(2764        "chown",2765        Signature(ArgTypes{ConstCharPtrTy, Uid_tTy, Gid_tTy}, RetType{IntTy}),2766        Summary(NoEvalCall)2767            .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)2768            .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)2769            .ArgConstraint(NotNull(ArgNo(0))));2770 2771    // int lchown(const char *path, uid_t owner, gid_t group);2772    addToFunctionSummaryMap(2773        "lchown",2774        Signature(ArgTypes{ConstCharPtrTy, Uid_tTy, Gid_tTy}, RetType{IntTy}),2775        Summary(NoEvalCall)2776            .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)2777            .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)2778            .ArgConstraint(NotNull(ArgNo(0))));2779 2780    // int fchown(int fildes, uid_t owner, gid_t group);2781    addToFunctionSummaryMap(2782        "fchown", Signature(ArgTypes{IntTy, Uid_tTy, Gid_tTy}, RetType{IntTy}),2783        Summary(NoEvalCall)2784            .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)2785            .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)2786            .ArgConstraint(2787                ArgumentCondition(0, WithinRange, Range(0, IntMax))));2788 2789    // int rmdir(const char *pathname);2790    addToFunctionSummaryMap(2791        "rmdir", Signature(ArgTypes{ConstCharPtrTy}, RetType{IntTy}),2792        Summary(NoEvalCall)2793            .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)2794            .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)2795            .ArgConstraint(NotNull(ArgNo(0))));2796 2797    // int chdir(const char *path);2798    addToFunctionSummaryMap(2799        "chdir", Signature(ArgTypes{ConstCharPtrTy}, RetType{IntTy}),2800        Summary(NoEvalCall)2801            .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)2802            .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)2803            .ArgConstraint(NotNull(ArgNo(0))));2804 2805    // int link(const char *oldpath, const char *newpath);2806    addToFunctionSummaryMap(2807        "link",2808        Signature(ArgTypes{ConstCharPtrTy, ConstCharPtrTy}, RetType{IntTy}),2809        Summary(NoEvalCall)2810            .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)2811            .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)2812            .ArgConstraint(NotNull(ArgNo(0)))2813            .ArgConstraint(NotNull(ArgNo(1))));2814 2815    // int linkat(int fd1, const char *path1, int fd2, const char *path2,2816    //            int flag);2817    addToFunctionSummaryMap(2818        "linkat",2819        Signature(ArgTypes{IntTy, ConstCharPtrTy, IntTy, ConstCharPtrTy, IntTy},2820                  RetType{IntTy}),2821        Summary(NoEvalCall)2822            .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)2823            .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)2824            .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))2825            .ArgConstraint(NotNull(ArgNo(1)))2826            .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(2)))2827            .ArgConstraint(NotNull(ArgNo(3))));2828 2829    // int unlink(const char *pathname);2830    addToFunctionSummaryMap(2831        "unlink", Signature(ArgTypes{ConstCharPtrTy}, RetType{IntTy}),2832        Summary(NoEvalCall)2833            .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)2834            .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)2835            .ArgConstraint(NotNull(ArgNo(0))));2836 2837    // int unlinkat(int fd, const char *path, int flag);2838    addToFunctionSummaryMap(2839        "unlinkat",2840        Signature(ArgTypes{IntTy, ConstCharPtrTy, IntTy}, RetType{IntTy}),2841        Summary(NoEvalCall)2842            .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)2843            .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)2844            .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))2845            .ArgConstraint(NotNull(ArgNo(1))));2846 2847    std::optional<QualType> StructStatTy = lookupTy("stat");2848    std::optional<QualType> StructStatPtrTy = getPointerTy(StructStatTy);2849    std::optional<QualType> StructStatPtrRestrictTy =2850        getRestrictTy(StructStatPtrTy);2851 2852    // int fstat(int fd, struct stat *statbuf);2853    addToFunctionSummaryMap(2854        "fstat", Signature(ArgTypes{IntTy, StructStatPtrTy}, RetType{IntTy}),2855        Summary(NoEvalCall)2856            .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)2857            .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)2858            .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))2859            .ArgConstraint(NotNull(ArgNo(1))));2860 2861    // int stat(const char *restrict path, struct stat *restrict buf);2862    addToFunctionSummaryMap(2863        "stat",2864        Signature(ArgTypes{ConstCharPtrRestrictTy, StructStatPtrRestrictTy},2865                  RetType{IntTy}),2866        Summary(NoEvalCall)2867            .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)2868            .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)2869            .ArgConstraint(NotNull(ArgNo(0)))2870            .ArgConstraint(NotNull(ArgNo(1))));2871 2872    // int lstat(const char *restrict path, struct stat *restrict buf);2873    addToFunctionSummaryMap(2874        "lstat",2875        Signature(ArgTypes{ConstCharPtrRestrictTy, StructStatPtrRestrictTy},2876                  RetType{IntTy}),2877        Summary(NoEvalCall)2878            .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)2879            .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)2880            .ArgConstraint(NotNull(ArgNo(0)))2881            .ArgConstraint(NotNull(ArgNo(1))));2882 2883    // int fstatat(int fd, const char *restrict path,2884    //             struct stat *restrict buf, int flag);2885    addToFunctionSummaryMap(2886        "fstatat",2887        Signature(ArgTypes{IntTy, ConstCharPtrRestrictTy,2888                           StructStatPtrRestrictTy, IntTy},2889                  RetType{IntTy}),2890        Summary(NoEvalCall)2891            .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)2892            .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)2893            .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))2894            .ArgConstraint(NotNull(ArgNo(1)))2895            .ArgConstraint(NotNull(ArgNo(2))));2896 2897    // DIR *opendir(const char *name);2898    addToFunctionSummaryMap(2899        "opendir", Signature(ArgTypes{ConstCharPtrTy}, RetType{DirPtrTy}),2900        Summary(NoEvalCall)2901            .Case({NotNull(Ret)}, ErrnoMustNotBeChecked, GenericSuccessMsg)2902            .Case({IsNull(Ret)}, ErrnoNEZeroIrrelevant, GenericFailureMsg)2903            .ArgConstraint(NotNull(ArgNo(0))));2904 2905    // DIR *fdopendir(int fd);2906    addToFunctionSummaryMap(2907        "fdopendir", Signature(ArgTypes{IntTy}, RetType{DirPtrTy}),2908        Summary(NoEvalCall)2909            .Case({NotNull(Ret)}, ErrnoMustNotBeChecked, GenericSuccessMsg)2910            .Case({IsNull(Ret)}, ErrnoNEZeroIrrelevant, GenericFailureMsg)2911            .ArgConstraint(2912                ArgumentCondition(0, WithinRange, Range(0, IntMax))));2913 2914    // int isatty(int fildes);2915    addToFunctionSummaryMap(2916        "isatty", Signature(ArgTypes{IntTy}, RetType{IntTy}),2917        Summary(NoEvalCall)2918            .Case({ReturnValueCondition(WithinRange, Range(0, 1))},2919                  ErrnoIrrelevant)2920            .ArgConstraint(2921                ArgumentCondition(0, WithinRange, Range(0, IntMax))));2922 2923    // int close(int fildes);2924    addToFunctionSummaryMap(2925        "close", Signature(ArgTypes{IntTy}, RetType{IntTy}),2926        Summary(NoEvalCall)2927            .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)2928            .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)2929            .ArgConstraint(2930                ArgumentCondition(0, WithinRange, Range(-1, IntMax))));2931 2932    // long fpathconf(int fildes, int name);2933    addToFunctionSummaryMap("fpathconf",2934                            Signature(ArgTypes{IntTy, IntTy}, RetType{LongTy}),2935                            Summary(NoEvalCall)2936                                .ArgConstraint(ArgumentCondition(2937                                    0, WithinRange, Range(0, IntMax))));2938 2939    // long pathconf(const char *path, int name);2940    addToFunctionSummaryMap(2941        "pathconf", Signature(ArgTypes{ConstCharPtrTy, IntTy}, RetType{LongTy}),2942        Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));2943 2944    // void rewinddir(DIR *dir);2945    addToFunctionSummaryMap(2946        "rewinddir", Signature(ArgTypes{DirPtrTy}, RetType{VoidTy}),2947        Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));2948 2949    // void seekdir(DIR *dirp, long loc);2950    addToFunctionSummaryMap(2951        "seekdir", Signature(ArgTypes{DirPtrTy, LongTy}, RetType{VoidTy}),2952        Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));2953 2954    // int rand_r(unsigned int *seedp);2955    addToFunctionSummaryMap(2956        "rand_r", Signature(ArgTypes{UnsignedIntPtrTy}, RetType{IntTy}),2957        Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));2958 2959    // void *mmap(void *addr, size_t length, int prot, int flags, int fd,2960    // off_t offset);2961    // FIXME: Improve for errno modeling.2962    addToFunctionSummaryMap(2963        "mmap",2964        Signature(2965            ArgTypes{VoidPtrTy, SizeTyCanonTy, IntTy, IntTy, IntTy, Off_tTy},2966            RetType{VoidPtrTy}),2967        Summary(NoEvalCall)2968            .ArgConstraint(ArgumentCondition(1, WithinRange, Range(1, SizeMax)))2969            .ArgConstraint(2970                ArgumentCondition(4, WithinRange, Range(-1, IntMax))));2971 2972    std::optional<QualType> Off64_tTy = lookupTy("off64_t");2973    // void *mmap64(void *addr, size_t length, int prot, int flags, int fd,2974    // off64_t offset);2975    // FIXME: Improve for errno modeling.2976    addToFunctionSummaryMap(2977        "mmap64",2978        Signature(2979            ArgTypes{VoidPtrTy, SizeTyCanonTy, IntTy, IntTy, IntTy, Off64_tTy},2980            RetType{VoidPtrTy}),2981        Summary(NoEvalCall)2982            .ArgConstraint(ArgumentCondition(1, WithinRange, Range(1, SizeMax)))2983            .ArgConstraint(2984                ArgumentCondition(4, WithinRange, Range(-1, IntMax))));2985 2986    // int pipe(int fildes[2]);2987    addToFunctionSummaryMap(2988        "pipe", Signature(ArgTypes{IntPtrTy}, RetType{IntTy}),2989        Summary(NoEvalCall)2990            .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)2991            .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)2992            .ArgConstraint(NotNull(ArgNo(0))));2993 2994    // off_t lseek(int fildes, off_t offset, int whence);2995    // In the first case we can not tell for sure if it failed or not.2996    // A return value different from of the expected offset (that is unknown2997    // here) may indicate failure. For this reason we do not enforce the errno2998    // check (can cause false positive).2999    addToFunctionSummaryMap(3000        "lseek", Signature(ArgTypes{IntTy, Off_tTy, IntTy}, RetType{Off_tTy}),3001        Summary(NoEvalCall)3002            .Case(ReturnsNonnegative, ErrnoIrrelevant)3003            .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)3004            .ArgConstraint(3005                ArgumentCondition(0, WithinRange, Range(0, IntMax))));3006 3007    // ssize_t readlink(const char *restrict path, char *restrict buf,3008    //                  size_t bufsize);3009    addToFunctionSummaryMap(3010        "readlink",3011        Signature(3012            ArgTypes{ConstCharPtrRestrictTy, CharPtrRestrictTy, SizeTyCanonTy},3013            RetType{Ssize_tTy}),3014        Summary(NoEvalCall)3015            .Case({ArgumentCondition(2, WithinRange, Range(1, IntMax)),3016                   ReturnValueCondition(LessThanOrEq, ArgNo(2)),3017                   ReturnValueCondition(WithinRange, Range(1, Ssize_tMax))},3018                  ErrnoMustNotBeChecked, GenericSuccessMsg)3019            .Case({ArgumentCondition(2, WithinRange, SingleValue(0)),3020                   ReturnValueCondition(WithinRange, SingleValue(0))},3021                  ErrnoMustNotBeChecked,3022                  "Assuming that argument 'bufsize' is 0")3023            .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)3024            .ArgConstraint(NotNull(ArgNo(0)))3025            .ArgConstraint(NotNull(ArgNo(1)))3026            .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),3027                                      /*BufSize=*/ArgNo(2)))3028            .ArgConstraint(3029                ArgumentCondition(2, WithinRange, Range(0, SizeMax))));3030 3031    // ssize_t readlinkat(int fd, const char *restrict path,3032    //                    char *restrict buf, size_t bufsize);3033    addToFunctionSummaryMap(3034        "readlinkat",3035        Signature(ArgTypes{IntTy, ConstCharPtrRestrictTy, CharPtrRestrictTy,3036                           SizeTyCanonTy},3037                  RetType{Ssize_tTy}),3038        Summary(NoEvalCall)3039            .Case({ArgumentCondition(3, WithinRange, Range(1, IntMax)),3040                   ReturnValueCondition(LessThanOrEq, ArgNo(3)),3041                   ReturnValueCondition(WithinRange, Range(1, Ssize_tMax))},3042                  ErrnoMustNotBeChecked, GenericSuccessMsg)3043            .Case({ArgumentCondition(3, WithinRange, SingleValue(0)),3044                   ReturnValueCondition(WithinRange, SingleValue(0))},3045                  ErrnoMustNotBeChecked,3046                  "Assuming that argument 'bufsize' is 0")3047            .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)3048            .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))3049            .ArgConstraint(NotNull(ArgNo(1)))3050            .ArgConstraint(NotNull(ArgNo(2)))3051            .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(2),3052                                      /*BufSize=*/ArgNo(3)))3053            .ArgConstraint(3054                ArgumentCondition(3, WithinRange, Range(0, SizeMax))));3055 3056    // int renameat(int olddirfd, const char *oldpath, int newdirfd, const char3057    // *newpath);3058    addToFunctionSummaryMap(3059        "renameat",3060        Signature(ArgTypes{IntTy, ConstCharPtrTy, IntTy, ConstCharPtrTy},3061                  RetType{IntTy}),3062        Summary(NoEvalCall)3063            .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)3064            .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)3065            .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))3066            .ArgConstraint(NotNull(ArgNo(1)))3067            .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(2)))3068            .ArgConstraint(NotNull(ArgNo(3))));3069 3070    // char *realpath(const char *restrict file_name,3071    //                char *restrict resolved_name);3072    // FIXME: If the argument 'resolved_name' is not NULL, macro 'PATH_MAX'3073    //        should be defined in "limits.h" to guarrantee a success.3074    addToFunctionSummaryMap(3075        "realpath",3076        Signature(ArgTypes{ConstCharPtrRestrictTy, CharPtrRestrictTy},3077                  RetType{CharPtrTy}),3078        Summary(NoEvalCall)3079            .Case({NotNull(Ret)}, ErrnoMustNotBeChecked, GenericSuccessMsg)3080            .Case({IsNull(Ret)}, ErrnoNEZeroIrrelevant, GenericFailureMsg)3081            .ArgConstraint(NotNull(ArgNo(0))));3082 3083    QualType CharPtrConstPtr = getPointerTy(getConstTy(CharPtrTy));3084 3085    // int execv(const char *path, char *const argv[]);3086    addToFunctionSummaryMap(3087        "execv",3088        Signature(ArgTypes{ConstCharPtrTy, CharPtrConstPtr}, RetType{IntTy}),3089        Summary(NoEvalCall)3090            .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)3091            .ArgConstraint(NotNull(ArgNo(0))));3092 3093    // int execvp(const char *file, char *const argv[]);3094    addToFunctionSummaryMap(3095        "execvp",3096        Signature(ArgTypes{ConstCharPtrTy, CharPtrConstPtr}, RetType{IntTy}),3097        Summary(NoEvalCall)3098            .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)3099            .ArgConstraint(NotNull(ArgNo(0))));3100 3101    // int getopt(int argc, char * const argv[], const char *optstring);3102    addToFunctionSummaryMap(3103        "getopt",3104        Signature(ArgTypes{IntTy, CharPtrConstPtr, ConstCharPtrTy},3105                  RetType{IntTy}),3106        Summary(NoEvalCall)3107            .Case({ReturnValueCondition(WithinRange, Range(-1, UCharRangeMax))},3108                  ErrnoIrrelevant)3109            .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))3110            .ArgConstraint(NotNull(ArgNo(1)))3111            .ArgConstraint(NotNull(ArgNo(2))));3112 3113    std::optional<QualType> StructSockaddrTy = lookupTy("sockaddr");3114    std::optional<QualType> StructSockaddrPtrTy =3115        getPointerTy(StructSockaddrTy);3116    std::optional<QualType> ConstStructSockaddrPtrTy =3117        getPointerTy(getConstTy(StructSockaddrTy));3118    std::optional<QualType> StructSockaddrPtrRestrictTy =3119        getRestrictTy(StructSockaddrPtrTy);3120    std::optional<QualType> ConstStructSockaddrPtrRestrictTy =3121        getRestrictTy(ConstStructSockaddrPtrTy);3122    std::optional<QualType> Socklen_tTy = lookupTy("socklen_t");3123    std::optional<QualType> Socklen_tPtrTy = getPointerTy(Socklen_tTy);3124    std::optional<QualType> Socklen_tPtrRestrictTy =3125        getRestrictTy(Socklen_tPtrTy);3126    std::optional<RangeInt> Socklen_tMax = getMaxValue(Socklen_tTy);3127 3128    // In 'socket.h' of some libc implementations with C99, sockaddr parameter3129    // is a transparent union of the underlying sockaddr_ family of pointers3130    // instead of being a pointer to struct sockaddr. In these cases, the3131    // standardized signature will not match, thus we try to match with another3132    // signature that has the joker Irrelevant type. We also remove those3133    // constraints which require pointer types for the sockaddr param.3134 3135    // int socket(int domain, int type, int protocol);3136    addToFunctionSummaryMap(3137        "socket", Signature(ArgTypes{IntTy, IntTy, IntTy}, RetType{IntTy}),3138        Summary(NoEvalCall)3139            .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked,3140                  GenericSuccessMsg)3141            .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg));3142 3143    auto Accept =3144        Summary(NoEvalCall)3145            .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked,3146                  GenericSuccessMsg)3147            .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)3148            .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)));3149    if (!addToFunctionSummaryMap(3150            "accept",3151            // int accept(int socket, struct sockaddr *restrict address,3152            //            socklen_t *restrict address_len);3153            Signature(ArgTypes{IntTy, StructSockaddrPtrRestrictTy,3154                               Socklen_tPtrRestrictTy},3155                      RetType{IntTy}),3156            Accept))3157      addToFunctionSummaryMap(3158          "accept",3159          Signature(ArgTypes{IntTy, Irrelevant, Socklen_tPtrRestrictTy},3160                    RetType{IntTy}),3161          Accept);3162 3163    // int bind(int socket, const struct sockaddr *address, socklen_t3164    //          address_len);3165    if (!addToFunctionSummaryMap(3166            "bind",3167            Signature(ArgTypes{IntTy, ConstStructSockaddrPtrTy, Socklen_tTy},3168                      RetType{IntTy}),3169            Summary(NoEvalCall)3170                .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)3171                .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)3172                .ArgConstraint(3173                    ArgumentCondition(0, WithinRange, Range(0, IntMax)))3174                .ArgConstraint(NotNull(ArgNo(1)))3175                .ArgConstraint(3176                    BufferSize(/*Buffer=*/ArgNo(1), /*BufSize=*/ArgNo(2)))3177                .ArgConstraint(3178                    ArgumentCondition(2, WithinRange, Range(0, Socklen_tMax)))))3179      // Do not add constraints on sockaddr.3180      addToFunctionSummaryMap(3181          "bind",3182          Signature(ArgTypes{IntTy, Irrelevant, Socklen_tTy}, RetType{IntTy}),3183          Summary(NoEvalCall)3184              .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)3185              .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)3186              .ArgConstraint(3187                  ArgumentCondition(0, WithinRange, Range(0, IntMax)))3188              .ArgConstraint(3189                  ArgumentCondition(2, WithinRange, Range(0, Socklen_tMax))));3190 3191    // int getpeername(int socket, struct sockaddr *restrict address,3192    //                 socklen_t *restrict address_len);3193    if (!addToFunctionSummaryMap(3194            "getpeername",3195            Signature(ArgTypes{IntTy, StructSockaddrPtrRestrictTy,3196                               Socklen_tPtrRestrictTy},3197                      RetType{IntTy}),3198            Summary(NoEvalCall)3199                .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)3200                .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)3201                .ArgConstraint(3202                    ArgumentCondition(0, WithinRange, Range(0, IntMax)))3203                .ArgConstraint(NotNull(ArgNo(1)))3204                .ArgConstraint(NotNull(ArgNo(2)))))3205      addToFunctionSummaryMap(3206          "getpeername",3207          Signature(ArgTypes{IntTy, Irrelevant, Socklen_tPtrRestrictTy},3208                    RetType{IntTy}),3209          Summary(NoEvalCall)3210              .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)3211              .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)3212              .ArgConstraint(3213                  ArgumentCondition(0, WithinRange, Range(0, IntMax))));3214 3215    // int getsockname(int socket, struct sockaddr *restrict address,3216    //                 socklen_t *restrict address_len);3217    if (!addToFunctionSummaryMap(3218            "getsockname",3219            Signature(ArgTypes{IntTy, StructSockaddrPtrRestrictTy,3220                               Socklen_tPtrRestrictTy},3221                      RetType{IntTy}),3222            Summary(NoEvalCall)3223                .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)3224                .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)3225                .ArgConstraint(3226                    ArgumentCondition(0, WithinRange, Range(0, IntMax)))3227                .ArgConstraint(NotNull(ArgNo(1)))3228                .ArgConstraint(NotNull(ArgNo(2)))))3229      addToFunctionSummaryMap(3230          "getsockname",3231          Signature(ArgTypes{IntTy, Irrelevant, Socklen_tPtrRestrictTy},3232                    RetType{IntTy}),3233          Summary(NoEvalCall)3234              .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)3235              .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)3236              .ArgConstraint(3237                  ArgumentCondition(0, WithinRange, Range(0, IntMax))));3238 3239    // int connect(int socket, const struct sockaddr *address, socklen_t3240    //             address_len);3241    if (!addToFunctionSummaryMap(3242            "connect",3243            Signature(ArgTypes{IntTy, ConstStructSockaddrPtrTy, Socklen_tTy},3244                      RetType{IntTy}),3245            Summary(NoEvalCall)3246                .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)3247                .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)3248                .ArgConstraint(3249                    ArgumentCondition(0, WithinRange, Range(0, IntMax)))3250                .ArgConstraint(NotNull(ArgNo(1)))))3251      addToFunctionSummaryMap(3252          "connect",3253          Signature(ArgTypes{IntTy, Irrelevant, Socklen_tTy}, RetType{IntTy}),3254          Summary(NoEvalCall)3255              .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)3256              .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)3257              .ArgConstraint(3258                  ArgumentCondition(0, WithinRange, Range(0, IntMax))));3259 3260    auto Recvfrom =3261        Summary(NoEvalCall)3262            .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)),3263                   ReturnValueCondition(WithinRange, Range(1, Ssize_tMax))},3264                  ErrnoMustNotBeChecked, GenericSuccessMsg)3265            .Case({ReturnValueCondition(WithinRange, SingleValue(0)),3266                   ArgumentCondition(2, WithinRange, SingleValue(0))},3267                  ErrnoMustNotBeChecked, GenericSuccessMsg)3268            .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)3269            .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))3270            .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),3271                                      /*BufSize=*/ArgNo(2)));3272    if (!addToFunctionSummaryMap(3273            "recvfrom",3274            // ssize_t recvfrom(int socket, void *restrict buffer,3275            //                  size_t length,3276            //                  int flags, struct sockaddr *restrict address,3277            //                  socklen_t *restrict address_len);3278            Signature(ArgTypes{IntTy, VoidPtrRestrictTy, SizeTyCanonTy, IntTy,3279                               StructSockaddrPtrRestrictTy,3280                               Socklen_tPtrRestrictTy},3281                      RetType{Ssize_tTy}),3282            Recvfrom))3283      addToFunctionSummaryMap(3284          "recvfrom",3285          Signature(ArgTypes{IntTy, VoidPtrRestrictTy, SizeTyCanonTy, IntTy,3286                             Irrelevant, Socklen_tPtrRestrictTy},3287                    RetType{Ssize_tTy}),3288          Recvfrom);3289 3290    auto Sendto =3291        Summary(NoEvalCall)3292            .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)),3293                   ReturnValueCondition(WithinRange, Range(1, Ssize_tMax))},3294                  ErrnoMustNotBeChecked, GenericSuccessMsg)3295            .Case({ReturnValueCondition(WithinRange, SingleValue(0)),3296                   ArgumentCondition(2, WithinRange, SingleValue(0))},3297                  ErrnoMustNotBeChecked, GenericSuccessMsg)3298            .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)3299            .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))3300            .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),3301                                      /*BufSize=*/ArgNo(2)));3302    if (!addToFunctionSummaryMap(3303            "sendto",3304            // ssize_t sendto(int socket, const void *message, size_t length,3305            //                int flags, const struct sockaddr *dest_addr,3306            //                socklen_t dest_len);3307            Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTyCanonTy, IntTy,3308                               ConstStructSockaddrPtrTy, Socklen_tTy},3309                      RetType{Ssize_tTy}),3310            Sendto))3311      addToFunctionSummaryMap(3312          "sendto",3313          Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTyCanonTy, IntTy,3314                             Irrelevant, Socklen_tTy},3315                    RetType{Ssize_tTy}),3316          Sendto);3317 3318    // int listen(int sockfd, int backlog);3319    addToFunctionSummaryMap(3320        "listen", Signature(ArgTypes{IntTy, IntTy}, RetType{IntTy}),3321        Summary(NoEvalCall)3322            .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)3323            .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)3324            .ArgConstraint(3325                ArgumentCondition(0, WithinRange, Range(0, IntMax))));3326 3327    // ssize_t recv(int sockfd, void *buf, size_t len, int flags);3328    addToFunctionSummaryMap(3329        "recv",3330        Signature(ArgTypes{IntTy, VoidPtrTy, SizeTyCanonTy, IntTy},3331                  RetType{Ssize_tTy}),3332        Summary(NoEvalCall)3333            .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)),3334                   ReturnValueCondition(WithinRange, Range(1, Ssize_tMax))},3335                  ErrnoMustNotBeChecked, GenericSuccessMsg)3336            .Case({ReturnValueCondition(WithinRange, SingleValue(0)),3337                   ArgumentCondition(2, WithinRange, SingleValue(0))},3338                  ErrnoMustNotBeChecked, GenericSuccessMsg)3339            .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)3340            .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))3341            .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),3342                                      /*BufSize=*/ArgNo(2))));3343 3344    std::optional<QualType> StructMsghdrTy = lookupTy("msghdr");3345    std::optional<QualType> StructMsghdrPtrTy = getPointerTy(StructMsghdrTy);3346    std::optional<QualType> ConstStructMsghdrPtrTy =3347        getPointerTy(getConstTy(StructMsghdrTy));3348 3349    // ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);3350    addToFunctionSummaryMap(3351        "recvmsg",3352        Signature(ArgTypes{IntTy, StructMsghdrPtrTy, IntTy},3353                  RetType{Ssize_tTy}),3354        Summary(NoEvalCall)3355            .Case({ReturnValueCondition(WithinRange, Range(1, Ssize_tMax))},3356                  ErrnoMustNotBeChecked, GenericSuccessMsg)3357            .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)3358            .ArgConstraint(3359                ArgumentCondition(0, WithinRange, Range(0, IntMax))));3360 3361    // ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);3362    addToFunctionSummaryMap(3363        "sendmsg",3364        Signature(ArgTypes{IntTy, ConstStructMsghdrPtrTy, IntTy},3365                  RetType{Ssize_tTy}),3366        Summary(NoEvalCall)3367            .Case({ReturnValueCondition(WithinRange, Range(1, Ssize_tMax))},3368                  ErrnoMustNotBeChecked, GenericSuccessMsg)3369            .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)3370            .ArgConstraint(3371                ArgumentCondition(0, WithinRange, Range(0, IntMax))));3372 3373    // int setsockopt(int socket, int level, int option_name,3374    //                const void *option_value, socklen_t option_len);3375    addToFunctionSummaryMap(3376        "setsockopt",3377        Signature(ArgTypes{IntTy, IntTy, IntTy, ConstVoidPtrTy, Socklen_tTy},3378                  RetType{IntTy}),3379        Summary(NoEvalCall)3380            .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)3381            .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)3382            .ArgConstraint(NotNullBuffer(ArgNo(3), ArgNo(4)))3383            .ArgConstraint(3384                BufferSize(/*Buffer=*/ArgNo(3), /*BufSize=*/ArgNo(4)))3385            .ArgConstraint(3386                ArgumentCondition(4, WithinRange, Range(0, Socklen_tMax))));3387 3388    // int getsockopt(int socket, int level, int option_name,3389    //                void *restrict option_value,3390    //                socklen_t *restrict option_len);3391    addToFunctionSummaryMap(3392        "getsockopt",3393        Signature(ArgTypes{IntTy, IntTy, IntTy, VoidPtrRestrictTy,3394                           Socklen_tPtrRestrictTy},3395                  RetType{IntTy}),3396        Summary(NoEvalCall)3397            .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)3398            .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)3399            .ArgConstraint(NotNull(ArgNo(3)))3400            .ArgConstraint(NotNull(ArgNo(4))));3401 3402    // ssize_t send(int sockfd, const void *buf, size_t len, int flags);3403    addToFunctionSummaryMap(3404        "send",3405        Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTyCanonTy, IntTy},3406                  RetType{Ssize_tTy}),3407        Summary(NoEvalCall)3408            .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)),3409                   ReturnValueCondition(WithinRange, Range(1, Ssize_tMax))},3410                  ErrnoMustNotBeChecked, GenericSuccessMsg)3411            .Case({ReturnValueCondition(WithinRange, SingleValue(0)),3412                   ArgumentCondition(2, WithinRange, SingleValue(0))},3413                  ErrnoMustNotBeChecked, GenericSuccessMsg)3414            .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)3415            .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))3416            .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),3417                                      /*BufSize=*/ArgNo(2))));3418 3419    // int socketpair(int domain, int type, int protocol, int sv[2]);3420    addToFunctionSummaryMap(3421        "socketpair",3422        Signature(ArgTypes{IntTy, IntTy, IntTy, IntPtrTy}, RetType{IntTy}),3423        Summary(NoEvalCall)3424            .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)3425            .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)3426            .ArgConstraint(NotNull(ArgNo(3))));3427 3428    // int shutdown(int socket, int how);3429    addToFunctionSummaryMap(3430        "shutdown", Signature(ArgTypes{IntTy, IntTy}, RetType{IntTy}),3431        Summary(NoEvalCall)3432            .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)3433            .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)3434            .ArgConstraint(3435                ArgumentCondition(0, WithinRange, Range(0, IntMax))));3436 3437    // int getnameinfo(const struct sockaddr *restrict sa, socklen_t salen,3438    //                 char *restrict node, socklen_t nodelen,3439    //                 char *restrict service,3440    //                 socklen_t servicelen, int flags);3441    //3442    // This is defined in netdb.h. And contrary to 'socket.h', the sockaddr3443    // parameter is never handled as a transparent union in netdb.h3444    addToFunctionSummaryMap(3445        "getnameinfo",3446        Signature(ArgTypes{ConstStructSockaddrPtrRestrictTy, Socklen_tTy,3447                           CharPtrRestrictTy, Socklen_tTy, CharPtrRestrictTy,3448                           Socklen_tTy, IntTy},3449                  RetType{IntTy}),3450        Summary(NoEvalCall)3451            .ArgConstraint(3452                BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1)))3453            .ArgConstraint(3454                ArgumentCondition(1, WithinRange, Range(0, Socklen_tMax)))3455            .ArgConstraint(3456                BufferSize(/*Buffer=*/ArgNo(2), /*BufSize=*/ArgNo(3)))3457            .ArgConstraint(3458                ArgumentCondition(3, WithinRange, Range(0, Socklen_tMax)))3459            .ArgConstraint(3460                BufferSize(/*Buffer=*/ArgNo(4), /*BufSize=*/ArgNo(5)))3461            .ArgConstraint(3462                ArgumentCondition(5, WithinRange, Range(0, Socklen_tMax))));3463 3464    std::optional<QualType> StructUtimbufTy = lookupTy("utimbuf");3465    std::optional<QualType> StructUtimbufPtrTy = getPointerTy(StructUtimbufTy);3466 3467    // int utime(const char *filename, struct utimbuf *buf);3468    addToFunctionSummaryMap(3469        "utime",3470        Signature(ArgTypes{ConstCharPtrTy, StructUtimbufPtrTy}, RetType{IntTy}),3471        Summary(NoEvalCall)3472            .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)3473            .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)3474            .ArgConstraint(NotNull(ArgNo(0))));3475 3476    std::optional<QualType> StructTimespecTy = lookupTy("timespec");3477    std::optional<QualType> StructTimespecPtrTy =3478        getPointerTy(StructTimespecTy);3479    std::optional<QualType> ConstStructTimespecPtrTy =3480        getPointerTy(getConstTy(StructTimespecTy));3481 3482    // int futimens(int fd, const struct timespec times[2]);3483    addToFunctionSummaryMap(3484        "futimens",3485        Signature(ArgTypes{IntTy, ConstStructTimespecPtrTy}, RetType{IntTy}),3486        Summary(NoEvalCall)3487            .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)3488            .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)3489            .ArgConstraint(3490                ArgumentCondition(0, WithinRange, Range(0, IntMax))));3491 3492    // int utimensat(int dirfd, const char *pathname,3493    //               const struct timespec times[2], int flags);3494    addToFunctionSummaryMap(3495        "utimensat",3496        Signature(3497            ArgTypes{IntTy, ConstCharPtrTy, ConstStructTimespecPtrTy, IntTy},3498            RetType{IntTy}),3499        Summary(NoEvalCall)3500            .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)3501            .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)3502            .ArgConstraint(NotNull(ArgNo(1))));3503 3504    std::optional<QualType> StructTimevalTy = lookupTy("timeval");3505    std::optional<QualType> ConstStructTimevalPtrTy =3506        getPointerTy(getConstTy(StructTimevalTy));3507 3508    // int utimes(const char *filename, const struct timeval times[2]);3509    addToFunctionSummaryMap(3510        "utimes",3511        Signature(ArgTypes{ConstCharPtrTy, ConstStructTimevalPtrTy},3512                  RetType{IntTy}),3513        Summary(NoEvalCall)3514            .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)3515            .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)3516            .ArgConstraint(NotNull(ArgNo(0))));3517 3518    // int nanosleep(const struct timespec *rqtp, struct timespec *rmtp);3519    addToFunctionSummaryMap(3520        "nanosleep",3521        Signature(ArgTypes{ConstStructTimespecPtrTy, StructTimespecPtrTy},3522                  RetType{IntTy}),3523        Summary(NoEvalCall)3524            .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)3525            .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)3526            .ArgConstraint(NotNull(ArgNo(0))));3527 3528    std::optional<QualType> Time_tTy = lookupTy("time_t");3529    std::optional<QualType> ConstTime_tPtrTy =3530        getPointerTy(getConstTy(Time_tTy));3531    std::optional<QualType> ConstTime_tPtrRestrictTy =3532        getRestrictTy(ConstTime_tPtrTy);3533 3534    std::optional<QualType> StructTmTy = lookupTy("tm");3535    std::optional<QualType> StructTmPtrTy = getPointerTy(StructTmTy);3536    std::optional<QualType> StructTmPtrRestrictTy =3537        getRestrictTy(StructTmPtrTy);3538    std::optional<QualType> ConstStructTmPtrTy =3539        getPointerTy(getConstTy(StructTmTy));3540    std::optional<QualType> ConstStructTmPtrRestrictTy =3541        getRestrictTy(ConstStructTmPtrTy);3542 3543    // struct tm * localtime(const time_t *tp);3544    addToFunctionSummaryMap(3545        "localtime",3546        Signature(ArgTypes{ConstTime_tPtrTy}, RetType{StructTmPtrTy}),3547        Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));3548 3549    // struct tm *localtime_r(const time_t *restrict timer,3550    //                        struct tm *restrict result);3551    addToFunctionSummaryMap(3552        "localtime_r",3553        Signature(ArgTypes{ConstTime_tPtrRestrictTy, StructTmPtrRestrictTy},3554                  RetType{StructTmPtrTy}),3555        Summary(NoEvalCall)3556            .ArgConstraint(NotNull(ArgNo(0)))3557            .ArgConstraint(NotNull(ArgNo(1))));3558 3559    // char *asctime_r(const struct tm *restrict tm, char *restrict buf);3560    addToFunctionSummaryMap(3561        "asctime_r",3562        Signature(ArgTypes{ConstStructTmPtrRestrictTy, CharPtrRestrictTy},3563                  RetType{CharPtrTy}),3564        Summary(NoEvalCall)3565            .ArgConstraint(NotNull(ArgNo(0)))3566            .ArgConstraint(NotNull(ArgNo(1)))3567            .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),3568                                      /*MinBufSize=*/BVF.getValue(26, IntTy))));3569 3570    // char *ctime_r(const time_t *timep, char *buf);3571    addToFunctionSummaryMap(3572        "ctime_r",3573        Signature(ArgTypes{ConstTime_tPtrTy, CharPtrTy}, RetType{CharPtrTy}),3574        Summary(NoEvalCall)3575            .ArgConstraint(NotNull(ArgNo(0)))3576            .ArgConstraint(NotNull(ArgNo(1)))3577            .ArgConstraint(BufferSize(3578                /*Buffer=*/ArgNo(1),3579                /*MinBufSize=*/BVF.getValue(26, IntTy))));3580 3581    // struct tm *gmtime_r(const time_t *restrict timer,3582    //                     struct tm *restrict result);3583    addToFunctionSummaryMap(3584        "gmtime_r",3585        Signature(ArgTypes{ConstTime_tPtrRestrictTy, StructTmPtrRestrictTy},3586                  RetType{StructTmPtrTy}),3587        Summary(NoEvalCall)3588            .ArgConstraint(NotNull(ArgNo(0)))3589            .ArgConstraint(NotNull(ArgNo(1))));3590 3591    // struct tm * gmtime(const time_t *tp);3592    addToFunctionSummaryMap(3593        "gmtime", Signature(ArgTypes{ConstTime_tPtrTy}, RetType{StructTmPtrTy}),3594        Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));3595 3596    std::optional<QualType> Clockid_tTy = lookupTy("clockid_t");3597 3598    // int clock_gettime(clockid_t clock_id, struct timespec *tp);3599    addToFunctionSummaryMap(3600        "clock_gettime",3601        Signature(ArgTypes{Clockid_tTy, StructTimespecPtrTy}, RetType{IntTy}),3602        Summary(NoEvalCall)3603            .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)3604            .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)3605            .ArgConstraint(NotNull(ArgNo(1))));3606 3607    std::optional<QualType> StructItimervalTy = lookupTy("itimerval");3608    std::optional<QualType> StructItimervalPtrTy =3609        getPointerTy(StructItimervalTy);3610 3611    // int getitimer(int which, struct itimerval *curr_value);3612    addToFunctionSummaryMap(3613        "getitimer",3614        Signature(ArgTypes{IntTy, StructItimervalPtrTy}, RetType{IntTy}),3615        Summary(NoEvalCall)3616            .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)3617            .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)3618            .ArgConstraint(NotNull(ArgNo(1))));3619 3620    std::optional<QualType> Pthread_cond_tTy = lookupTy("pthread_cond_t");3621    std::optional<QualType> Pthread_cond_tPtrTy =3622        getPointerTy(Pthread_cond_tTy);3623    std::optional<QualType> Pthread_tTy = lookupTy("pthread_t");3624    std::optional<QualType> Pthread_tPtrTy = getPointerTy(Pthread_tTy);3625    std::optional<QualType> Pthread_tPtrRestrictTy =3626        getRestrictTy(Pthread_tPtrTy);3627    std::optional<QualType> Pthread_mutex_tTy = lookupTy("pthread_mutex_t");3628    std::optional<QualType> Pthread_mutex_tPtrTy =3629        getPointerTy(Pthread_mutex_tTy);3630    std::optional<QualType> Pthread_mutex_tPtrRestrictTy =3631        getRestrictTy(Pthread_mutex_tPtrTy);3632    std::optional<QualType> Pthread_attr_tTy = lookupTy("pthread_attr_t");3633    std::optional<QualType> Pthread_attr_tPtrTy =3634        getPointerTy(Pthread_attr_tTy);3635    std::optional<QualType> ConstPthread_attr_tPtrTy =3636        getPointerTy(getConstTy(Pthread_attr_tTy));3637    std::optional<QualType> ConstPthread_attr_tPtrRestrictTy =3638        getRestrictTy(ConstPthread_attr_tPtrTy);3639    std::optional<QualType> Pthread_mutexattr_tTy =3640        lookupTy("pthread_mutexattr_t");3641    std::optional<QualType> ConstPthread_mutexattr_tPtrTy =3642        getPointerTy(getConstTy(Pthread_mutexattr_tTy));3643    std::optional<QualType> ConstPthread_mutexattr_tPtrRestrictTy =3644        getRestrictTy(ConstPthread_mutexattr_tPtrTy);3645 3646    QualType PthreadStartRoutineTy = getPointerTy(3647        ACtx.getFunctionType(/*ResultTy=*/VoidPtrTy, /*Args=*/VoidPtrTy,3648                             FunctionProtoType::ExtProtoInfo()));3649 3650    // int pthread_cond_signal(pthread_cond_t *cond);3651    // int pthread_cond_broadcast(pthread_cond_t *cond);3652    addToFunctionSummaryMap(3653        {"pthread_cond_signal", "pthread_cond_broadcast"},3654        Signature(ArgTypes{Pthread_cond_tPtrTy}, RetType{IntTy}),3655        Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));3656 3657    // int pthread_create(pthread_t *restrict thread,3658    //                    const pthread_attr_t *restrict attr,3659    //                    void *(*start_routine)(void*), void *restrict arg);3660    addToFunctionSummaryMap(3661        "pthread_create",3662        Signature(ArgTypes{Pthread_tPtrRestrictTy,3663                           ConstPthread_attr_tPtrRestrictTy,3664                           PthreadStartRoutineTy, VoidPtrRestrictTy},3665                  RetType{IntTy}),3666        Summary(NoEvalCall)3667            .ArgConstraint(NotNull(ArgNo(0)))3668            .ArgConstraint(NotNull(ArgNo(2))));3669 3670    // int pthread_attr_destroy(pthread_attr_t *attr);3671    // int pthread_attr_init(pthread_attr_t *attr);3672    addToFunctionSummaryMap(3673        {"pthread_attr_destroy", "pthread_attr_init"},3674        Signature(ArgTypes{Pthread_attr_tPtrTy}, RetType{IntTy}),3675        Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));3676 3677    // int pthread_attr_getstacksize(const pthread_attr_t *restrict attr,3678    //                               size_t *restrict stacksize);3679    // int pthread_attr_getguardsize(const pthread_attr_t *restrict attr,3680    //                               size_t *restrict guardsize);3681    addToFunctionSummaryMap(3682        {"pthread_attr_getstacksize", "pthread_attr_getguardsize"},3683        Signature(ArgTypes{ConstPthread_attr_tPtrRestrictTy, SizePtrRestrictTy},3684                  RetType{IntTy}),3685        Summary(NoEvalCall)3686            .ArgConstraint(NotNull(ArgNo(0)))3687            .ArgConstraint(NotNull(ArgNo(1))));3688 3689    // int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize);3690    // int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize);3691    addToFunctionSummaryMap(3692        {"pthread_attr_setstacksize", "pthread_attr_setguardsize"},3693        Signature(ArgTypes{Pthread_attr_tPtrTy, SizeTyCanonTy}, RetType{IntTy}),3694        Summary(NoEvalCall)3695            .ArgConstraint(NotNull(ArgNo(0)))3696            .ArgConstraint(3697                ArgumentCondition(1, WithinRange, Range(0, SizeMax))));3698 3699    // int pthread_mutex_init(pthread_mutex_t *restrict mutex, const3700    //                        pthread_mutexattr_t *restrict attr);3701    addToFunctionSummaryMap(3702        "pthread_mutex_init",3703        Signature(ArgTypes{Pthread_mutex_tPtrRestrictTy,3704                           ConstPthread_mutexattr_tPtrRestrictTy},3705                  RetType{IntTy}),3706        Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));3707 3708    // int pthread_mutex_destroy(pthread_mutex_t *mutex);3709    // int pthread_mutex_lock(pthread_mutex_t *mutex);3710    // int pthread_mutex_trylock(pthread_mutex_t *mutex);3711    // int pthread_mutex_unlock(pthread_mutex_t *mutex);3712    addToFunctionSummaryMap(3713        {"pthread_mutex_destroy", "pthread_mutex_lock", "pthread_mutex_trylock",3714         "pthread_mutex_unlock"},3715        Signature(ArgTypes{Pthread_mutex_tPtrTy}, RetType{IntTy}),3716        Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));3717  }3718 3719  // Functions for testing.3720  if (AddTestFunctions) {3721    const RangeInt IntMin = BVF.getMinValue(IntTy)->getLimitedValue();3722 3723    addToFunctionSummaryMap(3724        "__not_null", Signature(ArgTypes{IntPtrTy}, RetType{IntTy}),3725        Summary(EvalCallAsPure).ArgConstraint(NotNull(ArgNo(0))));3726 3727    addToFunctionSummaryMap(3728        "__not_null_buffer",3729        Signature(ArgTypes{VoidPtrTy, IntTy, IntTy}, RetType{IntTy}),3730        Summary(EvalCallAsPure)3731            .ArgConstraint(NotNullBuffer(ArgNo(0), ArgNo(1), ArgNo(2))));3732 3733    // Test inside range constraints.3734    addToFunctionSummaryMap(3735        "__single_val_0", Signature(ArgTypes{IntTy}, RetType{IntTy}),3736        Summary(EvalCallAsPure)3737            .ArgConstraint(ArgumentCondition(0U, WithinRange, SingleValue(0))));3738    addToFunctionSummaryMap(3739        "__single_val_1", Signature(ArgTypes{IntTy}, RetType{IntTy}),3740        Summary(EvalCallAsPure)3741            .ArgConstraint(ArgumentCondition(0U, WithinRange, SingleValue(1))));3742    addToFunctionSummaryMap(3743        "__range_1_2", Signature(ArgTypes{IntTy}, RetType{IntTy}),3744        Summary(EvalCallAsPure)3745            .ArgConstraint(ArgumentCondition(0U, WithinRange, Range(1, 2))));3746    addToFunctionSummaryMap(3747        "__range_m1_1", Signature(ArgTypes{IntTy}, RetType{IntTy}),3748        Summary(EvalCallAsPure)3749            .ArgConstraint(ArgumentCondition(0U, WithinRange, Range(-1, 1))));3750    addToFunctionSummaryMap(3751        "__range_m2_m1", Signature(ArgTypes{IntTy}, RetType{IntTy}),3752        Summary(EvalCallAsPure)3753            .ArgConstraint(ArgumentCondition(0U, WithinRange, Range(-2, -1))));3754    addToFunctionSummaryMap(3755        "__range_m10_10", Signature(ArgTypes{IntTy}, RetType{IntTy}),3756        Summary(EvalCallAsPure)3757            .ArgConstraint(ArgumentCondition(0U, WithinRange, Range(-10, 10))));3758    addToFunctionSummaryMap("__range_m1_inf",3759                            Signature(ArgTypes{IntTy}, RetType{IntTy}),3760                            Summary(EvalCallAsPure)3761                                .ArgConstraint(ArgumentCondition(3762                                    0U, WithinRange, Range(-1, IntMax))));3763    addToFunctionSummaryMap("__range_0_inf",3764                            Signature(ArgTypes{IntTy}, RetType{IntTy}),3765                            Summary(EvalCallAsPure)3766                                .ArgConstraint(ArgumentCondition(3767                                    0U, WithinRange, Range(0, IntMax))));3768    addToFunctionSummaryMap("__range_1_inf",3769                            Signature(ArgTypes{IntTy}, RetType{IntTy}),3770                            Summary(EvalCallAsPure)3771                                .ArgConstraint(ArgumentCondition(3772                                    0U, WithinRange, Range(1, IntMax))));3773    addToFunctionSummaryMap("__range_minf_m1",3774                            Signature(ArgTypes{IntTy}, RetType{IntTy}),3775                            Summary(EvalCallAsPure)3776                                .ArgConstraint(ArgumentCondition(3777                                    0U, WithinRange, Range(IntMin, -1))));3778    addToFunctionSummaryMap("__range_minf_0",3779                            Signature(ArgTypes{IntTy}, RetType{IntTy}),3780                            Summary(EvalCallAsPure)3781                                .ArgConstraint(ArgumentCondition(3782                                    0U, WithinRange, Range(IntMin, 0))));3783    addToFunctionSummaryMap("__range_minf_1",3784                            Signature(ArgTypes{IntTy}, RetType{IntTy}),3785                            Summary(EvalCallAsPure)3786                                .ArgConstraint(ArgumentCondition(3787                                    0U, WithinRange, Range(IntMin, 1))));3788    addToFunctionSummaryMap("__range_1_2__4_6",3789                            Signature(ArgTypes{IntTy}, RetType{IntTy}),3790                            Summary(EvalCallAsPure)3791                                .ArgConstraint(ArgumentCondition(3792                                    0U, WithinRange, Range({1, 2}, {4, 6}))));3793    addToFunctionSummaryMap(3794        "__range_1_2__4_inf", Signature(ArgTypes{IntTy}, RetType{IntTy}),3795        Summary(EvalCallAsPure)3796            .ArgConstraint(ArgumentCondition(0U, WithinRange,3797                                             Range({1, 2}, {4, IntMax}))));3798 3799    // Test out of range constraints.3800    addToFunctionSummaryMap(3801        "__single_val_out_0", Signature(ArgTypes{IntTy}, RetType{IntTy}),3802        Summary(EvalCallAsPure)3803            .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(0))));3804    addToFunctionSummaryMap(3805        "__single_val_out_1", Signature(ArgTypes{IntTy}, RetType{IntTy}),3806        Summary(EvalCallAsPure)3807            .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(1))));3808    addToFunctionSummaryMap(3809        "__range_out_1_2", Signature(ArgTypes{IntTy}, RetType{IntTy}),3810        Summary(EvalCallAsPure)3811            .ArgConstraint(ArgumentCondition(0U, OutOfRange, Range(1, 2))));3812    addToFunctionSummaryMap(3813        "__range_out_m1_1", Signature(ArgTypes{IntTy}, RetType{IntTy}),3814        Summary(EvalCallAsPure)3815            .ArgConstraint(ArgumentCondition(0U, OutOfRange, Range(-1, 1))));3816    addToFunctionSummaryMap(3817        "__range_out_m2_m1", Signature(ArgTypes{IntTy}, RetType{IntTy}),3818        Summary(EvalCallAsPure)3819            .ArgConstraint(ArgumentCondition(0U, OutOfRange, Range(-2, -1))));3820    addToFunctionSummaryMap(3821        "__range_out_m10_10", Signature(ArgTypes{IntTy}, RetType{IntTy}),3822        Summary(EvalCallAsPure)3823            .ArgConstraint(ArgumentCondition(0U, OutOfRange, Range(-10, 10))));3824    addToFunctionSummaryMap("__range_out_m1_inf",3825                            Signature(ArgTypes{IntTy}, RetType{IntTy}),3826                            Summary(EvalCallAsPure)3827                                .ArgConstraint(ArgumentCondition(3828                                    0U, OutOfRange, Range(-1, IntMax))));3829    addToFunctionSummaryMap("__range_out_0_inf",3830                            Signature(ArgTypes{IntTy}, RetType{IntTy}),3831                            Summary(EvalCallAsPure)3832                                .ArgConstraint(ArgumentCondition(3833                                    0U, OutOfRange, Range(0, IntMax))));3834    addToFunctionSummaryMap("__range_out_1_inf",3835                            Signature(ArgTypes{IntTy}, RetType{IntTy}),3836                            Summary(EvalCallAsPure)3837                                .ArgConstraint(ArgumentCondition(3838                                    0U, OutOfRange, Range(1, IntMax))));3839    addToFunctionSummaryMap("__range_out_minf_m1",3840                            Signature(ArgTypes{IntTy}, RetType{IntTy}),3841                            Summary(EvalCallAsPure)3842                                .ArgConstraint(ArgumentCondition(3843                                    0U, OutOfRange, Range(IntMin, -1))));3844    addToFunctionSummaryMap("__range_out_minf_0",3845                            Signature(ArgTypes{IntTy}, RetType{IntTy}),3846                            Summary(EvalCallAsPure)3847                                .ArgConstraint(ArgumentCondition(3848                                    0U, OutOfRange, Range(IntMin, 0))));3849    addToFunctionSummaryMap("__range_out_minf_1",3850                            Signature(ArgTypes{IntTy}, RetType{IntTy}),3851                            Summary(EvalCallAsPure)3852                                .ArgConstraint(ArgumentCondition(3853                                    0U, OutOfRange, Range(IntMin, 1))));3854    addToFunctionSummaryMap("__range_out_1_2__4_6",3855                            Signature(ArgTypes{IntTy}, RetType{IntTy}),3856                            Summary(EvalCallAsPure)3857                                .ArgConstraint(ArgumentCondition(3858                                    0U, OutOfRange, Range({1, 2}, {4, 6}))));3859    addToFunctionSummaryMap(3860        "__range_out_1_2__4_inf", Signature(ArgTypes{IntTy}, RetType{IntTy}),3861        Summary(EvalCallAsPure)3862            .ArgConstraint(3863                ArgumentCondition(0U, OutOfRange, Range({1, 2}, {4, IntMax}))));3864 3865    // Test range kind.3866    addToFunctionSummaryMap(3867        "__within", Signature(ArgTypes{IntTy}, RetType{IntTy}),3868        Summary(EvalCallAsPure)3869            .ArgConstraint(ArgumentCondition(0U, WithinRange, SingleValue(1))));3870    addToFunctionSummaryMap(3871        "__out_of", Signature(ArgTypes{IntTy}, RetType{IntTy}),3872        Summary(EvalCallAsPure)3873            .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(1))));3874 3875    addToFunctionSummaryMap(3876        "__two_constrained_args",3877        Signature(ArgTypes{IntTy, IntTy}, RetType{IntTy}),3878        Summary(EvalCallAsPure)3879            .ArgConstraint(ArgumentCondition(0U, WithinRange, SingleValue(1)))3880            .ArgConstraint(ArgumentCondition(1U, WithinRange, SingleValue(1))));3881    addToFunctionSummaryMap(3882        "__arg_constrained_twice", Signature(ArgTypes{IntTy}, RetType{IntTy}),3883        Summary(EvalCallAsPure)3884            .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(1)))3885            .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(2))));3886    addToFunctionSummaryMap(3887        "__defaultparam",3888        Signature(ArgTypes{Irrelevant, IntTy}, RetType{IntTy}),3889        Summary(EvalCallAsPure).ArgConstraint(NotNull(ArgNo(0))));3890    addToFunctionSummaryMap(3891        "__variadic",3892        Signature(ArgTypes{VoidPtrTy, ConstCharPtrTy}, RetType{IntTy}),3893        Summary(EvalCallAsPure)3894            .ArgConstraint(NotNull(ArgNo(0)))3895            .ArgConstraint(NotNull(ArgNo(1))));3896    addToFunctionSummaryMap(3897        "__buf_size_arg_constraint",3898        Signature(ArgTypes{ConstVoidPtrTy, SizeTyCanonTy}, RetType{IntTy}),3899        Summary(EvalCallAsPure)3900            .ArgConstraint(3901                BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1))));3902    addToFunctionSummaryMap(3903        "__buf_size_arg_constraint_mul",3904        Signature(ArgTypes{ConstVoidPtrTy, SizeTyCanonTy, SizeTyCanonTy},3905                  RetType{IntTy}),3906        Summary(EvalCallAsPure)3907            .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1),3908                                      /*BufSizeMultiplier=*/ArgNo(2))));3909    addToFunctionSummaryMap(3910        "__buf_size_arg_constraint_concrete",3911        Signature(ArgTypes{ConstVoidPtrTy}, RetType{IntTy}),3912        Summary(EvalCallAsPure)3913            .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(0),3914                                      /*BufSize=*/BVF.getValue(10, IntTy))));3915    addToFunctionSummaryMap(3916        {"__test_restrict_param_0", "__test_restrict_param_1",3917         "__test_restrict_param_2"},3918        Signature(ArgTypes{VoidPtrRestrictTy}, RetType{VoidTy}),3919        Summary(EvalCallAsPure));3920 3921    // Test the application of cases.3922    addToFunctionSummaryMap(3923        "__test_case_note", Signature(ArgTypes{}, RetType{IntTy}),3924        Summary(EvalCallAsPure)3925            .Case({ReturnValueCondition(WithinRange, SingleValue(0))},3926                  ErrnoIrrelevant, "Function returns 0")3927            .Case({ReturnValueCondition(WithinRange, SingleValue(1))},3928                  ErrnoIrrelevant, "Function returns 1"));3929    addToFunctionSummaryMap(3930        "__test_case_range_1_2__4_6",3931        Signature(ArgTypes{IntTy}, RetType{IntTy}),3932        Summary(EvalCallAsPure)3933            .Case({ArgumentCondition(0U, WithinRange,3934                                     IntRangeVector{{IntMin, 0}, {3, 3}}),3935                   ReturnValueCondition(WithinRange, SingleValue(1))},3936                  ErrnoIrrelevant)3937            .Case({ArgumentCondition(0U, WithinRange,3938                                     IntRangeVector{{3, 3}, {7, IntMax}}),3939                   ReturnValueCondition(WithinRange, SingleValue(2))},3940                  ErrnoIrrelevant)3941            .Case({ArgumentCondition(0U, WithinRange,3942                                     IntRangeVector{{IntMin, 0}, {7, IntMax}}),3943                   ReturnValueCondition(WithinRange, SingleValue(3))},3944                  ErrnoIrrelevant)3945            .Case({ArgumentCondition(3946                       0U, WithinRange,3947                       IntRangeVector{{IntMin, 0}, {3, 3}, {7, IntMax}}),3948                   ReturnValueCondition(WithinRange, SingleValue(4))},3949                  ErrnoIrrelevant));3950  }3951}3952 3953void ento::registerStdCLibraryFunctionsChecker(CheckerManager &mgr) {3954  auto *Checker = mgr.registerChecker<StdLibraryFunctionsChecker>();3955  Checker->CheckName = mgr.getCurrentCheckerName();3956  const AnalyzerOptions &Opts = mgr.getAnalyzerOptions();3957  Checker->DisplayLoadedSummaries =3958      Opts.getCheckerBooleanOption(Checker, "DisplayLoadedSummaries");3959  Checker->ModelPOSIX = Opts.getCheckerBooleanOption(Checker, "ModelPOSIX");3960  Checker->ShouldAssumeControlledEnvironment =3961      Opts.ShouldAssumeControlledEnvironment;3962}3963 3964bool ento::shouldRegisterStdCLibraryFunctionsChecker(3965    const CheckerManager &mgr) {3966  return true;3967}3968 3969void ento::registerStdCLibraryFunctionsTesterChecker(CheckerManager &mgr) {3970  auto *Checker = mgr.getChecker<StdLibraryFunctionsChecker>();3971  Checker->AddTestFunctions = true;3972}3973 3974bool ento::shouldRegisterStdCLibraryFunctionsTesterChecker(3975    const CheckerManager &mgr) {3976  return true;3977}3978