xref: /llvm-project/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp (revision f0b9dbcfc7ba2a217cab3217d6217fc270c88b58)
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-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This checker improves modeling of a few simple library functions.
10 //
11 // This checker provides a specification format - `Summary' - and
12 // contains descriptions of some library functions in this format. Each
13 // specification contains a list of branches for splitting the program state
14 // upon call, and range constraints on argument and return-value symbols that
15 // are satisfied on each branch. This spec can be expanded to include more
16 // items, like external effects of the function.
17 //
18 // The main difference between this approach and the body farms technique is
19 // 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 value
21 // iff `x' is a punctuation character, that is, when `x' is in range
22 //   ['!', '/']   [':', '@']  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 farm
25 // would result in many more branches. Because each branch needs to be analyzed
26 // 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 path
30 // was not consciously intended, and therefore it might have been unreachable.
31 //
32 // This checker uses eval::Call for modeling pure functions (functions without
33 // side effets), for which their `Summary' is a precise model. This avoids
34 // unnecessary invalidation passes. Conflicts with other checkers are unlikely
35 // because if the function has no other effects, other checkers would probably
36 // never want to improve upon the modeling done by this checker.
37 //
38 // Non-pure functions, for which only partial improvement over the default
39 // behavior is expected, are modeled via check::PostCall, non-intrusively.
40 //
41 // The following standard C functions are currently supported:
42 //
43 //   fgetc      getline   isdigit   isupper     toascii
44 //   fread      isalnum   isgraph   isxdigit
45 //   fwrite     isalpha   islower   read
46 //   getc       isascii   isprint   write
47 //   getchar    isblank   ispunct   toupper
48 //   getdelim   iscntrl   isspace   tolower
49 //
50 //===----------------------------------------------------------------------===//
51 
52 #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
53 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
54 #include "clang/StaticAnalyzer/Core/Checker.h"
55 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
56 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
57 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
58 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h"
59 #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicSize.h"
60 
61 using namespace clang;
62 using namespace clang::ento;
63 
64 namespace {
65 class StdLibraryFunctionsChecker
66     : public Checker<check::PreCall, check::PostCall, eval::Call> {
67 
68   class Summary;
69 
70   /// Specify how much the analyzer engine should entrust modeling this function
71   /// to us. If he doesn't, he performs additional invalidations.
72   enum InvalidationKind { NoEvalCall, EvalCallAsPure };
73 
74   // The universal integral type to use in value range descriptions.
75   // Unsigned to make sure overflows are well-defined.
76   typedef uint64_t RangeInt;
77 
78   /// Normally, describes a single range constraint, eg. {{0, 1}, {3, 4}} is
79   /// a non-negative integer, which less than 5 and not equal to 2. For
80   /// `ComparesToArgument', holds information about how exactly to compare to
81   /// the argument.
82   typedef std::vector<std::pair<RangeInt, RangeInt>> IntRangeVector;
83 
84   /// A reference to an argument or return value by its number.
85   /// ArgNo in CallExpr and CallEvent is defined as Unsigned, but
86   /// obviously uint32_t should be enough for all practical purposes.
87   typedef uint32_t ArgNo;
88   static const ArgNo Ret;
89 
90   class ValueConstraint;
91 
92   // Pointer to the ValueConstraint. We need a copyable, polymorphic and
93   // default initialize able type (vector needs that). A raw pointer was good,
94   // however, we cannot default initialize that. unique_ptr makes the Summary
95   // class non-copyable, therefore not an option. Releasing the copyability
96   // requirement would render the initialization of the Summary map infeasible.
97   using ValueConstraintPtr = std::shared_ptr<ValueConstraint>;
98 
99   /// Polymorphic base class that represents a constraint on a given argument
100   /// (or return value) of a function. Derived classes implement different kind
101   /// of constraints, e.g range constraints or correlation between two
102   /// arguments.
103   class ValueConstraint {
104   public:
105     ValueConstraint(ArgNo ArgN) : ArgN(ArgN) {}
106     virtual ~ValueConstraint() {}
107     /// Apply the effects of the constraint on the given program state. If null
108     /// is returned then the constraint is not feasible.
109     virtual ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
110                                   const Summary &Summary,
111                                   CheckerContext &C) const = 0;
112     virtual ValueConstraintPtr negate() const {
113       llvm_unreachable("Not implemented");
114     };
115 
116     // Check whether the constraint is malformed or not. It is malformed if the
117     // specified argument has a mismatch with the given FunctionDecl (e.g. the
118     // arg number is out-of-range of the function's argument list).
119     bool checkValidity(const FunctionDecl *FD) const {
120       const bool ValidArg = ArgN == Ret || ArgN < FD->getNumParams();
121       assert(ValidArg && "Arg out of range!");
122       if (!ValidArg)
123         return false;
124       // Subclasses may further refine the validation.
125       return checkSpecificValidity(FD);
126     }
127     ArgNo getArgNo() const { return ArgN; }
128 
129   protected:
130     ArgNo ArgN; // Argument to which we apply the constraint.
131 
132     /// Do polymorphic sanity check on the constraint.
133     virtual bool checkSpecificValidity(const FunctionDecl *FD) const {
134       return true;
135     }
136   };
137 
138   /// Given a range, should the argument stay inside or outside this range?
139   enum RangeKind { OutOfRange, WithinRange };
140 
141   /// Encapsulates a range on a single symbol.
142   class RangeConstraint : public ValueConstraint {
143     RangeKind Kind;
144     // A range is formed as a set of intervals (sub-ranges).
145     // E.g. {['A', 'Z'], ['a', 'z']}
146     //
147     // The default constructed RangeConstraint has an empty range set, applying
148     // such constraint does not involve any assumptions, thus the State remains
149     // unchanged. This is meaningful, if the range is dependent on a looked up
150     // type (e.g. [0, Socklen_tMax]). If the type is not found, then the range
151     // is default initialized to be empty.
152     IntRangeVector Ranges;
153 
154   public:
155     RangeConstraint(ArgNo ArgN, RangeKind Kind, const IntRangeVector &Ranges)
156         : ValueConstraint(ArgN), Kind(Kind), Ranges(Ranges) {}
157 
158     const IntRangeVector &getRanges() const { return Ranges; }
159 
160   private:
161     ProgramStateRef applyAsOutOfRange(ProgramStateRef State,
162                                       const CallEvent &Call,
163                                       const Summary &Summary) const;
164     ProgramStateRef applyAsWithinRange(ProgramStateRef State,
165                                        const CallEvent &Call,
166                                        const Summary &Summary) const;
167 
168   public:
169     ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
170                           const Summary &Summary,
171                           CheckerContext &C) const override {
172       switch (Kind) {
173       case OutOfRange:
174         return applyAsOutOfRange(State, Call, Summary);
175       case WithinRange:
176         return applyAsWithinRange(State, Call, Summary);
177       }
178       llvm_unreachable("Unknown range kind!");
179     }
180 
181     ValueConstraintPtr negate() const override {
182       RangeConstraint Tmp(*this);
183       switch (Kind) {
184       case OutOfRange:
185         Tmp.Kind = WithinRange;
186         break;
187       case WithinRange:
188         Tmp.Kind = OutOfRange;
189         break;
190       }
191       return std::make_shared<RangeConstraint>(Tmp);
192     }
193 
194     bool checkSpecificValidity(const FunctionDecl *FD) const override {
195       const bool ValidArg =
196           getArgType(FD, ArgN)->isIntegralType(FD->getASTContext());
197       assert(ValidArg &&
198              "This constraint should be applied on an integral type");
199       return ValidArg;
200     }
201   };
202 
203   class ComparisonConstraint : public ValueConstraint {
204     BinaryOperator::Opcode Opcode;
205     ArgNo OtherArgN;
206 
207   public:
208     ComparisonConstraint(ArgNo ArgN, BinaryOperator::Opcode Opcode,
209                          ArgNo OtherArgN)
210         : ValueConstraint(ArgN), Opcode(Opcode), OtherArgN(OtherArgN) {}
211     ArgNo getOtherArgNo() const { return OtherArgN; }
212     BinaryOperator::Opcode getOpcode() const { return Opcode; }
213     ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
214                           const Summary &Summary,
215                           CheckerContext &C) const override;
216   };
217 
218   class NotNullConstraint : public ValueConstraint {
219     using ValueConstraint::ValueConstraint;
220     // This variable has a role when we negate the constraint.
221     bool CannotBeNull = true;
222 
223   public:
224     ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
225                           const Summary &Summary,
226                           CheckerContext &C) const override {
227       SVal V = getArgSVal(Call, getArgNo());
228       if (V.isUndef())
229         return State;
230 
231       DefinedOrUnknownSVal L = V.castAs<DefinedOrUnknownSVal>();
232       if (!L.getAs<Loc>())
233         return State;
234 
235       return State->assume(L, CannotBeNull);
236     }
237 
238     ValueConstraintPtr negate() const override {
239       NotNullConstraint Tmp(*this);
240       Tmp.CannotBeNull = !this->CannotBeNull;
241       return std::make_shared<NotNullConstraint>(Tmp);
242     }
243 
244     bool checkSpecificValidity(const FunctionDecl *FD) const override {
245       const bool ValidArg = getArgType(FD, ArgN)->isPointerType();
246       assert(ValidArg &&
247              "This constraint should be applied only on a pointer type");
248       return ValidArg;
249     }
250   };
251 
252   // Represents a buffer argument with an additional size constraint. The
253   // constraint may be a concrete value, or a symbolic value in an argument.
254   // Example 1. Concrete value as the minimum buffer size.
255   //   char *asctime_r(const struct tm *restrict tm, char *restrict buf);
256   //   // `buf` size must be at least 26 bytes according the POSIX standard.
257   // Example 2. Argument as a buffer size.
258   //   ctime_s(char *buffer, rsize_t bufsz, const time_t *time);
259   // Example 3. The size is computed as a multiplication of other args.
260   //   size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
261   //   // Here, ptr is the buffer, and its minimum size is `size * nmemb`.
262   class BufferSizeConstraint : public ValueConstraint {
263     // The concrete value which is the minimum size for the buffer.
264     llvm::Optional<llvm::APSInt> ConcreteSize;
265     // The argument which holds the size of the buffer.
266     llvm::Optional<ArgNo> SizeArgN;
267     // The argument which is a multiplier to size. This is set in case of
268     // `fread` like functions where the size is computed as a multiplication of
269     // two arguments.
270     llvm::Optional<ArgNo> SizeMultiplierArgN;
271     // The operator we use in apply. This is negated in negate().
272     BinaryOperator::Opcode Op = BO_LE;
273 
274   public:
275     BufferSizeConstraint(ArgNo Buffer, llvm::APSInt BufMinSize)
276         : ValueConstraint(Buffer), ConcreteSize(BufMinSize) {}
277     BufferSizeConstraint(ArgNo Buffer, ArgNo BufSize)
278         : ValueConstraint(Buffer), SizeArgN(BufSize) {}
279     BufferSizeConstraint(ArgNo Buffer, ArgNo BufSize, ArgNo BufSizeMultiplier)
280         : ValueConstraint(Buffer), SizeArgN(BufSize),
281           SizeMultiplierArgN(BufSizeMultiplier) {}
282 
283     ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
284                           const Summary &Summary,
285                           CheckerContext &C) const override {
286       SValBuilder &SvalBuilder = C.getSValBuilder();
287       // The buffer argument.
288       SVal BufV = getArgSVal(Call, getArgNo());
289 
290       // Get the size constraint.
291       const SVal SizeV = [this, &State, &Call, &Summary, &SvalBuilder]() {
292         if (ConcreteSize) {
293           return SVal(SvalBuilder.makeIntVal(*ConcreteSize));
294         } else if (SizeArgN) {
295           // The size argument.
296           SVal SizeV = getArgSVal(Call, *SizeArgN);
297           // Multiply with another argument if given.
298           if (SizeMultiplierArgN) {
299             SVal SizeMulV = getArgSVal(Call, *SizeMultiplierArgN);
300             SizeV = SvalBuilder.evalBinOp(State, BO_Mul, SizeV, SizeMulV,
301                                           Summary.getArgType(*SizeArgN));
302           }
303           return SizeV;
304         } else {
305           llvm_unreachable("The constraint must be either a concrete value or "
306                            "encoded in an arguement.");
307         }
308       }();
309 
310       // The dynamic size of the buffer argument, got from the analyzer engine.
311       SVal BufDynSize = getDynamicSizeWithOffset(State, BufV);
312 
313       SVal Feasible = SvalBuilder.evalBinOp(State, Op, SizeV, BufDynSize,
314                                             SvalBuilder.getContext().BoolTy);
315       if (auto F = Feasible.getAs<DefinedOrUnknownSVal>())
316         return State->assume(*F, true);
317 
318       // We can get here only if the size argument or the dynamic size is
319       // undefined. But the dynamic size should never be undefined, only
320       // unknown. So, here, the size of the argument is undefined, i.e. we
321       // cannot apply the constraint. Actually, other checkers like
322       // CallAndMessage should catch this situation earlier, because we call a
323       // function with an uninitialized argument.
324       llvm_unreachable("Size argument or the dynamic size is Undefined");
325     }
326 
327     ValueConstraintPtr negate() const override {
328       BufferSizeConstraint Tmp(*this);
329       Tmp.Op = BinaryOperator::negateComparisonOp(Op);
330       return std::make_shared<BufferSizeConstraint>(Tmp);
331     }
332 
333     bool checkSpecificValidity(const FunctionDecl *FD) const override {
334       const bool ValidArg = getArgType(FD, ArgN)->isPointerType();
335       assert(ValidArg &&
336              "This constraint should be applied only on a pointer type");
337       return ValidArg;
338     }
339   };
340 
341   /// The complete list of constraints that defines a single branch.
342   typedef std::vector<ValueConstraintPtr> ConstraintSet;
343 
344   using ArgTypes = std::vector<Optional<QualType>>;
345   using RetType = Optional<QualType>;
346 
347   // A placeholder type, we use it whenever we do not care about the concrete
348   // type in a Signature.
349   const QualType Irrelevant{};
350   bool static isIrrelevant(QualType T) { return T.isNull(); }
351 
352   // The signature of a function we want to describe with a summary. This is a
353   // concessive signature, meaning there may be irrelevant types in the
354   // signature which we do not check against a function with concrete types.
355   // All types in the spec need to be canonical.
356   class Signature {
357     using ArgQualTypes = std::vector<QualType>;
358     ArgQualTypes ArgTys;
359     QualType RetTy;
360     // True if any component type is not found by lookup.
361     bool Invalid = false;
362 
363   public:
364     // Construct a signature from optional types. If any of the optional types
365     // are not set then the signature will be invalid.
366     Signature(ArgTypes ArgTys, RetType RetTy) {
367       for (Optional<QualType> Arg : ArgTys) {
368         if (!Arg) {
369           Invalid = true;
370           return;
371         } else {
372           assertArgTypeSuitableForSignature(*Arg);
373           this->ArgTys.push_back(*Arg);
374         }
375       }
376       if (!RetTy) {
377         Invalid = true;
378         return;
379       } else {
380         assertRetTypeSuitableForSignature(*RetTy);
381         this->RetTy = *RetTy;
382       }
383     }
384 
385     bool isInvalid() const { return Invalid; }
386     bool matches(const FunctionDecl *FD) const;
387 
388   private:
389     static void assertArgTypeSuitableForSignature(QualType T) {
390       assert((T.isNull() || !T->isVoidType()) &&
391              "We should have no void types in the spec");
392       assert((T.isNull() || T.isCanonical()) &&
393              "We should only have canonical types in the spec");
394     }
395     static void assertRetTypeSuitableForSignature(QualType T) {
396       assert((T.isNull() || T.isCanonical()) &&
397              "We should only have canonical types in the spec");
398     }
399   };
400 
401   static QualType getArgType(const FunctionDecl *FD, ArgNo ArgN) {
402     assert(FD && "Function must be set");
403     QualType T = (ArgN == Ret)
404                      ? FD->getReturnType().getCanonicalType()
405                      : FD->getParamDecl(ArgN)->getType().getCanonicalType();
406     return T;
407   }
408 
409   using Cases = std::vector<ConstraintSet>;
410 
411   /// A summary includes information about
412   ///   * function prototype (signature)
413   ///   * approach to invalidation,
414   ///   * a list of branches - a list of list of ranges -
415   ///     A branch represents a path in the exploded graph of a function (which
416   ///     is a tree). So, a branch is a series of assumptions. In other words,
417   ///     branches represent split states and additional assumptions on top of
418   ///     the splitting assumption.
419   ///     For example, consider the branches in `isalpha(x)`
420   ///       Branch 1)
421   ///         x is in range ['A', 'Z'] or in ['a', 'z']
422   ///         then the return value is not 0. (I.e. out-of-range [0, 0])
423   ///       Branch 2)
424   ///         x is out-of-range ['A', 'Z'] and out-of-range ['a', 'z']
425   ///         then the return value is 0.
426   ///   * a list of argument constraints, that must be true on every branch.
427   ///     If these constraints are not satisfied that means a fatal error
428   ///     usually resulting in undefined behaviour.
429   ///
430   /// Application of a summary:
431   ///   The signature and argument constraints together contain information
432   ///   about which functions are handled by the summary. The signature can use
433   ///   "wildcards", i.e. Irrelevant types. Irrelevant type of a parameter in
434   ///   a signature means that type is not compared to the type of the parameter
435   ///   in the found FunctionDecl. Argument constraints may specify additional
436   ///   rules for the given parameter's type, those rules are checked once the
437   ///   signature is matched.
438   class Summary {
439     // FIXME Probably the Signature should not be part of the Summary,
440     // We can remove once all overload of addToFunctionSummaryMap requires the
441     // Signature explicitly given.
442     Optional<Signature> Sign;
443     const InvalidationKind InvalidationKd;
444     Cases CaseConstraints;
445     ConstraintSet ArgConstraints;
446 
447     // The function to which the summary applies. This is set after lookup and
448     // match to the signature.
449     const FunctionDecl *FD = nullptr;
450 
451   public:
452     Summary(ArgTypes ArgTys, RetType RetTy, InvalidationKind InvalidationKd)
453         : Sign(Signature(ArgTys, RetTy)), InvalidationKd(InvalidationKd) {}
454 
455     Summary(InvalidationKind InvalidationKd) : InvalidationKd(InvalidationKd) {}
456 
457     // FIXME Remove, once all overload of addToFunctionSummaryMap requires the
458     // Signature explicitly given.
459     Summary &setSignature(const Signature &S) {
460       Sign = S;
461       return *this;
462     }
463 
464     Summary &Case(ConstraintSet &&CS) {
465       CaseConstraints.push_back(std::move(CS));
466       return *this;
467     }
468     Summary &ArgConstraint(ValueConstraintPtr VC) {
469       ArgConstraints.push_back(VC);
470       return *this;
471     }
472 
473     InvalidationKind getInvalidationKd() const { return InvalidationKd; }
474     const Cases &getCaseConstraints() const { return CaseConstraints; }
475     const ConstraintSet &getArgConstraints() const { return ArgConstraints; }
476 
477     QualType getArgType(ArgNo ArgN) const {
478       return StdLibraryFunctionsChecker::getArgType(FD, ArgN);
479     }
480 
481     // Returns true if the summary should be applied to the given function.
482     // And if yes then store the function declaration.
483     bool matchesAndSet(const FunctionDecl *FD) {
484       assert(Sign &&
485              "Signature must be set before comparing to a FunctionDecl");
486       bool Result = Sign->matches(FD) && validateByConstraints(FD);
487       if (Result) {
488         assert(!this->FD && "FD must not be set more than once");
489         this->FD = FD;
490       }
491       return Result;
492     }
493 
494     // FIXME Remove, once all overload of addToFunctionSummaryMap requires the
495     // Signature explicitly given.
496     bool hasInvalidSignature() {
497       assert(Sign && "Signature must be set before this query");
498       return Sign->isInvalid();
499     }
500 
501   private:
502     // Once we know the exact type of the function then do sanity check on all
503     // the given constraints.
504     bool validateByConstraints(const FunctionDecl *FD) const {
505       for (const ConstraintSet &Case : CaseConstraints)
506         for (const ValueConstraintPtr &Constraint : Case)
507           if (!Constraint->checkValidity(FD))
508             return false;
509       for (const ValueConstraintPtr &Constraint : ArgConstraints)
510         if (!Constraint->checkValidity(FD))
511           return false;
512       return true;
513     }
514   };
515 
516   // The map of all functions supported by the checker. It is initialized
517   // lazily, and it doesn't change after initialization.
518   using FunctionSummaryMapType = llvm::DenseMap<const FunctionDecl *, Summary>;
519   mutable FunctionSummaryMapType FunctionSummaryMap;
520 
521   mutable std::unique_ptr<BugType> BT_InvalidArg;
522 
523   static SVal getArgSVal(const CallEvent &Call, ArgNo ArgN) {
524     return ArgN == Ret ? Call.getReturnValue() : Call.getArgSVal(ArgN);
525   }
526 
527 public:
528   void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
529   void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
530   bool evalCall(const CallEvent &Call, CheckerContext &C) const;
531 
532   enum CheckKind {
533     CK_StdCLibraryFunctionArgsChecker,
534     CK_StdCLibraryFunctionsTesterChecker,
535     CK_NumCheckKinds
536   };
537   DefaultBool ChecksEnabled[CK_NumCheckKinds];
538   CheckerNameRef CheckNames[CK_NumCheckKinds];
539 
540   bool DisplayLoadedSummaries = false;
541   bool ModelPOSIX = false;
542 
543 private:
544   Optional<Summary> findFunctionSummary(const FunctionDecl *FD,
545                                         CheckerContext &C) const;
546   Optional<Summary> findFunctionSummary(const CallEvent &Call,
547                                         CheckerContext &C) const;
548 
549   void initFunctionSummaries(CheckerContext &C) const;
550 
551   void reportBug(const CallEvent &Call, ExplodedNode *N,
552                  CheckerContext &C) const {
553     if (!ChecksEnabled[CK_StdCLibraryFunctionArgsChecker])
554       return;
555     // TODO Add detailed diagnostic.
556     StringRef Msg = "Function argument constraint is not satisfied";
557     if (!BT_InvalidArg)
558       BT_InvalidArg = std::make_unique<BugType>(
559           CheckNames[CK_StdCLibraryFunctionArgsChecker],
560           "Unsatisfied argument constraints", categories::LogicError);
561     auto R = std::make_unique<PathSensitiveBugReport>(*BT_InvalidArg, Msg, N);
562     bugreporter::trackExpressionValue(N, Call.getArgExpr(0), *R);
563     C.emitReport(std::move(R));
564   }
565 };
566 
567 const StdLibraryFunctionsChecker::ArgNo StdLibraryFunctionsChecker::Ret =
568     std::numeric_limits<ArgNo>::max();
569 
570 } // end of anonymous namespace
571 
572 ProgramStateRef StdLibraryFunctionsChecker::RangeConstraint::applyAsOutOfRange(
573     ProgramStateRef State, const CallEvent &Call,
574     const Summary &Summary) const {
575   if (Ranges.empty())
576     return State;
577 
578   ProgramStateManager &Mgr = State->getStateManager();
579   SValBuilder &SVB = Mgr.getSValBuilder();
580   BasicValueFactory &BVF = SVB.getBasicValueFactory();
581   ConstraintManager &CM = Mgr.getConstraintManager();
582   QualType T = Summary.getArgType(getArgNo());
583   SVal V = getArgSVal(Call, getArgNo());
584 
585   if (auto N = V.getAs<NonLoc>()) {
586     const IntRangeVector &R = getRanges();
587     size_t E = R.size();
588     for (size_t I = 0; I != E; ++I) {
589       const llvm::APSInt &Min = BVF.getValue(R[I].first, T);
590       const llvm::APSInt &Max = BVF.getValue(R[I].second, T);
591       assert(Min <= Max);
592       State = CM.assumeInclusiveRange(State, *N, Min, Max, false);
593       if (!State)
594         break;
595     }
596   }
597 
598   return State;
599 }
600 
601 ProgramStateRef StdLibraryFunctionsChecker::RangeConstraint::applyAsWithinRange(
602     ProgramStateRef State, const CallEvent &Call,
603     const Summary &Summary) const {
604   if (Ranges.empty())
605     return State;
606 
607   ProgramStateManager &Mgr = State->getStateManager();
608   SValBuilder &SVB = Mgr.getSValBuilder();
609   BasicValueFactory &BVF = SVB.getBasicValueFactory();
610   ConstraintManager &CM = Mgr.getConstraintManager();
611   QualType T = Summary.getArgType(getArgNo());
612   SVal V = getArgSVal(Call, getArgNo());
613 
614   // "WithinRange R" is treated as "outside [T_MIN, T_MAX] \ R".
615   // We cut off [T_MIN, min(R) - 1] and [max(R) + 1, T_MAX] if necessary,
616   // and then cut away all holes in R one by one.
617   //
618   // E.g. consider a range list R as [A, B] and [C, D]
619   // -------+--------+------------------+------------+----------->
620   //        A        B                  C            D
621   // Then we assume that the value is not in [-inf, A - 1],
622   // then not in [D + 1, +inf], then not in [B + 1, C - 1]
623   if (auto N = V.getAs<NonLoc>()) {
624     const IntRangeVector &R = getRanges();
625     size_t E = R.size();
626 
627     const llvm::APSInt &MinusInf = BVF.getMinValue(T);
628     const llvm::APSInt &PlusInf = BVF.getMaxValue(T);
629 
630     const llvm::APSInt &Left = BVF.getValue(R[0].first - 1ULL, T);
631     if (Left != PlusInf) {
632       assert(MinusInf <= Left);
633       State = CM.assumeInclusiveRange(State, *N, MinusInf, Left, false);
634       if (!State)
635         return nullptr;
636     }
637 
638     const llvm::APSInt &Right = BVF.getValue(R[E - 1].second + 1ULL, T);
639     if (Right != MinusInf) {
640       assert(Right <= PlusInf);
641       State = CM.assumeInclusiveRange(State, *N, Right, PlusInf, false);
642       if (!State)
643         return nullptr;
644     }
645 
646     for (size_t I = 1; I != E; ++I) {
647       const llvm::APSInt &Min = BVF.getValue(R[I - 1].second + 1ULL, T);
648       const llvm::APSInt &Max = BVF.getValue(R[I].first - 1ULL, T);
649       if (Min <= Max) {
650         State = CM.assumeInclusiveRange(State, *N, Min, Max, false);
651         if (!State)
652           return nullptr;
653       }
654     }
655   }
656 
657   return State;
658 }
659 
660 ProgramStateRef StdLibraryFunctionsChecker::ComparisonConstraint::apply(
661     ProgramStateRef State, const CallEvent &Call, const Summary &Summary,
662     CheckerContext &C) const {
663 
664   ProgramStateManager &Mgr = State->getStateManager();
665   SValBuilder &SVB = Mgr.getSValBuilder();
666   QualType CondT = SVB.getConditionType();
667   QualType T = Summary.getArgType(getArgNo());
668   SVal V = getArgSVal(Call, getArgNo());
669 
670   BinaryOperator::Opcode Op = getOpcode();
671   ArgNo OtherArg = getOtherArgNo();
672   SVal OtherV = getArgSVal(Call, OtherArg);
673   QualType OtherT = Summary.getArgType(OtherArg);
674   // Note: we avoid integral promotion for comparison.
675   OtherV = SVB.evalCast(OtherV, T, OtherT);
676   if (auto CompV = SVB.evalBinOp(State, Op, V, OtherV, CondT)
677                        .getAs<DefinedOrUnknownSVal>())
678     State = State->assume(*CompV, true);
679   return State;
680 }
681 
682 void StdLibraryFunctionsChecker::checkPreCall(const CallEvent &Call,
683                                               CheckerContext &C) const {
684   Optional<Summary> FoundSummary = findFunctionSummary(Call, C);
685   if (!FoundSummary)
686     return;
687 
688   const Summary &Summary = *FoundSummary;
689   ProgramStateRef State = C.getState();
690 
691   ProgramStateRef NewState = State;
692   for (const ValueConstraintPtr &Constraint : Summary.getArgConstraints()) {
693     ProgramStateRef SuccessSt = Constraint->apply(NewState, Call, Summary, C);
694     ProgramStateRef FailureSt =
695         Constraint->negate()->apply(NewState, Call, Summary, C);
696     // The argument constraint is not satisfied.
697     if (FailureSt && !SuccessSt) {
698       if (ExplodedNode *N = C.generateErrorNode(NewState))
699         reportBug(Call, N, C);
700       break;
701     } else {
702       // We will apply the constraint even if we cannot reason about the
703       // argument. This means both SuccessSt and FailureSt can be true. If we
704       // weren't applying the constraint that would mean that symbolic
705       // execution continues on a code whose behaviour is undefined.
706       assert(SuccessSt);
707       NewState = SuccessSt;
708     }
709   }
710   if (NewState && NewState != State)
711     C.addTransition(NewState);
712 }
713 
714 void StdLibraryFunctionsChecker::checkPostCall(const CallEvent &Call,
715                                                CheckerContext &C) const {
716   Optional<Summary> FoundSummary = findFunctionSummary(Call, C);
717   if (!FoundSummary)
718     return;
719 
720   // Now apply the constraints.
721   const Summary &Summary = *FoundSummary;
722   ProgramStateRef State = C.getState();
723 
724   // Apply case/branch specifications.
725   for (const ConstraintSet &Case : Summary.getCaseConstraints()) {
726     ProgramStateRef NewState = State;
727     for (const ValueConstraintPtr &Constraint : Case) {
728       NewState = Constraint->apply(NewState, Call, Summary, C);
729       if (!NewState)
730         break;
731     }
732 
733     if (NewState && NewState != State)
734       C.addTransition(NewState);
735   }
736 }
737 
738 bool StdLibraryFunctionsChecker::evalCall(const CallEvent &Call,
739                                           CheckerContext &C) const {
740   Optional<Summary> FoundSummary = findFunctionSummary(Call, C);
741   if (!FoundSummary)
742     return false;
743 
744   const Summary &Summary = *FoundSummary;
745   switch (Summary.getInvalidationKd()) {
746   case EvalCallAsPure: {
747     ProgramStateRef State = C.getState();
748     const LocationContext *LC = C.getLocationContext();
749     const auto *CE = cast_or_null<CallExpr>(Call.getOriginExpr());
750     SVal V = C.getSValBuilder().conjureSymbolVal(
751         CE, LC, CE->getType().getCanonicalType(), C.blockCount());
752     State = State->BindExpr(CE, LC, V);
753     C.addTransition(State);
754     return true;
755   }
756   case NoEvalCall:
757     // Summary tells us to avoid performing eval::Call. The function is possibly
758     // evaluated by another checker, or evaluated conservatively.
759     return false;
760   }
761   llvm_unreachable("Unknown invalidation kind!");
762 }
763 
764 bool StdLibraryFunctionsChecker::Signature::matches(
765     const FunctionDecl *FD) const {
766   assert(!isInvalid());
767   // Check the number of arguments.
768   if (FD->param_size() != ArgTys.size())
769     return false;
770 
771   // The "restrict" keyword is illegal in C++, however, many libc
772   // implementations use the "__restrict" compiler intrinsic in functions
773   // prototypes. The "__restrict" keyword qualifies a type as a restricted type
774   // even in C++.
775   // In case of any non-C99 languages, we don't want to match based on the
776   // restrict qualifier because we cannot know if the given libc implementation
777   // qualifies the paramter type or not.
778   auto RemoveRestrict = [&FD](QualType T) {
779     if (!FD->getASTContext().getLangOpts().C99)
780       T.removeLocalRestrict();
781     return T;
782   };
783 
784   // Check the return type.
785   if (!isIrrelevant(RetTy)) {
786     QualType FDRetTy = RemoveRestrict(FD->getReturnType().getCanonicalType());
787     if (RetTy != FDRetTy)
788       return false;
789   }
790 
791   // Check the argument types.
792   for (size_t I = 0, E = ArgTys.size(); I != E; ++I) {
793     QualType ArgTy = ArgTys[I];
794     if (isIrrelevant(ArgTy))
795       continue;
796     QualType FDArgTy =
797         RemoveRestrict(FD->getParamDecl(I)->getType().getCanonicalType());
798     if (ArgTy != FDArgTy)
799       return false;
800   }
801 
802   return true;
803 }
804 
805 Optional<StdLibraryFunctionsChecker::Summary>
806 StdLibraryFunctionsChecker::findFunctionSummary(const FunctionDecl *FD,
807                                                 CheckerContext &C) const {
808   if (!FD)
809     return None;
810 
811   initFunctionSummaries(C);
812 
813   auto FSMI = FunctionSummaryMap.find(FD->getCanonicalDecl());
814   if (FSMI == FunctionSummaryMap.end())
815     return None;
816   return FSMI->second;
817 }
818 
819 Optional<StdLibraryFunctionsChecker::Summary>
820 StdLibraryFunctionsChecker::findFunctionSummary(const CallEvent &Call,
821                                                 CheckerContext &C) const {
822   const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
823   if (!FD)
824     return None;
825   return findFunctionSummary(FD, C);
826 }
827 
828 void StdLibraryFunctionsChecker::initFunctionSummaries(
829     CheckerContext &C) const {
830   if (!FunctionSummaryMap.empty())
831     return;
832 
833   SValBuilder &SVB = C.getSValBuilder();
834   BasicValueFactory &BVF = SVB.getBasicValueFactory();
835   const ASTContext &ACtx = BVF.getContext();
836 
837   // Helper class to lookup a type by its name.
838   class LookupType {
839     const ASTContext &ACtx;
840 
841   public:
842     LookupType(const ASTContext &ACtx) : ACtx(ACtx) {}
843 
844     // Find the type. If not found then the optional is not set.
845     llvm::Optional<QualType> operator()(StringRef Name) {
846       IdentifierInfo &II = ACtx.Idents.get(Name);
847       auto LookupRes = ACtx.getTranslationUnitDecl()->lookup(&II);
848       if (LookupRes.size() == 0)
849         return None;
850 
851       // Prioritze typedef declarations.
852       // This is needed in case of C struct typedefs. E.g.:
853       //   typedef struct FILE FILE;
854       // In this case, we have a RecordDecl 'struct FILE' with the name 'FILE'
855       // and we have a TypedefDecl with the name 'FILE'.
856       for (Decl *D : LookupRes)
857         if (auto *TD = dyn_cast<TypedefNameDecl>(D))
858           return ACtx.getTypeDeclType(TD).getCanonicalType();
859 
860       // Find the first TypeDecl.
861       // There maybe cases when a function has the same name as a struct.
862       // E.g. in POSIX: `struct stat` and the function `stat()`:
863       //   int stat(const char *restrict path, struct stat *restrict buf);
864       for (Decl *D : LookupRes)
865         if (auto *TD = dyn_cast<TypeDecl>(D))
866           return ACtx.getTypeDeclType(TD).getCanonicalType();
867       return None;
868     }
869   } lookupTy(ACtx);
870 
871   // Below are auxiliary classes to handle optional types that we get as a
872   // result of the lookup.
873   class GetRestrictTy {
874     const ASTContext &ACtx;
875 
876   public:
877     GetRestrictTy(const ASTContext &ACtx) : ACtx(ACtx) {}
878     QualType operator()(QualType Ty) {
879       return ACtx.getLangOpts().C99 ? ACtx.getRestrictType(Ty) : Ty;
880     }
881     Optional<QualType> operator()(Optional<QualType> Ty) {
882       if (Ty)
883         return operator()(*Ty);
884       return None;
885     }
886   } getRestrictTy(ACtx);
887   class GetPointerTy {
888     const ASTContext &ACtx;
889 
890   public:
891     GetPointerTy(const ASTContext &ACtx) : ACtx(ACtx) {}
892     QualType operator()(QualType Ty) { return ACtx.getPointerType(Ty); }
893     Optional<QualType> operator()(Optional<QualType> Ty) {
894       if (Ty)
895         return operator()(*Ty);
896       return None;
897     }
898   } getPointerTy(ACtx);
899   class {
900   public:
901     Optional<QualType> operator()(Optional<QualType> Ty) {
902       return Ty ? Optional<QualType>(Ty->withConst()) : None;
903     }
904     QualType operator()(QualType Ty) { return Ty.withConst(); }
905   } getConstTy;
906   class GetMaxValue {
907     BasicValueFactory &BVF;
908 
909   public:
910     GetMaxValue(BasicValueFactory &BVF) : BVF(BVF) {}
911     Optional<RangeInt> operator()(QualType Ty) {
912       return BVF.getMaxValue(Ty).getLimitedValue();
913     }
914     Optional<RangeInt> operator()(Optional<QualType> Ty) {
915       if (Ty) {
916         return operator()(*Ty);
917       }
918       return None;
919     }
920   } getMaxValue(BVF);
921 
922   // These types are useful for writing specifications quickly,
923   // New specifications should probably introduce more types.
924   // Some types are hard to obtain from the AST, eg. "ssize_t".
925   // In such cases it should be possible to provide multiple variants
926   // of function summary for common cases (eg. ssize_t could be int or long
927   // or long long, so three summary variants would be enough).
928   // Of course, function variants are also useful for C++ overloads.
929   const QualType VoidTy = ACtx.VoidTy;
930   const QualType CharTy = ACtx.CharTy;
931   const QualType WCharTy = ACtx.WCharTy;
932   const QualType IntTy = ACtx.IntTy;
933   const QualType UnsignedIntTy = ACtx.UnsignedIntTy;
934   const QualType LongTy = ACtx.LongTy;
935   const QualType LongLongTy = ACtx.LongLongTy;
936   const QualType SizeTy = ACtx.getSizeType();
937 
938   const QualType VoidPtrTy = getPointerTy(VoidTy); // void *
939   const QualType IntPtrTy = getPointerTy(IntTy);   // int *
940   const QualType UnsignedIntPtrTy =
941       getPointerTy(UnsignedIntTy); // unsigned int *
942   const QualType VoidPtrRestrictTy = getRestrictTy(VoidPtrTy);
943   const QualType ConstVoidPtrTy =
944       getPointerTy(getConstTy(VoidTy));            // const void *
945   const QualType CharPtrTy = getPointerTy(CharTy); // char *
946   const QualType CharPtrRestrictTy = getRestrictTy(CharPtrTy);
947   const QualType ConstCharPtrTy =
948       getPointerTy(getConstTy(CharTy)); // const char *
949   const QualType ConstCharPtrRestrictTy = getRestrictTy(ConstCharPtrTy);
950   const QualType Wchar_tPtrTy = getPointerTy(WCharTy); // wchar_t *
951   const QualType ConstWchar_tPtrTy =
952       getPointerTy(getConstTy(WCharTy)); // const wchar_t *
953   const QualType ConstVoidPtrRestrictTy = getRestrictTy(ConstVoidPtrTy);
954 
955   const RangeInt IntMax = BVF.getMaxValue(IntTy).getLimitedValue();
956   const RangeInt UnsignedIntMax =
957       BVF.getMaxValue(UnsignedIntTy).getLimitedValue();
958   const RangeInt LongMax = BVF.getMaxValue(LongTy).getLimitedValue();
959   const RangeInt LongLongMax = BVF.getMaxValue(LongLongTy).getLimitedValue();
960   const RangeInt SizeMax = BVF.getMaxValue(SizeTy).getLimitedValue();
961 
962   // Set UCharRangeMax to min of int or uchar maximum value.
963   // The C standard states that the arguments of functions like isalpha must
964   // be representable as an unsigned char. Their type is 'int', so the max
965   // value of the argument should be min(UCharMax, IntMax). This just happen
966   // to be true for commonly used and well tested instruction set
967   // architectures, but not for others.
968   const RangeInt UCharRangeMax =
969       std::min(BVF.getMaxValue(ACtx.UnsignedCharTy).getLimitedValue(), IntMax);
970 
971   // The platform dependent value of EOF.
972   // Try our best to parse this from the Preprocessor, otherwise fallback to -1.
973   const auto EOFv = [&C]() -> RangeInt {
974     if (const llvm::Optional<int> OptInt =
975             tryExpandAsInteger("EOF", C.getPreprocessor()))
976       return *OptInt;
977     return -1;
978   }();
979 
980   // Auxiliary class to aid adding summaries to the summary map.
981   struct AddToFunctionSummaryMap {
982     const ASTContext &ACtx;
983     FunctionSummaryMapType &Map;
984     bool DisplayLoadedSummaries;
985     AddToFunctionSummaryMap(const ASTContext &ACtx, FunctionSummaryMapType &FSM,
986                             bool DisplayLoadedSummaries)
987         : ACtx(ACtx), Map(FSM), DisplayLoadedSummaries(DisplayLoadedSummaries) {
988     }
989 
990     // Add a summary to a FunctionDecl found by lookup. The lookup is performed
991     // by the given Name, and in the global scope. The summary will be attached
992     // to the found FunctionDecl only if the signatures match.
993     //
994     // Returns true if the summary has been added, false otherwise.
995     // FIXME remove all overloads without the explicit Signature parameter.
996     bool operator()(StringRef Name, Summary S) {
997       if (S.hasInvalidSignature())
998         return false;
999       IdentifierInfo &II = ACtx.Idents.get(Name);
1000       auto LookupRes = ACtx.getTranslationUnitDecl()->lookup(&II);
1001       if (LookupRes.size() == 0)
1002         return false;
1003       for (Decl *D : LookupRes) {
1004         if (auto *FD = dyn_cast<FunctionDecl>(D)) {
1005           if (S.matchesAndSet(FD)) {
1006             auto Res = Map.insert({FD->getCanonicalDecl(), S});
1007             assert(Res.second && "Function already has a summary set!");
1008             (void)Res;
1009             if (DisplayLoadedSummaries) {
1010               llvm::errs() << "Loaded summary for: ";
1011               FD->print(llvm::errs());
1012               llvm::errs() << "\n";
1013             }
1014             return true;
1015           }
1016         }
1017       }
1018       return false;
1019     }
1020     // Add the summary with the Signature explicitly given.
1021     bool operator()(StringRef Name, Signature Sign, Summary Sum) {
1022       return operator()(Name, Sum.setSignature(Sign));
1023     }
1024     // Add several summaries for the given name.
1025     void operator()(StringRef Name, const std::vector<Summary> &Summaries) {
1026       for (const Summary &S : Summaries)
1027         operator()(Name, S);
1028     }
1029     // Add the same summary for different names with the Signature explicitly
1030     // given.
1031     void operator()(std::vector<StringRef> Names, Signature Sign, Summary Sum) {
1032       for (StringRef Name : Names)
1033         operator()(Name, Sign, Sum);
1034     }
1035   } addToFunctionSummaryMap(ACtx, FunctionSummaryMap, DisplayLoadedSummaries);
1036 
1037   // Below are helpers functions to create the summaries.
1038   auto ArgumentCondition = [](ArgNo ArgN, RangeKind Kind,
1039                               IntRangeVector Ranges) {
1040     return std::make_shared<RangeConstraint>(ArgN, Kind, Ranges);
1041   };
1042   auto BufferSize = [](auto... Args) {
1043     return std::make_shared<BufferSizeConstraint>(Args...);
1044   };
1045   struct {
1046     auto operator()(RangeKind Kind, IntRangeVector Ranges) {
1047       return std::make_shared<RangeConstraint>(Ret, Kind, Ranges);
1048     }
1049     auto operator()(BinaryOperator::Opcode Op, ArgNo OtherArgN) {
1050       return std::make_shared<ComparisonConstraint>(Ret, Op, OtherArgN);
1051     }
1052   } ReturnValueCondition;
1053   struct {
1054     auto operator()(RangeInt b, RangeInt e) {
1055       return IntRangeVector{std::pair<RangeInt, RangeInt>{b, e}};
1056     }
1057     auto operator()(RangeInt b, Optional<RangeInt> e) {
1058       if (e)
1059         return IntRangeVector{std::pair<RangeInt, RangeInt>{b, *e}};
1060       return IntRangeVector{};
1061     }
1062   } Range;
1063   auto SingleValue = [](RangeInt v) {
1064     return IntRangeVector{std::pair<RangeInt, RangeInt>{v, v}};
1065   };
1066   auto LessThanOrEq = BO_LE;
1067   auto NotNull = [&](ArgNo ArgN) {
1068     return std::make_shared<NotNullConstraint>(ArgN);
1069   };
1070 
1071   Optional<QualType> FileTy = lookupTy("FILE");
1072   Optional<QualType> FilePtrTy = getPointerTy(FileTy);
1073   Optional<QualType> FilePtrRestrictTy = getRestrictTy(FilePtrTy);
1074 
1075   // Templates for summaries that are reused by many functions.
1076   auto Getc = [&]() {
1077     return Summary(ArgTypes{FilePtrTy}, RetType{IntTy}, NoEvalCall)
1078         .Case({ReturnValueCondition(WithinRange,
1079                                     {{EOFv, EOFv}, {0, UCharRangeMax}})});
1080   };
1081   auto Read = [&](RetType R, RangeInt Max) {
1082     return Summary(ArgTypes{Irrelevant, Irrelevant, SizeTy}, RetType{R},
1083                    NoEvalCall)
1084         .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)),
1085                ReturnValueCondition(WithinRange, Range(-1, Max))});
1086   };
1087   auto Fread = [&]() {
1088     return Summary(
1089                ArgTypes{VoidPtrRestrictTy, SizeTy, SizeTy, FilePtrRestrictTy},
1090                RetType{SizeTy}, NoEvalCall)
1091         .Case({
1092             ReturnValueCondition(LessThanOrEq, ArgNo(2)),
1093         })
1094         .ArgConstraint(NotNull(ArgNo(0)));
1095   };
1096   auto Fwrite = [&]() {
1097     return Summary(ArgTypes{ConstVoidPtrRestrictTy, SizeTy, SizeTy,
1098                             FilePtrRestrictTy},
1099                    RetType{SizeTy}, NoEvalCall)
1100         .Case({
1101             ReturnValueCondition(LessThanOrEq, ArgNo(2)),
1102         })
1103         .ArgConstraint(NotNull(ArgNo(0)));
1104   };
1105   auto Getline = [&](RetType R, RangeInt Max) {
1106     return Summary(ArgTypes{Irrelevant, Irrelevant, Irrelevant}, RetType{R},
1107                    NoEvalCall)
1108         .Case({ReturnValueCondition(WithinRange, {{-1, -1}, {1, Max}})});
1109   };
1110 
1111   // We are finally ready to define specifications for all supported functions.
1112   //
1113   // Argument ranges should always cover all variants. If return value
1114   // is completely unknown, omit it from the respective range set.
1115   //
1116   // Every item in the list of range sets represents a particular
1117   // execution path the analyzer would need to explore once
1118   // the call is modeled - a new program state is constructed
1119   // for every range set, and each range line in the range set
1120   // corresponds to a specific constraint within this state.
1121 
1122   // The isascii() family of functions.
1123   // The behavior is undefined if the value of the argument is not
1124   // representable as unsigned char or is not equal to EOF. See e.g. C99
1125   // 7.4.1.2 The isalpha function (p: 181-182).
1126   addToFunctionSummaryMap(
1127       "isalnum",
1128       Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
1129           // Boils down to isupper() or islower() or isdigit().
1130           .Case({ArgumentCondition(0U, WithinRange,
1131                                    {{'0', '9'}, {'A', 'Z'}, {'a', 'z'}}),
1132                  ReturnValueCondition(OutOfRange, SingleValue(0))})
1133           // The locale-specific range.
1134           // No post-condition. We are completely unaware of
1135           // locale-specific return values.
1136           .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})})
1137           .Case(
1138               {ArgumentCondition(
1139                    0U, OutOfRange,
1140                    {{'0', '9'}, {'A', 'Z'}, {'a', 'z'}, {128, UCharRangeMax}}),
1141                ReturnValueCondition(WithinRange, SingleValue(0))})
1142           .ArgConstraint(ArgumentCondition(
1143               0U, WithinRange, {{EOFv, EOFv}, {0, UCharRangeMax}})));
1144   addToFunctionSummaryMap(
1145       "isalpha",
1146       Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
1147           .Case({ArgumentCondition(0U, WithinRange, {{'A', 'Z'}, {'a', 'z'}}),
1148                  ReturnValueCondition(OutOfRange, SingleValue(0))})
1149           // The locale-specific range.
1150           .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})})
1151           .Case({ArgumentCondition(
1152                      0U, OutOfRange,
1153                      {{'A', 'Z'}, {'a', 'z'}, {128, UCharRangeMax}}),
1154                  ReturnValueCondition(WithinRange, SingleValue(0))}));
1155   addToFunctionSummaryMap(
1156       "isascii",
1157       Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
1158           .Case({ArgumentCondition(0U, WithinRange, Range(0, 127)),
1159                  ReturnValueCondition(OutOfRange, SingleValue(0))})
1160           .Case({ArgumentCondition(0U, OutOfRange, Range(0, 127)),
1161                  ReturnValueCondition(WithinRange, SingleValue(0))}));
1162   addToFunctionSummaryMap(
1163       "isblank",
1164       Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
1165           .Case({ArgumentCondition(0U, WithinRange, {{'\t', '\t'}, {' ', ' '}}),
1166                  ReturnValueCondition(OutOfRange, SingleValue(0))})
1167           .Case({ArgumentCondition(0U, OutOfRange, {{'\t', '\t'}, {' ', ' '}}),
1168                  ReturnValueCondition(WithinRange, SingleValue(0))}));
1169   addToFunctionSummaryMap(
1170       "iscntrl",
1171       Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
1172           .Case({ArgumentCondition(0U, WithinRange, {{0, 32}, {127, 127}}),
1173                  ReturnValueCondition(OutOfRange, SingleValue(0))})
1174           .Case({ArgumentCondition(0U, OutOfRange, {{0, 32}, {127, 127}}),
1175                  ReturnValueCondition(WithinRange, SingleValue(0))}));
1176   addToFunctionSummaryMap(
1177       "isdigit",
1178       Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
1179           .Case({ArgumentCondition(0U, WithinRange, Range('0', '9')),
1180                  ReturnValueCondition(OutOfRange, SingleValue(0))})
1181           .Case({ArgumentCondition(0U, OutOfRange, Range('0', '9')),
1182                  ReturnValueCondition(WithinRange, SingleValue(0))}));
1183   addToFunctionSummaryMap(
1184       "isgraph",
1185       Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
1186           .Case({ArgumentCondition(0U, WithinRange, Range(33, 126)),
1187                  ReturnValueCondition(OutOfRange, SingleValue(0))})
1188           .Case({ArgumentCondition(0U, OutOfRange, Range(33, 126)),
1189                  ReturnValueCondition(WithinRange, SingleValue(0))}));
1190   addToFunctionSummaryMap(
1191       "islower",
1192       Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
1193           // Is certainly lowercase.
1194           .Case({ArgumentCondition(0U, WithinRange, Range('a', 'z')),
1195                  ReturnValueCondition(OutOfRange, SingleValue(0))})
1196           // Is ascii but not lowercase.
1197           .Case({ArgumentCondition(0U, WithinRange, Range(0, 127)),
1198                  ArgumentCondition(0U, OutOfRange, Range('a', 'z')),
1199                  ReturnValueCondition(WithinRange, SingleValue(0))})
1200           // The locale-specific range.
1201           .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})})
1202           // Is not an unsigned char.
1203           .Case({ArgumentCondition(0U, OutOfRange, Range(0, UCharRangeMax)),
1204                  ReturnValueCondition(WithinRange, SingleValue(0))}));
1205   addToFunctionSummaryMap(
1206       "isprint",
1207       Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
1208           .Case({ArgumentCondition(0U, WithinRange, Range(32, 126)),
1209                  ReturnValueCondition(OutOfRange, SingleValue(0))})
1210           .Case({ArgumentCondition(0U, OutOfRange, Range(32, 126)),
1211                  ReturnValueCondition(WithinRange, SingleValue(0))}));
1212   addToFunctionSummaryMap(
1213       "ispunct",
1214       Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
1215           .Case({ArgumentCondition(
1216                      0U, WithinRange,
1217                      {{'!', '/'}, {':', '@'}, {'[', '`'}, {'{', '~'}}),
1218                  ReturnValueCondition(OutOfRange, SingleValue(0))})
1219           .Case({ArgumentCondition(
1220                      0U, OutOfRange,
1221                      {{'!', '/'}, {':', '@'}, {'[', '`'}, {'{', '~'}}),
1222                  ReturnValueCondition(WithinRange, SingleValue(0))}));
1223   addToFunctionSummaryMap(
1224       "isspace",
1225       Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
1226           // Space, '\f', '\n', '\r', '\t', '\v'.
1227           .Case({ArgumentCondition(0U, WithinRange, {{9, 13}, {' ', ' '}}),
1228                  ReturnValueCondition(OutOfRange, SingleValue(0))})
1229           // The locale-specific range.
1230           .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})})
1231           .Case({ArgumentCondition(0U, OutOfRange,
1232                                    {{9, 13}, {' ', ' '}, {128, UCharRangeMax}}),
1233                  ReturnValueCondition(WithinRange, SingleValue(0))}));
1234   addToFunctionSummaryMap(
1235       "isupper",
1236       Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
1237           // Is certainly uppercase.
1238           .Case({ArgumentCondition(0U, WithinRange, Range('A', 'Z')),
1239                  ReturnValueCondition(OutOfRange, SingleValue(0))})
1240           // The locale-specific range.
1241           .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})})
1242           // Other.
1243           .Case({ArgumentCondition(0U, OutOfRange,
1244                                    {{'A', 'Z'}, {128, UCharRangeMax}}),
1245                  ReturnValueCondition(WithinRange, SingleValue(0))}));
1246   addToFunctionSummaryMap(
1247       "isxdigit",
1248       Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
1249           .Case({ArgumentCondition(0U, WithinRange,
1250                                    {{'0', '9'}, {'A', 'F'}, {'a', 'f'}}),
1251                  ReturnValueCondition(OutOfRange, SingleValue(0))})
1252           .Case({ArgumentCondition(0U, OutOfRange,
1253                                    {{'0', '9'}, {'A', 'F'}, {'a', 'f'}}),
1254                  ReturnValueCondition(WithinRange, SingleValue(0))}));
1255   addToFunctionSummaryMap(
1256       "toupper", Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
1257                      .ArgConstraint(ArgumentCondition(
1258                          0U, WithinRange, {{EOFv, EOFv}, {0, UCharRangeMax}})));
1259   addToFunctionSummaryMap(
1260       "tolower", Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
1261                      .ArgConstraint(ArgumentCondition(
1262                          0U, WithinRange, {{EOFv, EOFv}, {0, UCharRangeMax}})));
1263   addToFunctionSummaryMap(
1264       "toascii", Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
1265                      .ArgConstraint(ArgumentCondition(
1266                          0U, WithinRange, {{EOFv, EOFv}, {0, UCharRangeMax}})));
1267 
1268   // The getc() family of functions that returns either a char or an EOF.
1269     addToFunctionSummaryMap("getc", Getc());
1270     addToFunctionSummaryMap("fgetc", Getc());
1271   addToFunctionSummaryMap(
1272       "getchar", Summary(ArgTypes{}, RetType{IntTy}, NoEvalCall)
1273                      .Case({ReturnValueCondition(
1274                          WithinRange, {{EOFv, EOFv}, {0, UCharRangeMax}})}));
1275 
1276   // read()-like functions that never return more than buffer size.
1277     addToFunctionSummaryMap("fread", Fread());
1278     addToFunctionSummaryMap("fwrite", Fwrite());
1279 
1280   // We are not sure how ssize_t is defined on every platform, so we
1281   // provide three variants that should cover common cases.
1282   // FIXME these are actually defined by POSIX and not by the C standard, we
1283   // should handle them together with the rest of the POSIX functions.
1284   addToFunctionSummaryMap("read", {Read(IntTy, IntMax), Read(LongTy, LongMax),
1285                                    Read(LongLongTy, LongLongMax)});
1286   addToFunctionSummaryMap("write", {Read(IntTy, IntMax), Read(LongTy, LongMax),
1287                                     Read(LongLongTy, LongLongMax)});
1288 
1289   // getline()-like functions either fail or read at least the delimiter.
1290   // FIXME these are actually defined by POSIX and not by the C standard, we
1291   // should handle them together with the rest of the POSIX functions.
1292   addToFunctionSummaryMap("getline",
1293                           {Getline(IntTy, IntMax), Getline(LongTy, LongMax),
1294                            Getline(LongLongTy, LongLongMax)});
1295   addToFunctionSummaryMap("getdelim",
1296                           {Getline(IntTy, IntMax), Getline(LongTy, LongMax),
1297                            Getline(LongLongTy, LongLongMax)});
1298 
1299   if (ModelPOSIX) {
1300 
1301     // long a64l(const char *str64);
1302     addToFunctionSummaryMap(
1303         "a64l", Summary(ArgTypes{ConstCharPtrTy}, RetType{LongTy}, NoEvalCall)
1304                     .ArgConstraint(NotNull(ArgNo(0))));
1305 
1306     // char *l64a(long value);
1307     addToFunctionSummaryMap(
1308         "l64a", Summary(ArgTypes{LongTy}, RetType{CharPtrTy}, NoEvalCall)
1309                     .ArgConstraint(
1310                         ArgumentCondition(0, WithinRange, Range(0, LongMax))));
1311 
1312     // int access(const char *pathname, int amode);
1313     addToFunctionSummaryMap("access", Summary(ArgTypes{ConstCharPtrTy, IntTy},
1314                                               RetType{IntTy}, NoEvalCall)
1315                                           .ArgConstraint(NotNull(ArgNo(0))));
1316 
1317     // int faccessat(int dirfd, const char *pathname, int mode, int flags);
1318     addToFunctionSummaryMap(
1319         "faccessat", Summary(ArgTypes{IntTy, ConstCharPtrTy, IntTy, IntTy},
1320                              RetType{IntTy}, NoEvalCall)
1321                          .ArgConstraint(NotNull(ArgNo(1))));
1322 
1323     // int dup(int fildes);
1324     addToFunctionSummaryMap(
1325         "dup", Summary(ArgTypes{IntTy}, RetType{IntTy}, NoEvalCall)
1326                    .ArgConstraint(
1327                        ArgumentCondition(0, WithinRange, Range(0, IntMax))));
1328 
1329     // int dup2(int fildes1, int filedes2);
1330     addToFunctionSummaryMap(
1331         "dup2",
1332         Summary(ArgTypes{IntTy, IntTy}, RetType{IntTy}, NoEvalCall)
1333             .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
1334             .ArgConstraint(
1335                 ArgumentCondition(1, WithinRange, Range(0, IntMax))));
1336 
1337     // int fdatasync(int fildes);
1338     addToFunctionSummaryMap(
1339         "fdatasync", Summary(ArgTypes{IntTy}, RetType{IntTy}, NoEvalCall)
1340                          .ArgConstraint(ArgumentCondition(0, WithinRange,
1341                                                           Range(0, IntMax))));
1342 
1343     // int fnmatch(const char *pattern, const char *string, int flags);
1344     addToFunctionSummaryMap(
1345         "fnmatch", Summary(ArgTypes{ConstCharPtrTy, ConstCharPtrTy, IntTy},
1346                            RetType{IntTy}, EvalCallAsPure)
1347                        .ArgConstraint(NotNull(ArgNo(0)))
1348                        .ArgConstraint(NotNull(ArgNo(1))));
1349 
1350     // int fsync(int fildes);
1351     addToFunctionSummaryMap(
1352         "fsync", Summary(ArgTypes{IntTy}, RetType{IntTy}, NoEvalCall)
1353                      .ArgConstraint(
1354                          ArgumentCondition(0, WithinRange, Range(0, IntMax))));
1355 
1356     Optional<QualType> Off_tTy = lookupTy("off_t");
1357 
1358     // int truncate(const char *path, off_t length);
1359     addToFunctionSummaryMap(
1360         "truncate",
1361         Summary(ArgTypes{ConstCharPtrTy, Off_tTy}, RetType{IntTy}, NoEvalCall)
1362             .ArgConstraint(NotNull(ArgNo(0))));
1363 
1364     // int symlink(const char *oldpath, const char *newpath);
1365     addToFunctionSummaryMap("symlink",
1366                             Summary(ArgTypes{ConstCharPtrTy, ConstCharPtrTy},
1367                                     RetType{IntTy}, NoEvalCall)
1368                                 .ArgConstraint(NotNull(ArgNo(0)))
1369                                 .ArgConstraint(NotNull(ArgNo(1))));
1370 
1371     // int symlinkat(const char *oldpath, int newdirfd, const char *newpath);
1372     addToFunctionSummaryMap(
1373         "symlinkat",
1374         Summary(ArgTypes{ConstCharPtrTy, IntTy, ConstCharPtrTy}, RetType{IntTy},
1375                 NoEvalCall)
1376             .ArgConstraint(NotNull(ArgNo(0)))
1377             .ArgConstraint(ArgumentCondition(1, WithinRange, Range(0, IntMax)))
1378             .ArgConstraint(NotNull(ArgNo(2))));
1379 
1380     // int lockf(int fd, int cmd, off_t len);
1381     addToFunctionSummaryMap(
1382         "lockf",
1383         Summary(ArgTypes{IntTy, IntTy, Off_tTy}, RetType{IntTy}, NoEvalCall)
1384             .ArgConstraint(
1385                 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
1386 
1387     Optional<QualType> Mode_tTy = lookupTy("mode_t");
1388 
1389     // int creat(const char *pathname, mode_t mode);
1390     addToFunctionSummaryMap("creat", Summary(ArgTypes{ConstCharPtrTy, Mode_tTy},
1391                                              RetType{IntTy}, NoEvalCall)
1392                                          .ArgConstraint(NotNull(ArgNo(0))));
1393 
1394     // unsigned int sleep(unsigned int seconds);
1395     addToFunctionSummaryMap(
1396         "sleep",
1397         Summary(ArgTypes{UnsignedIntTy}, RetType{UnsignedIntTy}, NoEvalCall)
1398             .ArgConstraint(
1399                 ArgumentCondition(0, WithinRange, Range(0, UnsignedIntMax))));
1400 
1401     Optional<QualType> DirTy = lookupTy("DIR");
1402     Optional<QualType> DirPtrTy = getPointerTy(DirTy);
1403 
1404     // int dirfd(DIR *dirp);
1405     addToFunctionSummaryMap(
1406         "dirfd", Summary(ArgTypes{DirPtrTy}, RetType{IntTy}, NoEvalCall)
1407                      .ArgConstraint(NotNull(ArgNo(0))));
1408 
1409     // unsigned int alarm(unsigned int seconds);
1410     addToFunctionSummaryMap(
1411         "alarm",
1412         Summary(ArgTypes{UnsignedIntTy}, RetType{UnsignedIntTy}, NoEvalCall)
1413             .ArgConstraint(
1414                 ArgumentCondition(0, WithinRange, Range(0, UnsignedIntMax))));
1415 
1416     // int closedir(DIR *dir);
1417     addToFunctionSummaryMap(
1418         "closedir", Summary(ArgTypes{DirPtrTy}, RetType{IntTy}, NoEvalCall)
1419                         .ArgConstraint(NotNull(ArgNo(0))));
1420 
1421     // char *strdup(const char *s);
1422     addToFunctionSummaryMap("strdup", Summary(ArgTypes{ConstCharPtrTy},
1423                                               RetType{CharPtrTy}, NoEvalCall)
1424                                           .ArgConstraint(NotNull(ArgNo(0))));
1425 
1426     // char *strndup(const char *s, size_t n);
1427     addToFunctionSummaryMap(
1428         "strndup", Summary(ArgTypes{ConstCharPtrTy, SizeTy}, RetType{CharPtrTy},
1429                            NoEvalCall)
1430                        .ArgConstraint(NotNull(ArgNo(0)))
1431                        .ArgConstraint(ArgumentCondition(1, WithinRange,
1432                                                         Range(0, SizeMax))));
1433 
1434     // wchar_t *wcsdup(const wchar_t *s);
1435     addToFunctionSummaryMap("wcsdup", Summary(ArgTypes{ConstWchar_tPtrTy},
1436                                               RetType{Wchar_tPtrTy}, NoEvalCall)
1437                                           .ArgConstraint(NotNull(ArgNo(0))));
1438 
1439     // int mkstemp(char *template);
1440     addToFunctionSummaryMap(
1441         "mkstemp", Summary(ArgTypes{CharPtrTy}, RetType{IntTy}, NoEvalCall)
1442                        .ArgConstraint(NotNull(ArgNo(0))));
1443 
1444     // char *mkdtemp(char *template);
1445     addToFunctionSummaryMap(
1446         "mkdtemp", Summary(ArgTypes{CharPtrTy}, RetType{CharPtrTy}, NoEvalCall)
1447                        .ArgConstraint(NotNull(ArgNo(0))));
1448 
1449     // char *getcwd(char *buf, size_t size);
1450     addToFunctionSummaryMap(
1451         "getcwd",
1452         Summary(ArgTypes{CharPtrTy, SizeTy}, RetType{CharPtrTy}, NoEvalCall)
1453             .ArgConstraint(
1454                 ArgumentCondition(1, WithinRange, Range(0, SizeMax))));
1455 
1456     // int mkdir(const char *pathname, mode_t mode);
1457     addToFunctionSummaryMap("mkdir", Summary(ArgTypes{ConstCharPtrTy, Mode_tTy},
1458                                              RetType{IntTy}, NoEvalCall)
1459                                          .ArgConstraint(NotNull(ArgNo(0))));
1460 
1461     // int mkdirat(int dirfd, const char *pathname, mode_t mode);
1462     addToFunctionSummaryMap("mkdirat",
1463                             Summary(ArgTypes{IntTy, ConstCharPtrTy, Mode_tTy},
1464                                     RetType{IntTy}, NoEvalCall)
1465                                 .ArgConstraint(NotNull(ArgNo(1))));
1466 
1467     Optional<QualType> Dev_tTy = lookupTy("dev_t");
1468 
1469     // int mknod(const char *pathname, mode_t mode, dev_t dev);
1470     addToFunctionSummaryMap("mknod",
1471                             Summary(ArgTypes{ConstCharPtrTy, Mode_tTy, Dev_tTy},
1472                                     RetType{IntTy}, NoEvalCall)
1473                                 .ArgConstraint(NotNull(ArgNo(0))));
1474 
1475     // int mknodat(int dirfd, const char *pathname, mode_t mode, dev_t dev);
1476     addToFunctionSummaryMap(
1477         "mknodat", Summary(ArgTypes{IntTy, ConstCharPtrTy, Mode_tTy, Dev_tTy},
1478                            RetType{IntTy}, NoEvalCall)
1479                        .ArgConstraint(NotNull(ArgNo(1))));
1480 
1481     // int chmod(const char *path, mode_t mode);
1482     addToFunctionSummaryMap("chmod", Summary(ArgTypes{ConstCharPtrTy, Mode_tTy},
1483                                              RetType{IntTy}, NoEvalCall)
1484                                          .ArgConstraint(NotNull(ArgNo(0))));
1485 
1486     // int fchmodat(int dirfd, const char *pathname, mode_t mode, int flags);
1487     addToFunctionSummaryMap(
1488         "fchmodat",
1489         Summary(ArgTypes{IntTy, ConstCharPtrTy, Mode_tTy, IntTy},
1490                 RetType{IntTy}, NoEvalCall)
1491             .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
1492             .ArgConstraint(NotNull(ArgNo(1))));
1493 
1494     // int fchmod(int fildes, mode_t mode);
1495     addToFunctionSummaryMap(
1496         "fchmod", Summary(ArgTypes{IntTy, Mode_tTy}, RetType{IntTy}, NoEvalCall)
1497                       .ArgConstraint(
1498                           ArgumentCondition(0, WithinRange, Range(0, IntMax))));
1499 
1500     Optional<QualType> Uid_tTy = lookupTy("uid_t");
1501     Optional<QualType> Gid_tTy = lookupTy("gid_t");
1502 
1503     // int fchownat(int dirfd, const char *pathname, uid_t owner, gid_t group,
1504     //              int flags);
1505     addToFunctionSummaryMap(
1506         "fchownat",
1507         Summary(ArgTypes{IntTy, ConstCharPtrTy, Uid_tTy, Gid_tTy, IntTy},
1508                 RetType{IntTy}, NoEvalCall)
1509             .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
1510             .ArgConstraint(NotNull(ArgNo(1))));
1511 
1512     // int chown(const char *path, uid_t owner, gid_t group);
1513     addToFunctionSummaryMap("chown",
1514                             Summary(ArgTypes{ConstCharPtrTy, Uid_tTy, Gid_tTy},
1515                                     RetType{IntTy}, NoEvalCall)
1516                                 .ArgConstraint(NotNull(ArgNo(0))));
1517 
1518     // int lchown(const char *path, uid_t owner, gid_t group);
1519     addToFunctionSummaryMap("lchown",
1520                             Summary(ArgTypes{ConstCharPtrTy, Uid_tTy, Gid_tTy},
1521                                     RetType{IntTy}, NoEvalCall)
1522                                 .ArgConstraint(NotNull(ArgNo(0))));
1523 
1524     // int fchown(int fildes, uid_t owner, gid_t group);
1525     addToFunctionSummaryMap(
1526         "fchown",
1527         Summary(ArgTypes{IntTy, Uid_tTy, Gid_tTy}, RetType{IntTy}, NoEvalCall)
1528             .ArgConstraint(
1529                 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
1530 
1531     // int rmdir(const char *pathname);
1532     addToFunctionSummaryMap(
1533         "rmdir", Summary(ArgTypes{ConstCharPtrTy}, RetType{IntTy}, NoEvalCall)
1534                      .ArgConstraint(NotNull(ArgNo(0))));
1535 
1536     // int chdir(const char *path);
1537     addToFunctionSummaryMap(
1538         "chdir", Summary(ArgTypes{ConstCharPtrTy}, RetType{IntTy}, NoEvalCall)
1539                      .ArgConstraint(NotNull(ArgNo(0))));
1540 
1541     // int link(const char *oldpath, const char *newpath);
1542     addToFunctionSummaryMap("link",
1543                             Summary(ArgTypes{ConstCharPtrTy, ConstCharPtrTy},
1544                                     RetType{IntTy}, NoEvalCall)
1545                                 .ArgConstraint(NotNull(ArgNo(0)))
1546                                 .ArgConstraint(NotNull(ArgNo(1))));
1547 
1548     // int linkat(int fd1, const char *path1, int fd2, const char *path2,
1549     //            int flag);
1550     addToFunctionSummaryMap(
1551         "linkat",
1552         Summary(ArgTypes{IntTy, ConstCharPtrTy, IntTy, ConstCharPtrTy, IntTy},
1553                 RetType{IntTy}, NoEvalCall)
1554             .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
1555             .ArgConstraint(NotNull(ArgNo(1)))
1556             .ArgConstraint(ArgumentCondition(2, WithinRange, Range(0, IntMax)))
1557             .ArgConstraint(NotNull(ArgNo(3))));
1558 
1559     // int unlink(const char *pathname);
1560     addToFunctionSummaryMap(
1561         "unlink", Summary(ArgTypes{ConstCharPtrTy}, RetType{IntTy}, NoEvalCall)
1562                       .ArgConstraint(NotNull(ArgNo(0))));
1563 
1564     // int unlinkat(int fd, const char *path, int flag);
1565     addToFunctionSummaryMap(
1566         "unlinkat",
1567         Summary(ArgTypes{IntTy, ConstCharPtrTy, IntTy}, RetType{IntTy},
1568                 NoEvalCall)
1569             .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
1570             .ArgConstraint(NotNull(ArgNo(1))));
1571 
1572     Optional<QualType> StructStatTy = lookupTy("stat");
1573     Optional<QualType> StructStatPtrTy = getPointerTy(StructStatTy);
1574     Optional<QualType> StructStatPtrRestrictTy = getRestrictTy(StructStatPtrTy);
1575 
1576     // int fstat(int fd, struct stat *statbuf);
1577     addToFunctionSummaryMap(
1578         "fstat",
1579         Summary(ArgTypes{IntTy, StructStatPtrTy}, RetType{IntTy}, NoEvalCall)
1580             .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
1581             .ArgConstraint(NotNull(ArgNo(1))));
1582 
1583     // int stat(const char *restrict path, struct stat *restrict buf);
1584     addToFunctionSummaryMap("stat", Summary(ArgTypes{ConstCharPtrRestrictTy,
1585                                                      StructStatPtrRestrictTy},
1586                                             RetType{IntTy}, NoEvalCall)
1587                                         .ArgConstraint(NotNull(ArgNo(0)))
1588                                         .ArgConstraint(NotNull(ArgNo(1))));
1589 
1590     // int lstat(const char *restrict path, struct stat *restrict buf);
1591     addToFunctionSummaryMap("lstat", Summary(ArgTypes{ConstCharPtrRestrictTy,
1592                                                       StructStatPtrRestrictTy},
1593                                              RetType{IntTy}, NoEvalCall)
1594                                          .ArgConstraint(NotNull(ArgNo(0)))
1595                                          .ArgConstraint(NotNull(ArgNo(1))));
1596 
1597     // int fstatat(int fd, const char *restrict path,
1598     //             struct stat *restrict buf, int flag);
1599     addToFunctionSummaryMap(
1600         "fstatat",
1601         Summary(ArgTypes{IntTy, ConstCharPtrRestrictTy, StructStatPtrRestrictTy,
1602                          IntTy},
1603                 RetType{IntTy}, NoEvalCall)
1604             .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
1605             .ArgConstraint(NotNull(ArgNo(1)))
1606             .ArgConstraint(NotNull(ArgNo(2))));
1607 
1608     // DIR *opendir(const char *name);
1609     addToFunctionSummaryMap("opendir", Summary(ArgTypes{ConstCharPtrTy},
1610                                                RetType{DirPtrTy}, NoEvalCall)
1611                                            .ArgConstraint(NotNull(ArgNo(0))));
1612 
1613     // DIR *fdopendir(int fd);
1614     addToFunctionSummaryMap(
1615         "fdopendir", Summary(ArgTypes{IntTy}, RetType{DirPtrTy}, NoEvalCall)
1616                          .ArgConstraint(ArgumentCondition(0, WithinRange,
1617                                                           Range(0, IntMax))));
1618 
1619     // int isatty(int fildes);
1620     addToFunctionSummaryMap(
1621         "isatty", Summary(ArgTypes{IntTy}, RetType{IntTy}, NoEvalCall)
1622                       .ArgConstraint(
1623                           ArgumentCondition(0, WithinRange, Range(0, IntMax))));
1624 
1625     // FILE *popen(const char *command, const char *type);
1626     addToFunctionSummaryMap("popen",
1627                             Summary(ArgTypes{ConstCharPtrTy, ConstCharPtrTy},
1628                                     RetType{FilePtrTy}, NoEvalCall)
1629                                 .ArgConstraint(NotNull(ArgNo(0)))
1630                                 .ArgConstraint(NotNull(ArgNo(1))));
1631 
1632     // int pclose(FILE *stream);
1633     addToFunctionSummaryMap(
1634         "pclose", Summary(ArgTypes{FilePtrTy}, RetType{IntTy}, NoEvalCall)
1635                       .ArgConstraint(NotNull(ArgNo(0))));
1636 
1637     // int close(int fildes);
1638     addToFunctionSummaryMap(
1639         "close", Summary(ArgTypes{IntTy}, RetType{IntTy}, NoEvalCall)
1640                      .ArgConstraint(
1641                          ArgumentCondition(0, WithinRange, Range(0, IntMax))));
1642 
1643     // long fpathconf(int fildes, int name);
1644     addToFunctionSummaryMap(
1645         "fpathconf",
1646         Summary(ArgTypes{IntTy, IntTy}, RetType{LongTy}, NoEvalCall)
1647             .ArgConstraint(
1648                 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
1649 
1650     // long pathconf(const char *path, int name);
1651     addToFunctionSummaryMap("pathconf", Summary(ArgTypes{ConstCharPtrTy, IntTy},
1652                                                 RetType{LongTy}, NoEvalCall)
1653                                             .ArgConstraint(NotNull(ArgNo(0))));
1654 
1655     // FILE *fdopen(int fd, const char *mode);
1656     addToFunctionSummaryMap(
1657         "fdopen",
1658         Summary(ArgTypes{IntTy, ConstCharPtrTy}, RetType{FilePtrTy}, NoEvalCall)
1659             .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
1660             .ArgConstraint(NotNull(ArgNo(1))));
1661 
1662     // void rewinddir(DIR *dir);
1663     addToFunctionSummaryMap(
1664         "rewinddir", Summary(ArgTypes{DirPtrTy}, RetType{VoidTy}, NoEvalCall)
1665                          .ArgConstraint(NotNull(ArgNo(0))));
1666 
1667     // void seekdir(DIR *dirp, long loc);
1668     addToFunctionSummaryMap("seekdir", Summary(ArgTypes{DirPtrTy, LongTy},
1669                                                RetType{VoidTy}, NoEvalCall)
1670                                            .ArgConstraint(NotNull(ArgNo(0))));
1671 
1672     // int rand_r(unsigned int *seedp);
1673     addToFunctionSummaryMap("rand_r", Summary(ArgTypes{UnsignedIntPtrTy},
1674                                               RetType{IntTy}, NoEvalCall)
1675                                           .ArgConstraint(NotNull(ArgNo(0))));
1676 
1677     // int strcasecmp(const char *s1, const char *s2);
1678     addToFunctionSummaryMap("strcasecmp",
1679                             Summary(ArgTypes{ConstCharPtrTy, ConstCharPtrTy},
1680                                     RetType{IntTy}, EvalCallAsPure)
1681                                 .ArgConstraint(NotNull(ArgNo(0)))
1682                                 .ArgConstraint(NotNull(ArgNo(1))));
1683 
1684     // int strncasecmp(const char *s1, const char *s2, size_t n);
1685     addToFunctionSummaryMap(
1686         "strncasecmp", Summary(ArgTypes{ConstCharPtrTy, ConstCharPtrTy, SizeTy},
1687                                RetType{IntTy}, EvalCallAsPure)
1688                            .ArgConstraint(NotNull(ArgNo(0)))
1689                            .ArgConstraint(NotNull(ArgNo(1)))
1690                            .ArgConstraint(ArgumentCondition(
1691                                2, WithinRange, Range(0, SizeMax))));
1692 
1693     // int fileno(FILE *stream);
1694     addToFunctionSummaryMap(
1695         "fileno", Summary(ArgTypes{FilePtrTy}, RetType{IntTy}, NoEvalCall)
1696                       .ArgConstraint(NotNull(ArgNo(0))));
1697 
1698     // int fseeko(FILE *stream, off_t offset, int whence);
1699     addToFunctionSummaryMap(
1700         "fseeko",
1701         Summary(ArgTypes{FilePtrTy, Off_tTy, IntTy}, RetType{IntTy}, NoEvalCall)
1702             .ArgConstraint(NotNull(ArgNo(0))));
1703 
1704     // off_t ftello(FILE *stream);
1705     addToFunctionSummaryMap(
1706         "ftello", Summary(ArgTypes{FilePtrTy}, RetType{Off_tTy}, NoEvalCall)
1707                       .ArgConstraint(NotNull(ArgNo(0))));
1708 
1709     Optional<RangeInt> Off_tMax = getMaxValue(Off_tTy);
1710     // void *mmap(void *addr, size_t length, int prot, int flags, int fd,
1711     // off_t offset);
1712     addToFunctionSummaryMap(
1713         "mmap",
1714         Summary(ArgTypes{VoidPtrTy, SizeTy, IntTy, IntTy, IntTy, Off_tTy},
1715                 RetType{VoidPtrTy}, NoEvalCall)
1716             .ArgConstraint(ArgumentCondition(1, WithinRange, Range(1, SizeMax)))
1717             .ArgConstraint(
1718                 ArgumentCondition(4, WithinRange, Range(0, Off_tMax))));
1719 
1720     Optional<QualType> Off64_tTy = lookupTy("off64_t");
1721     Optional<RangeInt> Off64_tMax = getMaxValue(Off_tTy);
1722     // void *mmap64(void *addr, size_t length, int prot, int flags, int fd,
1723     // off64_t offset);
1724     addToFunctionSummaryMap(
1725         "mmap64",
1726         Summary(ArgTypes{VoidPtrTy, SizeTy, IntTy, IntTy, IntTy, Off64_tTy},
1727                 RetType{VoidPtrTy}, NoEvalCall)
1728             .ArgConstraint(ArgumentCondition(1, WithinRange, Range(1, SizeMax)))
1729             .ArgConstraint(
1730                 ArgumentCondition(4, WithinRange, Range(0, Off64_tMax))));
1731 
1732     // int pipe(int fildes[2]);
1733     addToFunctionSummaryMap(
1734         "pipe", Summary(ArgTypes{IntPtrTy}, RetType{IntTy}, NoEvalCall)
1735                     .ArgConstraint(NotNull(ArgNo(0))));
1736 
1737     // off_t lseek(int fildes, off_t offset, int whence);
1738     addToFunctionSummaryMap(
1739         "lseek",
1740         Summary(ArgTypes{IntTy, Off_tTy, IntTy}, RetType{Off_tTy}, NoEvalCall)
1741             .ArgConstraint(
1742                 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
1743 
1744     Optional<QualType> Ssize_tTy = lookupTy("ssize_t");
1745 
1746     // ssize_t readlink(const char *restrict path, char *restrict buf,
1747     //                  size_t bufsize);
1748     addToFunctionSummaryMap(
1749         "readlink",
1750         Summary(ArgTypes{ConstCharPtrRestrictTy, CharPtrRestrictTy, SizeTy},
1751                 RetType{Ssize_tTy}, NoEvalCall)
1752             .ArgConstraint(NotNull(ArgNo(0)))
1753             .ArgConstraint(NotNull(ArgNo(1)))
1754             .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
1755                                       /*BufSize=*/ArgNo(2)))
1756             .ArgConstraint(
1757                 ArgumentCondition(2, WithinRange, Range(0, SizeMax))));
1758 
1759     // ssize_t readlinkat(int fd, const char *restrict path,
1760     //                    char *restrict buf, size_t bufsize);
1761     addToFunctionSummaryMap(
1762         "readlinkat",
1763         Summary(
1764             ArgTypes{IntTy, ConstCharPtrRestrictTy, CharPtrRestrictTy, SizeTy},
1765             RetType{Ssize_tTy}, NoEvalCall)
1766             .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
1767             .ArgConstraint(NotNull(ArgNo(1)))
1768             .ArgConstraint(NotNull(ArgNo(2)))
1769             .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(2),
1770                                       /*BufSize=*/ArgNo(3)))
1771             .ArgConstraint(
1772                 ArgumentCondition(3, WithinRange, Range(0, SizeMax))));
1773 
1774     // int renameat(int olddirfd, const char *oldpath, int newdirfd, const char
1775     // *newpath);
1776     addToFunctionSummaryMap("renameat", Summary(ArgTypes{IntTy, ConstCharPtrTy,
1777                                                          IntTy, ConstCharPtrTy},
1778                                                 RetType{IntTy}, NoEvalCall)
1779                                             .ArgConstraint(NotNull(ArgNo(1)))
1780                                             .ArgConstraint(NotNull(ArgNo(3))));
1781 
1782     // char *realpath(const char *restrict file_name,
1783     //                char *restrict resolved_name);
1784     addToFunctionSummaryMap(
1785         "realpath", Summary(ArgTypes{ConstCharPtrRestrictTy, CharPtrRestrictTy},
1786                             RetType{CharPtrTy}, NoEvalCall)
1787                         .ArgConstraint(NotNull(ArgNo(0))));
1788 
1789     QualType CharPtrConstPtr = getPointerTy(getConstTy(CharPtrTy));
1790 
1791     // int execv(const char *path, char *const argv[]);
1792     addToFunctionSummaryMap("execv",
1793                             Summary(ArgTypes{ConstCharPtrTy, CharPtrConstPtr},
1794                                     RetType{IntTy}, NoEvalCall)
1795                                 .ArgConstraint(NotNull(ArgNo(0))));
1796 
1797     // int execvp(const char *file, char *const argv[]);
1798     addToFunctionSummaryMap("execvp",
1799                             Summary(ArgTypes{ConstCharPtrTy, CharPtrConstPtr},
1800                                     RetType{IntTy}, NoEvalCall)
1801                                 .ArgConstraint(NotNull(ArgNo(0))));
1802 
1803     // int getopt(int argc, char * const argv[], const char *optstring);
1804     addToFunctionSummaryMap(
1805         "getopt",
1806         Summary(ArgTypes{IntTy, CharPtrConstPtr, ConstCharPtrTy},
1807                 RetType{IntTy}, NoEvalCall)
1808             .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
1809             .ArgConstraint(NotNull(ArgNo(1)))
1810             .ArgConstraint(NotNull(ArgNo(2))));
1811 
1812     Optional<QualType> StructSockaddrTy = lookupTy("sockaddr");
1813     Optional<QualType> StructSockaddrPtrTy = getPointerTy(StructSockaddrTy);
1814     Optional<QualType> ConstStructSockaddrPtrTy =
1815         getPointerTy(getConstTy(StructSockaddrTy));
1816     Optional<QualType> StructSockaddrPtrRestrictTy =
1817         getRestrictTy(StructSockaddrPtrTy);
1818     Optional<QualType> ConstStructSockaddrPtrRestrictTy =
1819         getRestrictTy(ConstStructSockaddrPtrTy);
1820     Optional<QualType> Socklen_tTy = lookupTy("socklen_t");
1821     Optional<QualType> Socklen_tPtrTy = getPointerTy(Socklen_tTy);
1822     Optional<QualType> Socklen_tPtrRestrictTy = getRestrictTy(Socklen_tPtrTy);
1823     Optional<RangeInt> Socklen_tMax = getMaxValue(Socklen_tTy);
1824 
1825     // In 'socket.h' of some libc implementations with C99, sockaddr parameter
1826     // is a transparent union of the underlying sockaddr_ family of pointers
1827     // instead of being a pointer to struct sockaddr. In these cases, the
1828     // standardized signature will not match, thus we try to match with another
1829     // signature that has the joker Irrelevant type. We also remove those
1830     // constraints which require pointer types for the sockaddr param.
1831     auto Accept =
1832         Summary(NoEvalCall)
1833             .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)));
1834     if (!addToFunctionSummaryMap(
1835             "accept",
1836             // int accept(int socket, struct sockaddr *restrict address,
1837             //            socklen_t *restrict address_len);
1838             Signature(ArgTypes{IntTy, StructSockaddrPtrRestrictTy,
1839                                Socklen_tPtrRestrictTy},
1840                       RetType{IntTy}),
1841             Accept))
1842       addToFunctionSummaryMap(
1843           "accept",
1844           Signature(ArgTypes{IntTy, Irrelevant, Socklen_tPtrRestrictTy},
1845                     RetType{IntTy}),
1846           Accept);
1847 
1848     // int bind(int socket, const struct sockaddr *address, socklen_t
1849     //          address_len);
1850     if (!addToFunctionSummaryMap(
1851             "bind",
1852             Summary(ArgTypes{IntTy, ConstStructSockaddrPtrTy, Socklen_tTy},
1853                     RetType{IntTy}, NoEvalCall)
1854                 .ArgConstraint(
1855                     ArgumentCondition(0, WithinRange, Range(0, IntMax)))
1856                 .ArgConstraint(NotNull(ArgNo(1)))
1857                 .ArgConstraint(
1858                     BufferSize(/*Buffer=*/ArgNo(1), /*BufSize=*/ArgNo(2)))
1859                 .ArgConstraint(
1860                     ArgumentCondition(2, WithinRange, Range(0, Socklen_tMax)))))
1861       // Do not add constraints on sockaddr.
1862       addToFunctionSummaryMap(
1863           "bind", Summary(ArgTypes{IntTy, Irrelevant, Socklen_tTy},
1864                           RetType{IntTy}, NoEvalCall)
1865                       .ArgConstraint(
1866                           ArgumentCondition(0, WithinRange, Range(0, IntMax)))
1867                       .ArgConstraint(ArgumentCondition(
1868                           2, WithinRange, Range(0, Socklen_tMax))));
1869 
1870     // int getpeername(int socket, struct sockaddr *restrict address,
1871     //                 socklen_t *restrict address_len);
1872     if (!addToFunctionSummaryMap(
1873             "getpeername", Summary(ArgTypes{IntTy, StructSockaddrPtrRestrictTy,
1874                                             Socklen_tPtrRestrictTy},
1875                                    RetType{IntTy}, NoEvalCall)
1876                                .ArgConstraint(ArgumentCondition(
1877                                    0, WithinRange, Range(0, IntMax)))
1878                                .ArgConstraint(NotNull(ArgNo(1)))
1879                                .ArgConstraint(NotNull(ArgNo(2)))))
1880       addToFunctionSummaryMap(
1881           "getpeername",
1882           Summary(ArgTypes{IntTy, Irrelevant, Socklen_tPtrRestrictTy},
1883                   RetType{IntTy}, NoEvalCall)
1884               .ArgConstraint(
1885                   ArgumentCondition(0, WithinRange, Range(0, IntMax))));
1886 
1887     // int getsockname(int socket, struct sockaddr *restrict address,
1888     //                 socklen_t *restrict address_len);
1889     if (!addToFunctionSummaryMap(
1890             "getsockname", Summary(ArgTypes{IntTy, StructSockaddrPtrRestrictTy,
1891                                             Socklen_tPtrRestrictTy},
1892                                    RetType{IntTy}, NoEvalCall)
1893                                .ArgConstraint(ArgumentCondition(
1894                                    0, WithinRange, Range(0, IntMax)))
1895                                .ArgConstraint(NotNull(ArgNo(1)))
1896                                .ArgConstraint(NotNull(ArgNo(2)))))
1897       addToFunctionSummaryMap(
1898           "getsockname",
1899           Summary(ArgTypes{IntTy, Irrelevant, Socklen_tPtrRestrictTy},
1900                   RetType{IntTy}, NoEvalCall)
1901               .ArgConstraint(
1902                   ArgumentCondition(0, WithinRange, Range(0, IntMax))));
1903 
1904     // int connect(int socket, const struct sockaddr *address, socklen_t
1905     //             address_len);
1906     if (!addToFunctionSummaryMap(
1907             "connect",
1908             Summary(ArgTypes{IntTy, ConstStructSockaddrPtrTy, Socklen_tTy},
1909                     RetType{IntTy}, NoEvalCall)
1910                 .ArgConstraint(
1911                     ArgumentCondition(0, WithinRange, Range(0, IntMax)))
1912                 .ArgConstraint(NotNull(ArgNo(1)))))
1913       addToFunctionSummaryMap(
1914           "connect", Summary(ArgTypes{IntTy, Irrelevant, Socklen_tTy},
1915                              RetType{IntTy}, NoEvalCall)
1916                          .ArgConstraint(ArgumentCondition(0, WithinRange,
1917                                                           Range(0, IntMax))));
1918 
1919     auto Recvfrom =
1920         Summary(NoEvalCall)
1921             .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
1922             .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
1923                                       /*BufSize=*/ArgNo(2)));
1924     if (!addToFunctionSummaryMap(
1925             "recvfrom",
1926             // ssize_t recvfrom(int socket, void *restrict buffer,
1927             //                  size_t length,
1928             //                  int flags, struct sockaddr *restrict address,
1929             //                  socklen_t *restrict address_len);
1930             Signature(ArgTypes{IntTy, VoidPtrRestrictTy, SizeTy, IntTy,
1931                                StructSockaddrPtrRestrictTy,
1932                                Socklen_tPtrRestrictTy},
1933                       RetType{Ssize_tTy}),
1934             Recvfrom))
1935       addToFunctionSummaryMap(
1936           "recvfrom",
1937           Signature(ArgTypes{IntTy, VoidPtrRestrictTy, SizeTy, IntTy,
1938                              Irrelevant, Socklen_tPtrRestrictTy},
1939                     RetType{Ssize_tTy}),
1940           Recvfrom);
1941 
1942     auto Sendto =
1943         Summary(NoEvalCall)
1944             .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
1945             .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
1946                                       /*BufSize=*/ArgNo(2)));
1947     if (!addToFunctionSummaryMap(
1948             "sendto",
1949             // ssize_t sendto(int socket, const void *message, size_t length,
1950             //                int flags, const struct sockaddr *dest_addr,
1951             //                socklen_t dest_len);
1952             Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTy, IntTy,
1953                                ConstStructSockaddrPtrTy, Socklen_tTy},
1954                       RetType{Ssize_tTy}),
1955             Sendto))
1956       addToFunctionSummaryMap(
1957           "sendto",
1958           Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTy, IntTy, Irrelevant,
1959                              Socklen_tTy},
1960                     RetType{Ssize_tTy}),
1961           Sendto);
1962 
1963     // int listen(int sockfd, int backlog);
1964     addToFunctionSummaryMap(
1965         "listen", Summary(ArgTypes{IntTy, IntTy}, RetType{IntTy}, NoEvalCall)
1966                       .ArgConstraint(
1967                           ArgumentCondition(0, WithinRange, Range(0, IntMax))));
1968 
1969     // ssize_t recv(int sockfd, void *buf, size_t len, int flags);
1970     addToFunctionSummaryMap(
1971         "recv",
1972         Summary(ArgTypes{IntTy, VoidPtrTy, SizeTy, IntTy}, RetType{Ssize_tTy},
1973                 NoEvalCall)
1974             .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
1975             .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
1976                                       /*BufSize=*/ArgNo(2))));
1977 
1978     Optional<QualType> StructMsghdrTy = lookupTy("msghdr");
1979     Optional<QualType> StructMsghdrPtrTy = getPointerTy(StructMsghdrTy);
1980     Optional<QualType> ConstStructMsghdrPtrTy =
1981         getPointerTy(getConstTy(StructMsghdrTy));
1982 
1983     // ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);
1984     addToFunctionSummaryMap(
1985         "recvmsg", Summary(ArgTypes{IntTy, StructMsghdrPtrTy, IntTy},
1986                            RetType{Ssize_tTy}, NoEvalCall)
1987                        .ArgConstraint(ArgumentCondition(0, WithinRange,
1988                                                         Range(0, IntMax))));
1989 
1990     // ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
1991     addToFunctionSummaryMap(
1992         "sendmsg", Summary(ArgTypes{IntTy, ConstStructMsghdrPtrTy, IntTy},
1993                            RetType{Ssize_tTy}, NoEvalCall)
1994                        .ArgConstraint(ArgumentCondition(0, WithinRange,
1995                                                         Range(0, IntMax))));
1996 
1997     // int setsockopt(int socket, int level, int option_name,
1998     //                const void *option_value, socklen_t option_len);
1999     addToFunctionSummaryMap(
2000         "setsockopt",
2001         Summary(ArgTypes{IntTy, IntTy, IntTy, ConstVoidPtrTy, Socklen_tTy},
2002                 RetType{IntTy}, NoEvalCall)
2003             .ArgConstraint(NotNull(ArgNo(3)))
2004             .ArgConstraint(
2005                 BufferSize(/*Buffer=*/ArgNo(3), /*BufSize=*/ArgNo(4)))
2006             .ArgConstraint(
2007                 ArgumentCondition(4, WithinRange, Range(0, Socklen_tMax))));
2008 
2009     // int getsockopt(int socket, int level, int option_name,
2010     //                void *restrict option_value,
2011     //                socklen_t *restrict option_len);
2012     addToFunctionSummaryMap(
2013         "getsockopt", Summary(ArgTypes{IntTy, IntTy, IntTy, VoidPtrRestrictTy,
2014                                        Socklen_tPtrRestrictTy},
2015                               RetType{IntTy}, NoEvalCall)
2016                           .ArgConstraint(NotNull(ArgNo(3)))
2017                           .ArgConstraint(NotNull(ArgNo(4))));
2018 
2019     // ssize_t send(int sockfd, const void *buf, size_t len, int flags);
2020     addToFunctionSummaryMap(
2021         "send",
2022         Summary(ArgTypes{IntTy, ConstVoidPtrTy, SizeTy, IntTy},
2023                 RetType{Ssize_tTy}, NoEvalCall)
2024             .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
2025             .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
2026                                       /*BufSize=*/ArgNo(2))));
2027 
2028     // int socketpair(int domain, int type, int protocol, int sv[2]);
2029     addToFunctionSummaryMap("socketpair",
2030                             Summary(ArgTypes{IntTy, IntTy, IntTy, IntPtrTy},
2031                                     RetType{IntTy}, NoEvalCall)
2032                                 .ArgConstraint(NotNull(ArgNo(3))));
2033 
2034     // int getnameinfo(const struct sockaddr *restrict sa, socklen_t salen,
2035     //                 char *restrict node, socklen_t nodelen,
2036     //                 char *restrict service,
2037     //                 socklen_t servicelen, int flags);
2038     //
2039     // This is defined in netdb.h. And contrary to 'socket.h', the sockaddr
2040     // parameter is never handled as a transparent union in netdb.h
2041     addToFunctionSummaryMap(
2042         "getnameinfo",
2043         Summary(ArgTypes{ConstStructSockaddrPtrRestrictTy, Socklen_tTy,
2044                          CharPtrRestrictTy, Socklen_tTy, CharPtrRestrictTy,
2045                          Socklen_tTy, IntTy},
2046                 RetType{IntTy}, NoEvalCall)
2047             .ArgConstraint(
2048                 BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1)))
2049             .ArgConstraint(
2050                 ArgumentCondition(1, WithinRange, Range(0, Socklen_tMax)))
2051             .ArgConstraint(
2052                 BufferSize(/*Buffer=*/ArgNo(2), /*BufSize=*/ArgNo(3)))
2053             .ArgConstraint(
2054                 ArgumentCondition(3, WithinRange, Range(0, Socklen_tMax)))
2055             .ArgConstraint(
2056                 BufferSize(/*Buffer=*/ArgNo(4), /*BufSize=*/ArgNo(5)))
2057             .ArgConstraint(
2058                 ArgumentCondition(5, WithinRange, Range(0, Socklen_tMax))));
2059 
2060     Optional<QualType> StructUtimbufTy = lookupTy("utimbuf");
2061     Optional<QualType> StructUtimbufPtrTy = getPointerTy(StructUtimbufTy);
2062 
2063     // int utime(const char *filename, struct utimbuf *buf);
2064     addToFunctionSummaryMap(
2065         "utime", Summary(ArgTypes{ConstCharPtrTy, StructUtimbufPtrTy},
2066                          RetType{IntTy}, NoEvalCall)
2067                      .ArgConstraint(NotNull(ArgNo(0))));
2068 
2069     Optional<QualType> StructTimespecTy = lookupTy("timespec");
2070     Optional<QualType> StructTimespecPtrTy = getPointerTy(StructTimespecTy);
2071     Optional<QualType> ConstStructTimespecPtrTy =
2072         getPointerTy(getConstTy(StructTimespecTy));
2073 
2074     // int futimens(int fd, const struct timespec times[2]);
2075     addToFunctionSummaryMap(
2076         "futimens", Summary(ArgTypes{IntTy, ConstStructTimespecPtrTy},
2077                             RetType{IntTy}, NoEvalCall)
2078                         .ArgConstraint(ArgumentCondition(0, WithinRange,
2079                                                          Range(0, IntMax))));
2080 
2081     // int utimensat(int dirfd, const char *pathname,
2082     //               const struct timespec times[2], int flags);
2083     addToFunctionSummaryMap("utimensat",
2084                             Summary(ArgTypes{IntTy, ConstCharPtrTy,
2085                                              ConstStructTimespecPtrTy, IntTy},
2086                                     RetType{IntTy}, NoEvalCall)
2087                                 .ArgConstraint(NotNull(ArgNo(1))));
2088 
2089     Optional<QualType> StructTimevalTy = lookupTy("timeval");
2090     Optional<QualType> ConstStructTimevalPtrTy =
2091         getPointerTy(getConstTy(StructTimevalTy));
2092 
2093     // int utimes(const char *filename, const struct timeval times[2]);
2094     addToFunctionSummaryMap(
2095         "utimes", Summary(ArgTypes{ConstCharPtrTy, ConstStructTimevalPtrTy},
2096                           RetType{IntTy}, NoEvalCall)
2097                       .ArgConstraint(NotNull(ArgNo(0))));
2098 
2099     // int nanosleep(const struct timespec *rqtp, struct timespec *rmtp);
2100     addToFunctionSummaryMap(
2101         "nanosleep",
2102         Summary(ArgTypes{ConstStructTimespecPtrTy, StructTimespecPtrTy},
2103                 RetType{IntTy}, NoEvalCall)
2104             .ArgConstraint(NotNull(ArgNo(0))));
2105 
2106     Optional<QualType> Time_tTy = lookupTy("time_t");
2107     Optional<QualType> ConstTime_tPtrTy = getPointerTy(getConstTy(Time_tTy));
2108     Optional<QualType> ConstTime_tPtrRestrictTy =
2109         getRestrictTy(ConstTime_tPtrTy);
2110 
2111     Optional<QualType> StructTmTy = lookupTy("tm");
2112     Optional<QualType> StructTmPtrTy = getPointerTy(StructTmTy);
2113     Optional<QualType> StructTmPtrRestrictTy = getRestrictTy(StructTmPtrTy);
2114     Optional<QualType> ConstStructTmPtrTy =
2115         getPointerTy(getConstTy(StructTmTy));
2116     Optional<QualType> ConstStructTmPtrRestrictTy =
2117         getRestrictTy(ConstStructTmPtrTy);
2118 
2119     // struct tm * localtime(const time_t *tp);
2120     addToFunctionSummaryMap(
2121         "localtime",
2122         Summary(ArgTypes{ConstTime_tPtrTy}, RetType{StructTmPtrTy}, NoEvalCall)
2123             .ArgConstraint(NotNull(ArgNo(0))));
2124 
2125     // struct tm *localtime_r(const time_t *restrict timer,
2126     //                        struct tm *restrict result);
2127     addToFunctionSummaryMap(
2128         "localtime_r",
2129         Summary(ArgTypes{ConstTime_tPtrRestrictTy, StructTmPtrRestrictTy},
2130                 RetType{StructTmPtrTy}, NoEvalCall)
2131             .ArgConstraint(NotNull(ArgNo(0)))
2132             .ArgConstraint(NotNull(ArgNo(1))));
2133 
2134     // char *asctime_r(const struct tm *restrict tm, char *restrict buf);
2135     addToFunctionSummaryMap(
2136         "asctime_r",
2137         Summary(ArgTypes{ConstStructTmPtrRestrictTy, CharPtrRestrictTy},
2138                 RetType{CharPtrTy}, NoEvalCall)
2139             .ArgConstraint(NotNull(ArgNo(0)))
2140             .ArgConstraint(NotNull(ArgNo(1)))
2141             .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
2142                                       /*MinBufSize=*/BVF.getValue(26, IntTy))));
2143 
2144     // char *ctime_r(const time_t *timep, char *buf);
2145     addToFunctionSummaryMap("ctime_r",
2146                             Summary(ArgTypes{ConstTime_tPtrTy, CharPtrTy},
2147                                     RetType{CharPtrTy}, NoEvalCall)
2148                                 .ArgConstraint(NotNull(ArgNo(0)))
2149                                 .ArgConstraint(NotNull(ArgNo(1)))
2150                                 .ArgConstraint(BufferSize(
2151                                     /*Buffer=*/ArgNo(1),
2152                                     /*MinBufSize=*/BVF.getValue(26, IntTy))));
2153 
2154     // struct tm *gmtime_r(const time_t *restrict timer,
2155     //                     struct tm *restrict result);
2156     addToFunctionSummaryMap(
2157         "gmtime_r",
2158         Summary(ArgTypes{ConstTime_tPtrRestrictTy, StructTmPtrRestrictTy},
2159                 RetType{StructTmPtrTy}, NoEvalCall)
2160             .ArgConstraint(NotNull(ArgNo(0)))
2161             .ArgConstraint(NotNull(ArgNo(1))));
2162 
2163     // struct tm * gmtime(const time_t *tp);
2164     addToFunctionSummaryMap(
2165         "gmtime",
2166         Summary(ArgTypes{ConstTime_tPtrTy}, RetType{StructTmPtrTy}, NoEvalCall)
2167             .ArgConstraint(NotNull(ArgNo(0))));
2168 
2169     Optional<QualType> Clockid_tTy = lookupTy("clockid_t");
2170 
2171     // int clock_gettime(clockid_t clock_id, struct timespec *tp);
2172     addToFunctionSummaryMap("clock_gettime",
2173                             Summary(ArgTypes{Clockid_tTy, StructTimespecPtrTy},
2174                                     RetType{IntTy}, NoEvalCall)
2175                                 .ArgConstraint(NotNull(ArgNo(1))));
2176 
2177     Optional<QualType> StructItimervalTy = lookupTy("itimerval");
2178     Optional<QualType> StructItimervalPtrTy = getPointerTy(StructItimervalTy);
2179 
2180     // int getitimer(int which, struct itimerval *curr_value);
2181     addToFunctionSummaryMap("getitimer",
2182                             Summary(ArgTypes{IntTy, StructItimervalPtrTy},
2183                                     RetType{IntTy}, NoEvalCall)
2184                                 .ArgConstraint(NotNull(ArgNo(1))));
2185   }
2186 
2187   // Functions for testing.
2188   if (ChecksEnabled[CK_StdCLibraryFunctionsTesterChecker]) {
2189     addToFunctionSummaryMap(
2190         "__two_constrained_args",
2191         Summary(ArgTypes{IntTy, IntTy}, RetType{IntTy}, EvalCallAsPure)
2192             .ArgConstraint(ArgumentCondition(0U, WithinRange, SingleValue(1)))
2193             .ArgConstraint(ArgumentCondition(1U, WithinRange, SingleValue(1))));
2194     addToFunctionSummaryMap(
2195         "__arg_constrained_twice",
2196         Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
2197             .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(1)))
2198             .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(2))));
2199     addToFunctionSummaryMap(
2200         "__defaultparam",
2201         Summary(ArgTypes{Irrelevant, IntTy}, RetType{IntTy}, EvalCallAsPure)
2202             .ArgConstraint(NotNull(ArgNo(0))));
2203     addToFunctionSummaryMap("__variadic",
2204                             Summary(ArgTypes{VoidPtrTy, ConstCharPtrTy},
2205                                     RetType{IntTy}, EvalCallAsPure)
2206                                 .ArgConstraint(NotNull(ArgNo(0)))
2207                                 .ArgConstraint(NotNull(ArgNo(1))));
2208     addToFunctionSummaryMap(
2209         "__buf_size_arg_constraint",
2210         Summary(ArgTypes{ConstVoidPtrTy, SizeTy}, RetType{IntTy},
2211                 EvalCallAsPure)
2212             .ArgConstraint(
2213                 BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1))));
2214     addToFunctionSummaryMap(
2215         "__buf_size_arg_constraint_mul",
2216         Summary(ArgTypes{ConstVoidPtrTy, SizeTy, SizeTy}, RetType{IntTy},
2217                 EvalCallAsPure)
2218             .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1),
2219                                       /*BufSizeMultiplier=*/ArgNo(2))));
2220     addToFunctionSummaryMap(
2221         "__buf_size_arg_constraint_concrete",
2222         Summary(ArgTypes{ConstVoidPtrTy}, RetType{IntTy}, EvalCallAsPure)
2223             .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(0),
2224                                       /*BufSize=*/BVF.getValue(10, IntTy))));
2225     addToFunctionSummaryMap(
2226         {"__test_restrict_param_0", "__test_restrict_param_1",
2227          "__test_restrict_param_2"},
2228         Signature(ArgTypes{VoidPtrRestrictTy}, RetType{VoidTy}),
2229         Summary(EvalCallAsPure));
2230   }
2231 }
2232 
2233 void ento::registerStdCLibraryFunctionsChecker(CheckerManager &mgr) {
2234   auto *Checker = mgr.registerChecker<StdLibraryFunctionsChecker>();
2235   Checker->DisplayLoadedSummaries =
2236       mgr.getAnalyzerOptions().getCheckerBooleanOption(
2237           Checker, "DisplayLoadedSummaries");
2238   Checker->ModelPOSIX =
2239       mgr.getAnalyzerOptions().getCheckerBooleanOption(Checker, "ModelPOSIX");
2240 }
2241 
2242 bool ento::shouldRegisterStdCLibraryFunctionsChecker(
2243     const CheckerManager &mgr) {
2244   return true;
2245 }
2246 
2247 #define REGISTER_CHECKER(name)                                                 \
2248   void ento::register##name(CheckerManager &mgr) {                             \
2249     StdLibraryFunctionsChecker *checker =                                      \
2250         mgr.getChecker<StdLibraryFunctionsChecker>();                          \
2251     checker->ChecksEnabled[StdLibraryFunctionsChecker::CK_##name] = true;      \
2252     checker->CheckNames[StdLibraryFunctionsChecker::CK_##name] =               \
2253         mgr.getCurrentCheckerName();                                           \
2254   }                                                                            \
2255                                                                                \
2256   bool ento::shouldRegister##name(const CheckerManager &mgr) { return true; }
2257 
2258 REGISTER_CHECKER(StdCLibraryFunctionArgsChecker)
2259 REGISTER_CHECKER(StdCLibraryFunctionsTesterChecker)
2260