Coverage Report

Created: 2023-09-30 09:22

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