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