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