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