1bab175ecSDimitry Andric //=== StdLibraryFunctionsChecker.cpp - Model standard functions -*- C++ -*-===//
2bab175ecSDimitry Andric //
322989816SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
422989816SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
522989816SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6bab175ecSDimitry Andric //
7bab175ecSDimitry Andric //===----------------------------------------------------------------------===//
8bab175ecSDimitry Andric //
9bab175ecSDimitry Andric // This checker improves modeling of a few simple library functions.
10bab175ecSDimitry Andric //
11cfca06d7SDimitry Andric // This checker provides a specification format - `Summary' - and
12bab175ecSDimitry Andric // contains descriptions of some library functions in this format. Each
13bab175ecSDimitry Andric // specification contains a list of branches for splitting the program state
14bab175ecSDimitry Andric // upon call, and range constraints on argument and return-value symbols that
15bab175ecSDimitry Andric // are satisfied on each branch. This spec can be expanded to include more
16bab175ecSDimitry Andric // items, like external effects of the function.
17bab175ecSDimitry Andric //
18bab175ecSDimitry Andric // The main difference between this approach and the body farms technique is
19bab175ecSDimitry Andric // in more explicit control over how many branches are produced. For example,
20bab175ecSDimitry Andric // consider standard C function `ispunct(int x)', which returns a non-zero value
21bab175ecSDimitry Andric // iff `x' is a punctuation character, that is, when `x' is in range
22bab175ecSDimitry Andric // ['!', '/'] [':', '@'] U ['[', '\`'] U ['{', '~'].
23cfca06d7SDimitry Andric // `Summary' provides only two branches for this function. However,
24bab175ecSDimitry Andric // any attempt to describe this range with if-statements in the body farm
25bab175ecSDimitry Andric // would result in many more branches. Because each branch needs to be analyzed
26bab175ecSDimitry Andric // independently, this significantly reduces performance. Additionally,
27bab175ecSDimitry Andric // once we consider a branch on which `x' is in range, say, ['!', '/'],
28bab175ecSDimitry Andric // we assume that such branch is an important separate path through the program,
29bab175ecSDimitry Andric // which may lead to false positives because considering this particular path
30bab175ecSDimitry Andric // was not consciously intended, and therefore it might have been unreachable.
31bab175ecSDimitry Andric //
32cfca06d7SDimitry Andric // This checker uses eval::Call for modeling pure functions (functions without
33ac9a064cSDimitry Andric // side effects), for which their `Summary' is a precise model. This avoids
34cfca06d7SDimitry Andric // unnecessary invalidation passes. Conflicts with other checkers are unlikely
35cfca06d7SDimitry Andric // because if the function has no other effects, other checkers would probably
36cfca06d7SDimitry Andric // never want to improve upon the modeling done by this checker.
37bab175ecSDimitry Andric //
38cfca06d7SDimitry Andric // Non-pure functions, for which only partial improvement over the default
39bab175ecSDimitry Andric // behavior is expected, are modeled via check::PostCall, non-intrusively.
40bab175ecSDimitry Andric //
41bab175ecSDimitry Andric //===----------------------------------------------------------------------===//
42bab175ecSDimitry Andric
43145449b1SDimitry Andric #include "ErrnoModeling.h"
44676fbe81SDimitry Andric #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
45cfca06d7SDimitry Andric #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
46bab175ecSDimitry Andric #include "clang/StaticAnalyzer/Core/Checker.h"
47bab175ecSDimitry Andric #include "clang/StaticAnalyzer/Core/CheckerManager.h"
48bab175ecSDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
49bab175ecSDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
50cfca06d7SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h"
51344a3780SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicExtent.h"
527fa27ce4SDimitry Andric #include "llvm/ADT/STLExtras.h"
53344a3780SDimitry Andric #include "llvm/ADT/SmallString.h"
54344a3780SDimitry Andric #include "llvm/ADT/StringExtras.h"
557fa27ce4SDimitry Andric #include "llvm/Support/FormatVariadic.h"
56344a3780SDimitry Andric
57e3b55780SDimitry Andric #include <optional>
58344a3780SDimitry Andric #include <string>
59bab175ecSDimitry Andric
60bab175ecSDimitry Andric using namespace clang;
61bab175ecSDimitry Andric using namespace clang::ento;
62bab175ecSDimitry Andric
63bab175ecSDimitry Andric namespace {
64cfca06d7SDimitry Andric class StdLibraryFunctionsChecker
65cfca06d7SDimitry Andric : public Checker<check::PreCall, check::PostCall, eval::Call> {
66cfca06d7SDimitry Andric
67cfca06d7SDimitry Andric class Summary;
68bab175ecSDimitry Andric
69bab175ecSDimitry Andric /// Specify how much the analyzer engine should entrust modeling this function
707fa27ce4SDimitry Andric /// to us.
717fa27ce4SDimitry Andric enum InvalidationKind {
727fa27ce4SDimitry Andric /// No \c eval::Call for the function, it can be modeled elsewhere.
737fa27ce4SDimitry Andric /// This checker checks only pre and post conditions.
747fa27ce4SDimitry Andric NoEvalCall,
757fa27ce4SDimitry Andric /// The function is modeled completely in this checker.
767fa27ce4SDimitry Andric EvalCallAsPure
777fa27ce4SDimitry Andric };
78bab175ecSDimitry Andric
797fa27ce4SDimitry Andric /// Given a range, should the argument stay inside or outside this range?
807fa27ce4SDimitry Andric enum RangeKind { OutOfRange, WithinRange };
817fa27ce4SDimitry Andric
negateKind(RangeKind K)827fa27ce4SDimitry Andric static RangeKind negateKind(RangeKind K) {
837fa27ce4SDimitry Andric switch (K) {
847fa27ce4SDimitry Andric case OutOfRange:
857fa27ce4SDimitry Andric return WithinRange;
867fa27ce4SDimitry Andric case WithinRange:
877fa27ce4SDimitry Andric return OutOfRange;
887fa27ce4SDimitry Andric }
897fa27ce4SDimitry Andric llvm_unreachable("Unknown range kind");
907fa27ce4SDimitry Andric }
917fa27ce4SDimitry Andric
927fa27ce4SDimitry Andric /// The universal integral type to use in value range descriptions.
937fa27ce4SDimitry Andric /// Unsigned to make sure overflows are well-defined.
94cfca06d7SDimitry Andric typedef uint64_t RangeInt;
95bab175ecSDimitry Andric
967fa27ce4SDimitry Andric /// Describes a single range constraint. Eg. {{0, 1}, {3, 4}} is
977fa27ce4SDimitry Andric /// a non-negative integer, which less than 5 and not equal to 2.
98cfca06d7SDimitry Andric typedef std::vector<std::pair<RangeInt, RangeInt>> IntRangeVector;
99bab175ecSDimitry Andric
100bab175ecSDimitry Andric /// A reference to an argument or return value by its number.
101bab175ecSDimitry Andric /// ArgNo in CallExpr and CallEvent is defined as Unsigned, but
102bab175ecSDimitry Andric /// obviously uint32_t should be enough for all practical purposes.
103cfca06d7SDimitry Andric typedef uint32_t ArgNo;
1047fa27ce4SDimitry Andric /// Special argument number for specifying the return value.
105cfca06d7SDimitry Andric static const ArgNo Ret;
106bab175ecSDimitry Andric
1077fa27ce4SDimitry Andric /// Get a string representation of an argument index.
108344a3780SDimitry Andric /// E.g.: (1) -> '1st arg', (2) - > '2nd arg'
1097fa27ce4SDimitry Andric static void printArgDesc(ArgNo, llvm::raw_ostream &Out);
1107fa27ce4SDimitry Andric /// Print value X of the argument in form " (which is X)",
1117fa27ce4SDimitry Andric /// if the value is a fixed known value, otherwise print nothing.
1127fa27ce4SDimitry Andric /// This is used as simple explanation of values if possible.
1137fa27ce4SDimitry Andric static void printArgValueInfo(ArgNo ArgN, ProgramStateRef State,
1147fa27ce4SDimitry Andric const CallEvent &Call, llvm::raw_ostream &Out);
1157fa27ce4SDimitry Andric /// Append textual description of a numeric range [RMin,RMax] to
1167fa27ce4SDimitry Andric /// \p Out.
1177fa27ce4SDimitry Andric static void appendInsideRangeDesc(llvm::APSInt RMin, llvm::APSInt RMax,
1187fa27ce4SDimitry Andric QualType ArgT, BasicValueFactory &BVF,
1197fa27ce4SDimitry Andric llvm::raw_ostream &Out);
1207fa27ce4SDimitry Andric /// Append textual description of a numeric range out of [RMin,RMax] to
1217fa27ce4SDimitry Andric /// \p Out.
1227fa27ce4SDimitry Andric static void appendOutOfRangeDesc(llvm::APSInt RMin, llvm::APSInt RMax,
1237fa27ce4SDimitry Andric QualType ArgT, BasicValueFactory &BVF,
1247fa27ce4SDimitry Andric llvm::raw_ostream &Out);
125344a3780SDimitry Andric
126cfca06d7SDimitry Andric class ValueConstraint;
127cfca06d7SDimitry Andric
1287fa27ce4SDimitry Andric /// Pointer to the ValueConstraint. We need a copyable, polymorphic and
1297fa27ce4SDimitry Andric /// default initializable type (vector needs that). A raw pointer was good,
1307fa27ce4SDimitry Andric /// however, we cannot default initialize that. unique_ptr makes the Summary
1317fa27ce4SDimitry Andric /// class non-copyable, therefore not an option. Releasing the copyability
1327fa27ce4SDimitry Andric /// requirement would render the initialization of the Summary map infeasible.
1337fa27ce4SDimitry Andric /// Mind that a pointer to a new value constraint is created when the negate
1347fa27ce4SDimitry Andric /// function is used.
135cfca06d7SDimitry Andric using ValueConstraintPtr = std::shared_ptr<ValueConstraint>;
136cfca06d7SDimitry Andric
137cfca06d7SDimitry Andric /// Polymorphic base class that represents a constraint on a given argument
138cfca06d7SDimitry Andric /// (or return value) of a function. Derived classes implement different kind
139cfca06d7SDimitry Andric /// of constraints, e.g range constraints or correlation between two
140cfca06d7SDimitry Andric /// arguments.
1417fa27ce4SDimitry Andric /// These are used as argument constraints (preconditions) of functions, in
1427fa27ce4SDimitry Andric /// which case a bug report may be emitted if the constraint is not satisfied.
1437fa27ce4SDimitry Andric /// Another use is as conditions for summary cases, to create different
1447fa27ce4SDimitry Andric /// classes of behavior for a function. In this case no description of the
1457fa27ce4SDimitry Andric /// constraint is needed because the summary cases have an own (not generated)
1467fa27ce4SDimitry Andric /// description string.
147cfca06d7SDimitry Andric class ValueConstraint {
148cfca06d7SDimitry Andric public:
ValueConstraint(ArgNo ArgN)149cfca06d7SDimitry Andric ValueConstraint(ArgNo ArgN) : ArgN(ArgN) {}
~ValueConstraint()150cfca06d7SDimitry Andric virtual ~ValueConstraint() {}
1517fa27ce4SDimitry Andric
152cfca06d7SDimitry Andric /// Apply the effects of the constraint on the given program state. If null
153cfca06d7SDimitry Andric /// is returned then the constraint is not feasible.
154cfca06d7SDimitry Andric virtual ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
155cfca06d7SDimitry Andric const Summary &Summary,
156cfca06d7SDimitry Andric CheckerContext &C) const = 0;
1577fa27ce4SDimitry Andric
1587fa27ce4SDimitry Andric /// Represents that in which context do we require a description of the
1597fa27ce4SDimitry Andric /// constraint.
1607fa27ce4SDimitry Andric enum DescriptionKind {
1617fa27ce4SDimitry Andric /// Describe a constraint that was violated.
1627fa27ce4SDimitry Andric /// Description should start with something like "should be".
1637fa27ce4SDimitry Andric Violation,
1647fa27ce4SDimitry Andric /// Describe a constraint that was assumed to be true.
1657fa27ce4SDimitry Andric /// This can be used when a precondition is satisfied, or when a summary
1667fa27ce4SDimitry Andric /// case is applied.
1677fa27ce4SDimitry Andric /// Description should start with something like "is".
1687fa27ce4SDimitry Andric Assumption
1697fa27ce4SDimitry Andric };
1707fa27ce4SDimitry Andric
1717fa27ce4SDimitry Andric /// Give a description that explains the constraint to the user. Used when
1727fa27ce4SDimitry Andric /// a bug is reported or when the constraint is applied and displayed as a
1737fa27ce4SDimitry Andric /// note. The description should not mention the argument (getArgNo).
1747fa27ce4SDimitry Andric /// See StdLibraryFunctionsChecker::reportBug about how this function is
1757fa27ce4SDimitry Andric /// used (this function is used not only there).
describe(DescriptionKind DK,const CallEvent & Call,ProgramStateRef State,const Summary & Summary,llvm::raw_ostream & Out) const1767fa27ce4SDimitry Andric virtual void describe(DescriptionKind DK, const CallEvent &Call,
1777fa27ce4SDimitry Andric ProgramStateRef State, const Summary &Summary,
1787fa27ce4SDimitry Andric llvm::raw_ostream &Out) const {
1797fa27ce4SDimitry Andric // There are some descendant classes that are not used as argument
1807fa27ce4SDimitry Andric // constraints, e.g. ComparisonConstraint. In that case we can safely
1817fa27ce4SDimitry Andric // ignore the implementation of this function.
1827fa27ce4SDimitry Andric llvm_unreachable(
1837fa27ce4SDimitry Andric "Description not implemented for summary case constraints");
1847fa27ce4SDimitry Andric }
1857fa27ce4SDimitry Andric
1867fa27ce4SDimitry Andric /// Give a description that explains the actual argument value (where the
1877fa27ce4SDimitry Andric /// current ValueConstraint applies to) to the user. This function should be
1887fa27ce4SDimitry Andric /// called only when the current constraint is satisfied by the argument.
1897fa27ce4SDimitry Andric /// It should produce a more precise description than the constraint itself.
1907fa27ce4SDimitry Andric /// The actual value of the argument and the program state can be used to
1917fa27ce4SDimitry Andric /// make the description more precise. In the most simple case, if the
1927fa27ce4SDimitry Andric /// argument has a fixed known value this value can be printed into \p Out,
1937fa27ce4SDimitry Andric /// this is done by default.
1947fa27ce4SDimitry Andric /// The function should return true if a description was printed to \p Out,
1957fa27ce4SDimitry Andric /// otherwise false.
1967fa27ce4SDimitry Andric /// See StdLibraryFunctionsChecker::reportBug about how this function is
1977fa27ce4SDimitry Andric /// used.
describeArgumentValue(const CallEvent & Call,ProgramStateRef State,const Summary & Summary,llvm::raw_ostream & Out) const1987fa27ce4SDimitry Andric virtual bool describeArgumentValue(const CallEvent &Call,
1997fa27ce4SDimitry Andric ProgramStateRef State,
2007fa27ce4SDimitry Andric const Summary &Summary,
2017fa27ce4SDimitry Andric llvm::raw_ostream &Out) const {
2027fa27ce4SDimitry Andric if (auto N = getArgSVal(Call, getArgNo()).getAs<NonLoc>()) {
2037fa27ce4SDimitry Andric if (const llvm::APSInt *Int = N->getAsInteger()) {
2047fa27ce4SDimitry Andric Out << *Int;
2057fa27ce4SDimitry Andric return true;
2067fa27ce4SDimitry Andric }
2077fa27ce4SDimitry Andric }
2087fa27ce4SDimitry Andric return false;
2097fa27ce4SDimitry Andric }
2107fa27ce4SDimitry Andric
2117fa27ce4SDimitry Andric /// Return those arguments that should be tracked when we report a bug about
2127fa27ce4SDimitry Andric /// argument constraint violation. By default it is the argument that is
2137fa27ce4SDimitry Andric /// constrained, however, in some special cases we need to track other
2147fa27ce4SDimitry Andric /// arguments as well. E.g. a buffer size might be encoded in another
2157fa27ce4SDimitry Andric /// argument.
2167fa27ce4SDimitry Andric /// The "return value" argument number can not occur as returned value.
getArgsToTrack() const2177fa27ce4SDimitry Andric virtual std::vector<ArgNo> getArgsToTrack() const { return {ArgN}; }
2187fa27ce4SDimitry Andric
2197fa27ce4SDimitry Andric /// Get a constraint that represents exactly the opposite of the current.
negate() const220cfca06d7SDimitry Andric virtual ValueConstraintPtr negate() const {
221cfca06d7SDimitry Andric llvm_unreachable("Not implemented");
222cfca06d7SDimitry Andric };
223cfca06d7SDimitry Andric
2247fa27ce4SDimitry Andric /// Check whether the constraint is malformed or not. It is malformed if the
2257fa27ce4SDimitry Andric /// specified argument has a mismatch with the given FunctionDecl (e.g. the
2267fa27ce4SDimitry Andric /// arg number is out-of-range of the function's argument list).
2277fa27ce4SDimitry Andric /// This condition can indicate if a probably wrong or unexpected function
2287fa27ce4SDimitry Andric /// was found where the constraint is to be applied.
checkValidity(const FunctionDecl * FD) const229cfca06d7SDimitry Andric bool checkValidity(const FunctionDecl *FD) const {
230cfca06d7SDimitry Andric const bool ValidArg = ArgN == Ret || ArgN < FD->getNumParams();
231cfca06d7SDimitry Andric assert(ValidArg && "Arg out of range!");
232cfca06d7SDimitry Andric if (!ValidArg)
233cfca06d7SDimitry Andric return false;
234cfca06d7SDimitry Andric // Subclasses may further refine the validation.
235cfca06d7SDimitry Andric return checkSpecificValidity(FD);
236cfca06d7SDimitry Andric }
2377fa27ce4SDimitry Andric
2387fa27ce4SDimitry Andric /// Return the argument number (may be placeholder for "return value").
getArgNo() const239cfca06d7SDimitry Andric ArgNo getArgNo() const { return ArgN; }
240cfca06d7SDimitry Andric
241cfca06d7SDimitry Andric protected:
2427fa27ce4SDimitry Andric /// Argument to which to apply the constraint. It can be a real argument of
2437fa27ce4SDimitry Andric /// the function to check, or a special value to indicate the return value
2447fa27ce4SDimitry Andric /// of the function.
2457fa27ce4SDimitry Andric /// Every constraint is assigned to one main argument, even if other
2467fa27ce4SDimitry Andric /// arguments are involved.
2477fa27ce4SDimitry Andric ArgNo ArgN;
248cfca06d7SDimitry Andric
2497fa27ce4SDimitry Andric /// Do constraint-specific validation check.
checkSpecificValidity(const FunctionDecl * FD) const250cfca06d7SDimitry Andric virtual bool checkSpecificValidity(const FunctionDecl *FD) const {
251cfca06d7SDimitry Andric return true;
252cfca06d7SDimitry Andric }
253cfca06d7SDimitry Andric };
254cfca06d7SDimitry Andric
2557fa27ce4SDimitry Andric /// Check if a single argument falls into a specific "range".
2567fa27ce4SDimitry Andric /// A range is formed as a set of intervals.
2577fa27ce4SDimitry Andric /// E.g. \code {['A', 'Z'], ['a', 'z'], ['_', '_']} \endcode
2587fa27ce4SDimitry Andric /// The intervals are closed intervals that contain one or more values.
2597fa27ce4SDimitry Andric ///
2607fa27ce4SDimitry Andric /// The default constructed RangeConstraint has an empty range, applying
2617fa27ce4SDimitry Andric /// such constraint does not involve any assumptions, thus the State remains
2627fa27ce4SDimitry Andric /// unchanged. This is meaningful, if the range is dependent on a looked up
2637fa27ce4SDimitry Andric /// type (e.g. [0, Socklen_tMax]). If the type is not found, then the range
2647fa27ce4SDimitry Andric /// is default initialized to be empty.
265cfca06d7SDimitry Andric class RangeConstraint : public ValueConstraint {
2667fa27ce4SDimitry Andric /// The constraint can be specified by allowing or disallowing the range.
2677fa27ce4SDimitry Andric /// WithinRange indicates allowing the range, OutOfRange indicates
2687fa27ce4SDimitry Andric /// disallowing it (allowing the complementary range).
269b60736ecSDimitry Andric RangeKind Kind;
2707fa27ce4SDimitry Andric
2717fa27ce4SDimitry Andric /// A set of intervals.
272b60736ecSDimitry Andric IntRangeVector Ranges;
273bab175ecSDimitry Andric
2747fa27ce4SDimitry Andric /// A textual description of this constraint for the specific case where the
2757fa27ce4SDimitry Andric /// constraint is used. If empty a generated description will be used that
2767fa27ce4SDimitry Andric /// is built from the range of the constraint.
2777fa27ce4SDimitry Andric StringRef Description;
278bab175ecSDimitry Andric
2797fa27ce4SDimitry Andric public:
RangeConstraint(ArgNo ArgN,RangeKind Kind,const IntRangeVector & Ranges,StringRef Desc="")2807fa27ce4SDimitry Andric RangeConstraint(ArgNo ArgN, RangeKind Kind, const IntRangeVector &Ranges,
2817fa27ce4SDimitry Andric StringRef Desc = "")
2827fa27ce4SDimitry Andric : ValueConstraint(ArgN), Kind(Kind), Ranges(Ranges), Description(Desc) {
2837fa27ce4SDimitry Andric }
284344a3780SDimitry Andric
getRanges() const285b60736ecSDimitry Andric const IntRangeVector &getRanges() const { return Ranges; }
286bab175ecSDimitry Andric
287bab175ecSDimitry Andric ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
288cfca06d7SDimitry Andric const Summary &Summary,
2897fa27ce4SDimitry Andric CheckerContext &C) const override;
2907fa27ce4SDimitry Andric
2917fa27ce4SDimitry Andric void describe(DescriptionKind DK, const CallEvent &Call,
2927fa27ce4SDimitry Andric ProgramStateRef State, const Summary &Summary,
2937fa27ce4SDimitry Andric llvm::raw_ostream &Out) const override;
2947fa27ce4SDimitry Andric
2957fa27ce4SDimitry Andric bool describeArgumentValue(const CallEvent &Call, ProgramStateRef State,
2967fa27ce4SDimitry Andric const Summary &Summary,
2977fa27ce4SDimitry Andric llvm::raw_ostream &Out) const override;
298cfca06d7SDimitry Andric
negate() const299cfca06d7SDimitry Andric ValueConstraintPtr negate() const override {
300cfca06d7SDimitry Andric RangeConstraint Tmp(*this);
3017fa27ce4SDimitry Andric Tmp.Kind = negateKind(Kind);
302cfca06d7SDimitry Andric return std::make_shared<RangeConstraint>(Tmp);
303cfca06d7SDimitry Andric }
304cfca06d7SDimitry Andric
3057fa27ce4SDimitry Andric protected:
checkSpecificValidity(const FunctionDecl * FD) const306cfca06d7SDimitry Andric bool checkSpecificValidity(const FunctionDecl *FD) const override {
307cfca06d7SDimitry Andric const bool ValidArg =
308cfca06d7SDimitry Andric getArgType(FD, ArgN)->isIntegralType(FD->getASTContext());
309cfca06d7SDimitry Andric assert(ValidArg &&
310cfca06d7SDimitry Andric "This constraint should be applied on an integral type");
311cfca06d7SDimitry Andric return ValidArg;
312bab175ecSDimitry Andric }
3137fa27ce4SDimitry Andric
3147fa27ce4SDimitry Andric private:
3157fa27ce4SDimitry Andric /// A callback function that is used when iterating over the range
3167fa27ce4SDimitry Andric /// intervals. It gets the begin and end (inclusive) of one interval.
3177fa27ce4SDimitry Andric /// This is used to make any kind of task possible that needs an iteration
3187fa27ce4SDimitry Andric /// over the intervals.
3197fa27ce4SDimitry Andric using RangeApplyFunction =
3207fa27ce4SDimitry Andric std::function<bool(const llvm::APSInt &Min, const llvm::APSInt &Max)>;
3217fa27ce4SDimitry Andric
3227fa27ce4SDimitry Andric /// Call a function on the intervals of the range.
3237fa27ce4SDimitry Andric /// The function is called with all intervals in the range.
3247fa27ce4SDimitry Andric void applyOnWithinRange(BasicValueFactory &BVF, QualType ArgT,
3257fa27ce4SDimitry Andric const RangeApplyFunction &F) const;
3267fa27ce4SDimitry Andric /// Call a function on all intervals in the complementary range.
3277fa27ce4SDimitry Andric /// The function is called with all intervals that fall out of the range.
3287fa27ce4SDimitry Andric /// E.g. consider an interval list [A, B] and [C, D]
3297fa27ce4SDimitry Andric /// \code
3307fa27ce4SDimitry Andric /// -------+--------+------------------+------------+----------->
3317fa27ce4SDimitry Andric /// A B C D
3327fa27ce4SDimitry Andric /// \endcode
3337fa27ce4SDimitry Andric /// We get the ranges [-inf, A - 1], [D + 1, +inf], [B + 1, C - 1].
3347fa27ce4SDimitry Andric /// The \p ArgT is used to determine the min and max of the type that is
3357fa27ce4SDimitry Andric /// used as "-inf" and "+inf".
3367fa27ce4SDimitry Andric void applyOnOutOfRange(BasicValueFactory &BVF, QualType ArgT,
3377fa27ce4SDimitry Andric const RangeApplyFunction &F) const;
3387fa27ce4SDimitry Andric /// Call a function on the intervals of the range or the complementary
3397fa27ce4SDimitry Andric /// range.
applyOnRange(RangeKind Kind,BasicValueFactory & BVF,QualType ArgT,const RangeApplyFunction & F) const3407fa27ce4SDimitry Andric void applyOnRange(RangeKind Kind, BasicValueFactory &BVF, QualType ArgT,
3417fa27ce4SDimitry Andric const RangeApplyFunction &F) const {
3427fa27ce4SDimitry Andric switch (Kind) {
3437fa27ce4SDimitry Andric case OutOfRange:
3447fa27ce4SDimitry Andric applyOnOutOfRange(BVF, ArgT, F);
3457fa27ce4SDimitry Andric break;
3467fa27ce4SDimitry Andric case WithinRange:
3477fa27ce4SDimitry Andric applyOnWithinRange(BVF, ArgT, F);
3487fa27ce4SDimitry Andric break;
3497fa27ce4SDimitry Andric };
3507fa27ce4SDimitry Andric }
351bab175ecSDimitry Andric };
352bab175ecSDimitry Andric
3537fa27ce4SDimitry Andric /// Check relation of an argument to another.
354cfca06d7SDimitry Andric class ComparisonConstraint : public ValueConstraint {
355cfca06d7SDimitry Andric BinaryOperator::Opcode Opcode;
356cfca06d7SDimitry Andric ArgNo OtherArgN;
357bab175ecSDimitry Andric
358bab175ecSDimitry Andric public:
ComparisonConstraint(ArgNo ArgN,BinaryOperator::Opcode Opcode,ArgNo OtherArgN)359cfca06d7SDimitry Andric ComparisonConstraint(ArgNo ArgN, BinaryOperator::Opcode Opcode,
360cfca06d7SDimitry Andric ArgNo OtherArgN)
361cfca06d7SDimitry Andric : ValueConstraint(ArgN), Opcode(Opcode), OtherArgN(OtherArgN) {}
getOtherArgNo() const362cfca06d7SDimitry Andric ArgNo getOtherArgNo() const { return OtherArgN; }
getOpcode() const363cfca06d7SDimitry Andric BinaryOperator::Opcode getOpcode() const { return Opcode; }
364cfca06d7SDimitry Andric ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
365cfca06d7SDimitry Andric const Summary &Summary,
366cfca06d7SDimitry Andric CheckerContext &C) const override;
367cfca06d7SDimitry Andric };
368cfca06d7SDimitry Andric
3697fa27ce4SDimitry Andric /// Check null or non-null-ness of an argument that is of pointer type.
370cfca06d7SDimitry Andric class NotNullConstraint : public ValueConstraint {
371cfca06d7SDimitry Andric using ValueConstraint::ValueConstraint;
372cfca06d7SDimitry Andric // This variable has a role when we negate the constraint.
373cfca06d7SDimitry Andric bool CannotBeNull = true;
374cfca06d7SDimitry Andric
375cfca06d7SDimitry Andric public:
NotNullConstraint(ArgNo ArgN,bool CannotBeNull=true)376e3b55780SDimitry Andric NotNullConstraint(ArgNo ArgN, bool CannotBeNull = true)
377e3b55780SDimitry Andric : ValueConstraint(ArgN), CannotBeNull(CannotBeNull) {}
3787fa27ce4SDimitry Andric
379cfca06d7SDimitry Andric ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
380cfca06d7SDimitry Andric const Summary &Summary,
3817fa27ce4SDimitry Andric CheckerContext &C) const override;
382cfca06d7SDimitry Andric
3837fa27ce4SDimitry Andric void describe(DescriptionKind DK, const CallEvent &Call,
3847fa27ce4SDimitry Andric ProgramStateRef State, const Summary &Summary,
3857fa27ce4SDimitry Andric llvm::raw_ostream &Out) const override;
386cfca06d7SDimitry Andric
3877fa27ce4SDimitry Andric bool describeArgumentValue(const CallEvent &Call, ProgramStateRef State,
3887fa27ce4SDimitry Andric const Summary &Summary,
3897fa27ce4SDimitry Andric llvm::raw_ostream &Out) const override;
390cfca06d7SDimitry Andric
negate() const391cfca06d7SDimitry Andric ValueConstraintPtr negate() const override {
392cfca06d7SDimitry Andric NotNullConstraint Tmp(*this);
393cfca06d7SDimitry Andric Tmp.CannotBeNull = !this->CannotBeNull;
394cfca06d7SDimitry Andric return std::make_shared<NotNullConstraint>(Tmp);
395cfca06d7SDimitry Andric }
396cfca06d7SDimitry Andric
3977fa27ce4SDimitry Andric protected:
checkSpecificValidity(const FunctionDecl * FD) const3987fa27ce4SDimitry Andric bool checkSpecificValidity(const FunctionDecl *FD) const override {
3997fa27ce4SDimitry Andric const bool ValidArg = getArgType(FD, ArgN)->isPointerType();
4007fa27ce4SDimitry Andric assert(ValidArg &&
4017fa27ce4SDimitry Andric "This constraint should be applied only on a pointer type");
4027fa27ce4SDimitry Andric return ValidArg;
4037fa27ce4SDimitry Andric }
4047fa27ce4SDimitry Andric };
4057fa27ce4SDimitry Andric
4067fa27ce4SDimitry Andric /// Check null or non-null-ness of an argument that is of pointer type.
4077fa27ce4SDimitry Andric /// The argument is meant to be a buffer that has a size constraint, and it
4087fa27ce4SDimitry Andric /// is allowed to have a NULL value if the size is 0. The size can depend on
4097fa27ce4SDimitry Andric /// 1 or 2 additional arguments, if one of these is 0 the buffer is allowed to
4107fa27ce4SDimitry Andric /// be NULL. This is useful for functions like `fread` which have this special
4117fa27ce4SDimitry Andric /// property.
4127fa27ce4SDimitry Andric class NotNullBufferConstraint : public ValueConstraint {
4137fa27ce4SDimitry Andric using ValueConstraint::ValueConstraint;
4147fa27ce4SDimitry Andric ArgNo SizeArg1N;
4157fa27ce4SDimitry Andric std::optional<ArgNo> SizeArg2N;
4167fa27ce4SDimitry Andric // This variable has a role when we negate the constraint.
4177fa27ce4SDimitry Andric bool CannotBeNull = true;
4187fa27ce4SDimitry Andric
4197fa27ce4SDimitry Andric public:
NotNullBufferConstraint(ArgNo ArgN,ArgNo SizeArg1N,std::optional<ArgNo> SizeArg2N,bool CannotBeNull=true)4207fa27ce4SDimitry Andric NotNullBufferConstraint(ArgNo ArgN, ArgNo SizeArg1N,
4217fa27ce4SDimitry Andric std::optional<ArgNo> SizeArg2N,
4227fa27ce4SDimitry Andric bool CannotBeNull = true)
4237fa27ce4SDimitry Andric : ValueConstraint(ArgN), SizeArg1N(SizeArg1N), SizeArg2N(SizeArg2N),
4247fa27ce4SDimitry Andric CannotBeNull(CannotBeNull) {}
4257fa27ce4SDimitry Andric
4267fa27ce4SDimitry Andric ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
4277fa27ce4SDimitry Andric const Summary &Summary,
4287fa27ce4SDimitry Andric CheckerContext &C) const override;
4297fa27ce4SDimitry Andric
4307fa27ce4SDimitry Andric void describe(DescriptionKind DK, const CallEvent &Call,
4317fa27ce4SDimitry Andric ProgramStateRef State, const Summary &Summary,
4327fa27ce4SDimitry Andric llvm::raw_ostream &Out) const override;
4337fa27ce4SDimitry Andric
4347fa27ce4SDimitry Andric bool describeArgumentValue(const CallEvent &Call, ProgramStateRef State,
4357fa27ce4SDimitry Andric const Summary &Summary,
4367fa27ce4SDimitry Andric llvm::raw_ostream &Out) const override;
4377fa27ce4SDimitry Andric
negate() const4387fa27ce4SDimitry Andric ValueConstraintPtr negate() const override {
4397fa27ce4SDimitry Andric NotNullBufferConstraint Tmp(*this);
4407fa27ce4SDimitry Andric Tmp.CannotBeNull = !this->CannotBeNull;
4417fa27ce4SDimitry Andric return std::make_shared<NotNullBufferConstraint>(Tmp);
4427fa27ce4SDimitry Andric }
4437fa27ce4SDimitry Andric
4447fa27ce4SDimitry Andric protected:
checkSpecificValidity(const FunctionDecl * FD) const445cfca06d7SDimitry Andric bool checkSpecificValidity(const FunctionDecl *FD) const override {
446cfca06d7SDimitry Andric const bool ValidArg = getArgType(FD, ArgN)->isPointerType();
447cfca06d7SDimitry Andric assert(ValidArg &&
448cfca06d7SDimitry Andric "This constraint should be applied only on a pointer type");
449cfca06d7SDimitry Andric return ValidArg;
450cfca06d7SDimitry Andric }
451cfca06d7SDimitry Andric };
452cfca06d7SDimitry Andric
453b60736ecSDimitry Andric // Represents a buffer argument with an additional size constraint. The
454b60736ecSDimitry Andric // constraint may be a concrete value, or a symbolic value in an argument.
455b60736ecSDimitry Andric // Example 1. Concrete value as the minimum buffer size.
456b60736ecSDimitry Andric // char *asctime_r(const struct tm *restrict tm, char *restrict buf);
457b60736ecSDimitry Andric // // `buf` size must be at least 26 bytes according the POSIX standard.
458b60736ecSDimitry Andric // Example 2. Argument as a buffer size.
459cfca06d7SDimitry Andric // ctime_s(char *buffer, rsize_t bufsz, const time_t *time);
460b60736ecSDimitry Andric // Example 3. The size is computed as a multiplication of other args.
461cfca06d7SDimitry Andric // size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
462cfca06d7SDimitry Andric // // Here, ptr is the buffer, and its minimum size is `size * nmemb`.
463cfca06d7SDimitry Andric class BufferSizeConstraint : public ValueConstraint {
464b60736ecSDimitry Andric // The concrete value which is the minimum size for the buffer.
465e3b55780SDimitry Andric std::optional<llvm::APSInt> ConcreteSize;
466cfca06d7SDimitry Andric // The argument which holds the size of the buffer.
467e3b55780SDimitry Andric std::optional<ArgNo> SizeArgN;
468cfca06d7SDimitry Andric // The argument which is a multiplier to size. This is set in case of
469cfca06d7SDimitry Andric // `fread` like functions where the size is computed as a multiplication of
470cfca06d7SDimitry Andric // two arguments.
471e3b55780SDimitry Andric std::optional<ArgNo> SizeMultiplierArgN;
472cfca06d7SDimitry Andric // The operator we use in apply. This is negated in negate().
473cfca06d7SDimitry Andric BinaryOperator::Opcode Op = BO_LE;
474cfca06d7SDimitry Andric
475cfca06d7SDimitry Andric public:
BufferSizeConstraint(ArgNo Buffer,llvm::APSInt BufMinSize)476b60736ecSDimitry Andric BufferSizeConstraint(ArgNo Buffer, llvm::APSInt BufMinSize)
477b60736ecSDimitry Andric : ValueConstraint(Buffer), ConcreteSize(BufMinSize) {}
BufferSizeConstraint(ArgNo Buffer,ArgNo BufSize)478cfca06d7SDimitry Andric BufferSizeConstraint(ArgNo Buffer, ArgNo BufSize)
479cfca06d7SDimitry Andric : ValueConstraint(Buffer), SizeArgN(BufSize) {}
BufferSizeConstraint(ArgNo Buffer,ArgNo BufSize,ArgNo BufSizeMultiplier)480cfca06d7SDimitry Andric BufferSizeConstraint(ArgNo Buffer, ArgNo BufSize, ArgNo BufSizeMultiplier)
481cfca06d7SDimitry Andric : ValueConstraint(Buffer), SizeArgN(BufSize),
482cfca06d7SDimitry Andric SizeMultiplierArgN(BufSizeMultiplier) {}
483cfca06d7SDimitry Andric
4847fa27ce4SDimitry Andric ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
4857fa27ce4SDimitry Andric const Summary &Summary,
4867fa27ce4SDimitry Andric CheckerContext &C) const override;
4877fa27ce4SDimitry Andric
4887fa27ce4SDimitry Andric void describe(DescriptionKind DK, const CallEvent &Call,
4897fa27ce4SDimitry Andric ProgramStateRef State, const Summary &Summary,
4907fa27ce4SDimitry Andric llvm::raw_ostream &Out) const override;
4917fa27ce4SDimitry Andric
4927fa27ce4SDimitry Andric bool describeArgumentValue(const CallEvent &Call, ProgramStateRef State,
4937fa27ce4SDimitry Andric const Summary &Summary,
4947fa27ce4SDimitry Andric llvm::raw_ostream &Out) const override;
4957fa27ce4SDimitry Andric
getArgsToTrack() const496344a3780SDimitry Andric std::vector<ArgNo> getArgsToTrack() const override {
497344a3780SDimitry Andric std::vector<ArgNo> Result{ArgN};
498344a3780SDimitry Andric if (SizeArgN)
499344a3780SDimitry Andric Result.push_back(*SizeArgN);
500344a3780SDimitry Andric if (SizeMultiplierArgN)
501344a3780SDimitry Andric Result.push_back(*SizeMultiplierArgN);
502344a3780SDimitry Andric return Result;
503344a3780SDimitry Andric }
504344a3780SDimitry Andric
negate() const505cfca06d7SDimitry Andric ValueConstraintPtr negate() const override {
506cfca06d7SDimitry Andric BufferSizeConstraint Tmp(*this);
507cfca06d7SDimitry Andric Tmp.Op = BinaryOperator::negateComparisonOp(Op);
508cfca06d7SDimitry Andric return std::make_shared<BufferSizeConstraint>(Tmp);
509cfca06d7SDimitry Andric }
510b60736ecSDimitry Andric
5117fa27ce4SDimitry Andric protected:
checkSpecificValidity(const FunctionDecl * FD) const512b60736ecSDimitry Andric bool checkSpecificValidity(const FunctionDecl *FD) const override {
513b60736ecSDimitry Andric const bool ValidArg = getArgType(FD, ArgN)->isPointerType();
514b60736ecSDimitry Andric assert(ValidArg &&
515b60736ecSDimitry Andric "This constraint should be applied only on a pointer type");
516b60736ecSDimitry Andric return ValidArg;
517b60736ecSDimitry Andric }
518cfca06d7SDimitry Andric };
519cfca06d7SDimitry Andric
520cfca06d7SDimitry Andric /// The complete list of constraints that defines a single branch.
521145449b1SDimitry Andric using ConstraintSet = std::vector<ValueConstraintPtr>;
522145449b1SDimitry Andric
523145449b1SDimitry Andric /// Define how a function affects the system variable 'errno'.
524e3b55780SDimitry Andric /// This works together with the \c ErrnoModeling and \c ErrnoChecker classes.
525e3b55780SDimitry Andric /// Currently 3 use cases exist: success, failure, irrelevant.
526e3b55780SDimitry Andric /// In the future the failure case can be customized to set \c errno to a
527e3b55780SDimitry Andric /// more specific constraint (for example > 0), or new case can be added
528e3b55780SDimitry Andric /// for functions which require check of \c errno in both success and failure
529e3b55780SDimitry Andric /// case.
530145449b1SDimitry Andric class ErrnoConstraintBase {
531145449b1SDimitry Andric public:
532145449b1SDimitry Andric /// Apply specific state changes related to the errno variable.
533145449b1SDimitry Andric virtual ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
534145449b1SDimitry Andric const Summary &Summary,
535145449b1SDimitry Andric CheckerContext &C) const = 0;
536b1c73532SDimitry Andric /// Get a description about what happens with 'errno' here and how it causes
537b1c73532SDimitry Andric /// a later bug report created by ErrnoChecker.
538b1c73532SDimitry Andric /// Empty return value means that 'errno' related bug may not happen from
539b1c73532SDimitry Andric /// the current analyzed function.
describe(CheckerContext & C) const540b1c73532SDimitry Andric virtual const std::string describe(CheckerContext &C) const { return ""; }
541145449b1SDimitry Andric
~ErrnoConstraintBase()542145449b1SDimitry Andric virtual ~ErrnoConstraintBase() {}
543145449b1SDimitry Andric
544145449b1SDimitry Andric protected:
545e3b55780SDimitry Andric ErrnoConstraintBase() = default;
546145449b1SDimitry Andric
547145449b1SDimitry Andric /// This is used for conjure symbol for errno to differentiate from the
548145449b1SDimitry Andric /// original call expression (same expression is used for the errno symbol).
549145449b1SDimitry Andric static int Tag;
550145449b1SDimitry Andric };
551145449b1SDimitry Andric
552e3b55780SDimitry Andric /// Reset errno constraints to irrelevant.
553e3b55780SDimitry Andric /// This is applicable to functions that may change 'errno' and are not
554e3b55780SDimitry Andric /// modeled elsewhere.
555e3b55780SDimitry Andric class ResetErrnoConstraint : public ErrnoConstraintBase {
556145449b1SDimitry Andric public:
apply(ProgramStateRef State,const CallEvent & Call,const Summary & Summary,CheckerContext & C) const557e3b55780SDimitry Andric ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
558e3b55780SDimitry Andric const Summary &Summary,
559e3b55780SDimitry Andric CheckerContext &C) const override {
560e3b55780SDimitry Andric return errno_modeling::setErrnoState(State, errno_modeling::Irrelevant);
561145449b1SDimitry Andric }
562e3b55780SDimitry Andric };
563145449b1SDimitry Andric
564e3b55780SDimitry Andric /// Do not change errno constraints.
565e3b55780SDimitry Andric /// This is applicable to functions that are modeled in another checker
566e3b55780SDimitry Andric /// and the already set errno constraints should not be changed in the
567e3b55780SDimitry Andric /// post-call event.
568e3b55780SDimitry Andric class NoErrnoConstraint : public ErrnoConstraintBase {
569e3b55780SDimitry Andric public:
apply(ProgramStateRef State,const CallEvent & Call,const Summary & Summary,CheckerContext & C) const570e3b55780SDimitry Andric ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
571e3b55780SDimitry Andric const Summary &Summary,
572e3b55780SDimitry Andric CheckerContext &C) const override {
573e3b55780SDimitry Andric return State;
574e3b55780SDimitry Andric }
575e3b55780SDimitry Andric };
576e3b55780SDimitry Andric
577e3b55780SDimitry Andric /// Set errno constraint at failure cases of standard functions.
578e3b55780SDimitry Andric /// Failure case: 'errno' becomes not equal to 0 and may or may not be checked
579e3b55780SDimitry Andric /// by the program. \c ErrnoChecker does not emit a bug report after such a
580e3b55780SDimitry Andric /// function call.
581e3b55780SDimitry Andric class FailureErrnoConstraint : public ErrnoConstraintBase {
582e3b55780SDimitry Andric public:
apply(ProgramStateRef State,const CallEvent & Call,const Summary & Summary,CheckerContext & C) const583145449b1SDimitry Andric ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
584145449b1SDimitry Andric const Summary &Summary,
585145449b1SDimitry Andric CheckerContext &C) const override {
586145449b1SDimitry Andric SValBuilder &SVB = C.getSValBuilder();
587145449b1SDimitry Andric NonLoc ErrnoSVal =
588145449b1SDimitry Andric SVB.conjureSymbolVal(&Tag, Call.getOriginExpr(),
589145449b1SDimitry Andric C.getLocationContext(), C.getASTContext().IntTy,
590145449b1SDimitry Andric C.blockCount())
591145449b1SDimitry Andric .castAs<NonLoc>();
592e3b55780SDimitry Andric return errno_modeling::setErrnoForStdFailure(State, C, ErrnoSVal);
593145449b1SDimitry Andric }
594145449b1SDimitry Andric };
595145449b1SDimitry Andric
596e3b55780SDimitry Andric /// Set errno constraint at success cases of standard functions.
597b1c73532SDimitry Andric /// Success case: 'errno' is not allowed to be used because the value is
598b1c73532SDimitry Andric /// undefined after successful call.
599e3b55780SDimitry Andric /// \c ErrnoChecker can emit bug report after such a function call if errno
600e3b55780SDimitry Andric /// is used.
601145449b1SDimitry Andric class SuccessErrnoConstraint : public ErrnoConstraintBase {
602145449b1SDimitry Andric public:
apply(ProgramStateRef State,const CallEvent & Call,const Summary & Summary,CheckerContext & C) const603145449b1SDimitry Andric ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
604145449b1SDimitry Andric const Summary &Summary,
605145449b1SDimitry Andric CheckerContext &C) const override {
606e3b55780SDimitry Andric return errno_modeling::setErrnoForStdSuccess(State, C);
607145449b1SDimitry Andric }
608145449b1SDimitry Andric
describe(CheckerContext & C) const609b1c73532SDimitry Andric const std::string describe(CheckerContext &C) const override {
610b1c73532SDimitry Andric return "'errno' becomes undefined after the call";
611145449b1SDimitry Andric }
612145449b1SDimitry Andric };
613145449b1SDimitry Andric
614b1c73532SDimitry Andric /// Set errno constraint at functions that indicate failure only with 'errno'.
615b1c73532SDimitry Andric /// In this case 'errno' is required to be observed.
616b1c73532SDimitry Andric /// \c ErrnoChecker can emit bug report after such a function call if errno
617b1c73532SDimitry Andric /// is overwritten without a read before.
618e3b55780SDimitry Andric class ErrnoMustBeCheckedConstraint : public ErrnoConstraintBase {
619145449b1SDimitry Andric public:
apply(ProgramStateRef State,const CallEvent & Call,const Summary & Summary,CheckerContext & C) const620145449b1SDimitry Andric ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
621145449b1SDimitry Andric const Summary &Summary,
622145449b1SDimitry Andric CheckerContext &C) const override {
623e3b55780SDimitry Andric return errno_modeling::setErrnoStdMustBeChecked(State, C,
624e3b55780SDimitry Andric Call.getOriginExpr());
625e3b55780SDimitry Andric }
626e3b55780SDimitry Andric
describe(CheckerContext & C) const627b1c73532SDimitry Andric const std::string describe(CheckerContext &C) const override {
628b1c73532SDimitry Andric return "reading 'errno' is required to find out if the call has failed";
629145449b1SDimitry Andric }
630145449b1SDimitry Andric };
631145449b1SDimitry Andric
632145449b1SDimitry Andric /// A single branch of a function summary.
633145449b1SDimitry Andric ///
634145449b1SDimitry Andric /// A branch is defined by a series of constraints - "assumptions" -
635145449b1SDimitry Andric /// that together form a single possible outcome of invoking the function.
636145449b1SDimitry Andric /// When static analyzer considers a branch, it tries to introduce
637145449b1SDimitry Andric /// a child node in the Exploded Graph. The child node has to include
638145449b1SDimitry Andric /// constraints that define the branch. If the constraints contradict
639145449b1SDimitry Andric /// existing constraints in the state, the node is not created and the branch
640145449b1SDimitry Andric /// is dropped; otherwise it's queued for future exploration.
641145449b1SDimitry Andric /// The branch is accompanied by a note text that may be displayed
642145449b1SDimitry Andric /// to the user when a bug is found on a path that takes this branch.
643145449b1SDimitry Andric ///
644145449b1SDimitry Andric /// For example, consider the branches in `isalpha(x)`:
645145449b1SDimitry Andric /// Branch 1)
646145449b1SDimitry Andric /// x is in range ['A', 'Z'] or in ['a', 'z']
647145449b1SDimitry Andric /// then the return value is not 0. (I.e. out-of-range [0, 0])
648145449b1SDimitry Andric /// and the note may say "Assuming the character is alphabetical"
649145449b1SDimitry Andric /// Branch 2)
650145449b1SDimitry Andric /// x is out-of-range ['A', 'Z'] and out-of-range ['a', 'z']
651145449b1SDimitry Andric /// then the return value is 0
652145449b1SDimitry Andric /// and the note may say "Assuming the character is non-alphabetical".
653145449b1SDimitry Andric class SummaryCase {
654145449b1SDimitry Andric ConstraintSet Constraints;
655145449b1SDimitry Andric const ErrnoConstraintBase &ErrnoConstraint;
656145449b1SDimitry Andric StringRef Note;
657145449b1SDimitry Andric
658145449b1SDimitry Andric public:
SummaryCase(ConstraintSet && Constraints,const ErrnoConstraintBase & ErrnoC,StringRef Note)659145449b1SDimitry Andric SummaryCase(ConstraintSet &&Constraints, const ErrnoConstraintBase &ErrnoC,
660145449b1SDimitry Andric StringRef Note)
661145449b1SDimitry Andric : Constraints(std::move(Constraints)), ErrnoConstraint(ErrnoC),
662145449b1SDimitry Andric Note(Note) {}
663145449b1SDimitry Andric
SummaryCase(const ConstraintSet & Constraints,const ErrnoConstraintBase & ErrnoC,StringRef Note)664145449b1SDimitry Andric SummaryCase(const ConstraintSet &Constraints,
665145449b1SDimitry Andric const ErrnoConstraintBase &ErrnoC, StringRef Note)
666145449b1SDimitry Andric : Constraints(Constraints), ErrnoConstraint(ErrnoC), Note(Note) {}
667145449b1SDimitry Andric
getConstraints() const668145449b1SDimitry Andric const ConstraintSet &getConstraints() const { return Constraints; }
getErrnoConstraint() const669145449b1SDimitry Andric const ErrnoConstraintBase &getErrnoConstraint() const {
670145449b1SDimitry Andric return ErrnoConstraint;
671145449b1SDimitry Andric }
getNote() const672145449b1SDimitry Andric StringRef getNote() const { return Note; }
673145449b1SDimitry Andric };
674cfca06d7SDimitry Andric
675ac9a064cSDimitry Andric using ArgTypes = ArrayRef<std::optional<QualType>>;
676e3b55780SDimitry Andric using RetType = std::optional<QualType>;
677cfca06d7SDimitry Andric
678cfca06d7SDimitry Andric // A placeholder type, we use it whenever we do not care about the concrete
679cfca06d7SDimitry Andric // type in a Signature.
680cfca06d7SDimitry Andric const QualType Irrelevant{};
isIrrelevant(QualType T)681cfca06d7SDimitry Andric bool static isIrrelevant(QualType T) { return T.isNull(); }
682cfca06d7SDimitry Andric
683cfca06d7SDimitry Andric // The signature of a function we want to describe with a summary. This is a
684cfca06d7SDimitry Andric // concessive signature, meaning there may be irrelevant types in the
685cfca06d7SDimitry Andric // signature which we do not check against a function with concrete types.
686b60736ecSDimitry Andric // All types in the spec need to be canonical.
687b60736ecSDimitry Andric class Signature {
688b60736ecSDimitry Andric using ArgQualTypes = std::vector<QualType>;
689b60736ecSDimitry Andric ArgQualTypes ArgTys;
690b60736ecSDimitry Andric QualType RetTy;
691b60736ecSDimitry Andric // True if any component type is not found by lookup.
692b60736ecSDimitry Andric bool Invalid = false;
693b60736ecSDimitry Andric
694b60736ecSDimitry Andric public:
695b60736ecSDimitry Andric // Construct a signature from optional types. If any of the optional types
696b60736ecSDimitry Andric // are not set then the signature will be invalid.
Signature(ArgTypes ArgTys,RetType RetTy)697b60736ecSDimitry Andric Signature(ArgTypes ArgTys, RetType RetTy) {
698e3b55780SDimitry Andric for (std::optional<QualType> Arg : ArgTys) {
699b60736ecSDimitry Andric if (!Arg) {
700b60736ecSDimitry Andric Invalid = true;
701b60736ecSDimitry Andric return;
702b60736ecSDimitry Andric } else {
703b60736ecSDimitry Andric assertArgTypeSuitableForSignature(*Arg);
704b60736ecSDimitry Andric this->ArgTys.push_back(*Arg);
705cfca06d7SDimitry Andric }
706cfca06d7SDimitry Andric }
707b60736ecSDimitry Andric if (!RetTy) {
708b60736ecSDimitry Andric Invalid = true;
709b60736ecSDimitry Andric return;
710b60736ecSDimitry Andric } else {
711b60736ecSDimitry Andric assertRetTypeSuitableForSignature(*RetTy);
712b60736ecSDimitry Andric this->RetTy = *RetTy;
713b60736ecSDimitry Andric }
714b60736ecSDimitry Andric }
715b60736ecSDimitry Andric
isInvalid() const716b60736ecSDimitry Andric bool isInvalid() const { return Invalid; }
717cfca06d7SDimitry Andric bool matches(const FunctionDecl *FD) const;
718cfca06d7SDimitry Andric
719cfca06d7SDimitry Andric private:
assertArgTypeSuitableForSignature(QualType T)720cfca06d7SDimitry Andric static void assertArgTypeSuitableForSignature(QualType T) {
721cfca06d7SDimitry Andric assert((T.isNull() || !T->isVoidType()) &&
722cfca06d7SDimitry Andric "We should have no void types in the spec");
723cfca06d7SDimitry Andric assert((T.isNull() || T.isCanonical()) &&
724cfca06d7SDimitry Andric "We should only have canonical types in the spec");
725cfca06d7SDimitry Andric }
assertRetTypeSuitableForSignature(QualType T)726cfca06d7SDimitry Andric static void assertRetTypeSuitableForSignature(QualType T) {
727cfca06d7SDimitry Andric assert((T.isNull() || T.isCanonical()) &&
728cfca06d7SDimitry Andric "We should only have canonical types in the spec");
729cfca06d7SDimitry Andric }
730cfca06d7SDimitry Andric };
731cfca06d7SDimitry Andric
getArgType(const FunctionDecl * FD,ArgNo ArgN)732cfca06d7SDimitry Andric static QualType getArgType(const FunctionDecl *FD, ArgNo ArgN) {
733cfca06d7SDimitry Andric assert(FD && "Function must be set");
734cfca06d7SDimitry Andric QualType T = (ArgN == Ret)
735cfca06d7SDimitry Andric ? FD->getReturnType().getCanonicalType()
736cfca06d7SDimitry Andric : FD->getParamDecl(ArgN)->getType().getCanonicalType();
737bab175ecSDimitry Andric return T;
738bab175ecSDimitry Andric }
739bab175ecSDimitry Andric
740145449b1SDimitry Andric using SummaryCases = std::vector<SummaryCase>;
741bab175ecSDimitry Andric
742cfca06d7SDimitry Andric /// A summary includes information about
743cfca06d7SDimitry Andric /// * function prototype (signature)
744cfca06d7SDimitry Andric /// * approach to invalidation,
745145449b1SDimitry Andric /// * a list of branches - so, a list of list of ranges,
746cfca06d7SDimitry Andric /// * a list of argument constraints, that must be true on every branch.
747cfca06d7SDimitry Andric /// If these constraints are not satisfied that means a fatal error
748cfca06d7SDimitry Andric /// usually resulting in undefined behaviour.
749cfca06d7SDimitry Andric ///
750cfca06d7SDimitry Andric /// Application of a summary:
751cfca06d7SDimitry Andric /// The signature and argument constraints together contain information
752cfca06d7SDimitry Andric /// about which functions are handled by the summary. The signature can use
753cfca06d7SDimitry Andric /// "wildcards", i.e. Irrelevant types. Irrelevant type of a parameter in
754cfca06d7SDimitry Andric /// a signature means that type is not compared to the type of the parameter
755cfca06d7SDimitry Andric /// in the found FunctionDecl. Argument constraints may specify additional
756cfca06d7SDimitry Andric /// rules for the given parameter's type, those rules are checked once the
757cfca06d7SDimitry Andric /// signature is matched.
758cfca06d7SDimitry Andric class Summary {
759cfca06d7SDimitry Andric const InvalidationKind InvalidationKd;
760145449b1SDimitry Andric SummaryCases Cases;
761cfca06d7SDimitry Andric ConstraintSet ArgConstraints;
762cfca06d7SDimitry Andric
763cfca06d7SDimitry Andric // The function to which the summary applies. This is set after lookup and
764cfca06d7SDimitry Andric // match to the signature.
765cfca06d7SDimitry Andric const FunctionDecl *FD = nullptr;
766cfca06d7SDimitry Andric
767cfca06d7SDimitry Andric public:
Summary(InvalidationKind InvalidationKd)768b60736ecSDimitry Andric Summary(InvalidationKind InvalidationKd) : InvalidationKd(InvalidationKd) {}
769cfca06d7SDimitry Andric
Case(ConstraintSet && CS,const ErrnoConstraintBase & ErrnoC,StringRef Note="")770145449b1SDimitry Andric Summary &Case(ConstraintSet &&CS, const ErrnoConstraintBase &ErrnoC,
771145449b1SDimitry Andric StringRef Note = "") {
772145449b1SDimitry Andric Cases.push_back(SummaryCase(std::move(CS), ErrnoC, Note));
773cfca06d7SDimitry Andric return *this;
774cfca06d7SDimitry Andric }
Case(const ConstraintSet & CS,const ErrnoConstraintBase & ErrnoC,StringRef Note="")775145449b1SDimitry Andric Summary &Case(const ConstraintSet &CS, const ErrnoConstraintBase &ErrnoC,
776145449b1SDimitry Andric StringRef Note = "") {
777145449b1SDimitry Andric Cases.push_back(SummaryCase(CS, ErrnoC, Note));
778b60736ecSDimitry Andric return *this;
779b60736ecSDimitry Andric }
ArgConstraint(ValueConstraintPtr VC)780cfca06d7SDimitry Andric Summary &ArgConstraint(ValueConstraintPtr VC) {
781b60736ecSDimitry Andric assert(VC->getArgNo() != Ret &&
782b60736ecSDimitry Andric "Arg constraint should not refer to the return value");
783cfca06d7SDimitry Andric ArgConstraints.push_back(VC);
784cfca06d7SDimitry Andric return *this;
785cfca06d7SDimitry Andric }
786cfca06d7SDimitry Andric
getInvalidationKd() const787cfca06d7SDimitry Andric InvalidationKind getInvalidationKd() const { return InvalidationKd; }
getCases() const788145449b1SDimitry Andric const SummaryCases &getCases() const { return Cases; }
getArgConstraints() const789cfca06d7SDimitry Andric const ConstraintSet &getArgConstraints() const { return ArgConstraints; }
790cfca06d7SDimitry Andric
getArgType(ArgNo ArgN) const791cfca06d7SDimitry Andric QualType getArgType(ArgNo ArgN) const {
792cfca06d7SDimitry Andric return StdLibraryFunctionsChecker::getArgType(FD, ArgN);
793cfca06d7SDimitry Andric }
794cfca06d7SDimitry Andric
795cfca06d7SDimitry Andric // Returns true if the summary should be applied to the given function.
796cfca06d7SDimitry Andric // And if yes then store the function declaration.
matchesAndSet(const Signature & Sign,const FunctionDecl * FD)797b60736ecSDimitry Andric bool matchesAndSet(const Signature &Sign, const FunctionDecl *FD) {
798cfca06d7SDimitry Andric bool Result = Sign.matches(FD) && validateByConstraints(FD);
799cfca06d7SDimitry Andric if (Result) {
800cfca06d7SDimitry Andric assert(!this->FD && "FD must not be set more than once");
801cfca06d7SDimitry Andric this->FD = FD;
802cfca06d7SDimitry Andric }
803cfca06d7SDimitry Andric return Result;
804cfca06d7SDimitry Andric }
805cfca06d7SDimitry Andric
806cfca06d7SDimitry Andric private:
807846a2208SDimitry Andric // Once we know the exact type of the function then do validation check on
808846a2208SDimitry Andric // all the given constraints.
validateByConstraints(const FunctionDecl * FD) const809cfca06d7SDimitry Andric bool validateByConstraints(const FunctionDecl *FD) const {
810145449b1SDimitry Andric for (const SummaryCase &Case : Cases)
811145449b1SDimitry Andric for (const ValueConstraintPtr &Constraint : Case.getConstraints())
812cfca06d7SDimitry Andric if (!Constraint->checkValidity(FD))
813cfca06d7SDimitry Andric return false;
814cfca06d7SDimitry Andric for (const ValueConstraintPtr &Constraint : ArgConstraints)
815cfca06d7SDimitry Andric if (!Constraint->checkValidity(FD))
816cfca06d7SDimitry Andric return false;
817cfca06d7SDimitry Andric return true;
818cfca06d7SDimitry Andric }
819cfca06d7SDimitry Andric };
820bab175ecSDimitry Andric
821bab175ecSDimitry Andric // The map of all functions supported by the checker. It is initialized
822bab175ecSDimitry Andric // lazily, and it doesn't change after initialization.
823cfca06d7SDimitry Andric using FunctionSummaryMapType = llvm::DenseMap<const FunctionDecl *, Summary>;
824cfca06d7SDimitry Andric mutable FunctionSummaryMapType FunctionSummaryMap;
825bab175ecSDimitry Andric
82677dbea07SDimitry Andric const BugType BT_InvalidArg{this, "Function call with invalid argument"};
827344a3780SDimitry Andric mutable bool SummariesInitialized = false;
828cfca06d7SDimitry Andric
getArgSVal(const CallEvent & Call,ArgNo ArgN)829cfca06d7SDimitry Andric static SVal getArgSVal(const CallEvent &Call, ArgNo ArgN) {
830cfca06d7SDimitry Andric return ArgN == Ret ? Call.getReturnValue() : Call.getArgSVal(ArgN);
831bab175ecSDimitry Andric }
getFunctionName(const CallEvent & Call)8327fa27ce4SDimitry Andric static std::string getFunctionName(const CallEvent &Call) {
8337fa27ce4SDimitry Andric assert(Call.getDecl() &&
8347fa27ce4SDimitry Andric "Call was found by a summary, should have declaration");
8357fa27ce4SDimitry Andric return cast<NamedDecl>(Call.getDecl())->getNameAsString();
8367fa27ce4SDimitry Andric }
837bab175ecSDimitry Andric
838bab175ecSDimitry Andric public:
839cfca06d7SDimitry Andric void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
840bab175ecSDimitry Andric void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
84122989816SDimitry Andric bool evalCall(const CallEvent &Call, CheckerContext &C) const;
842bab175ecSDimitry Andric
8437fa27ce4SDimitry Andric CheckerNameRef CheckName;
8447fa27ce4SDimitry Andric bool AddTestFunctions = false;
845cfca06d7SDimitry Andric
846cfca06d7SDimitry Andric bool DisplayLoadedSummaries = false;
847cfca06d7SDimitry Andric bool ModelPOSIX = false;
848c0981da4SDimitry Andric bool ShouldAssumeControlledEnvironment = false;
849cfca06d7SDimitry Andric
850bab175ecSDimitry Andric private:
851e3b55780SDimitry Andric std::optional<Summary> findFunctionSummary(const FunctionDecl *FD,
852cfca06d7SDimitry Andric CheckerContext &C) const;
853e3b55780SDimitry Andric std::optional<Summary> findFunctionSummary(const CallEvent &Call,
854bab175ecSDimitry Andric CheckerContext &C) const;
855bab175ecSDimitry Andric
856cfca06d7SDimitry Andric void initFunctionSummaries(CheckerContext &C) const;
857cfca06d7SDimitry Andric
reportBug(const CallEvent & Call,ExplodedNode * N,const ValueConstraint * VC,const ValueConstraint * NegatedVC,const Summary & Summary,CheckerContext & C) const858cfca06d7SDimitry Andric void reportBug(const CallEvent &Call, ExplodedNode *N,
8597fa27ce4SDimitry Andric const ValueConstraint *VC, const ValueConstraint *NegatedVC,
8607fa27ce4SDimitry Andric const Summary &Summary, CheckerContext &C) const {
8617fa27ce4SDimitry Andric assert(Call.getDecl() &&
8627fa27ce4SDimitry Andric "Function found in summary must have a declaration available");
8637fa27ce4SDimitry Andric SmallString<256> Msg;
8647fa27ce4SDimitry Andric llvm::raw_svector_ostream MsgOs(Msg);
8657fa27ce4SDimitry Andric
8667fa27ce4SDimitry Andric MsgOs << "The ";
8677fa27ce4SDimitry Andric printArgDesc(VC->getArgNo(), MsgOs);
8687fa27ce4SDimitry Andric MsgOs << " to '" << getFunctionName(Call) << "' ";
8697fa27ce4SDimitry Andric bool ValuesPrinted =
8707fa27ce4SDimitry Andric NegatedVC->describeArgumentValue(Call, N->getState(), Summary, MsgOs);
8717fa27ce4SDimitry Andric if (ValuesPrinted)
8727fa27ce4SDimitry Andric MsgOs << " but ";
8737fa27ce4SDimitry Andric else
8747fa27ce4SDimitry Andric MsgOs << "is out of the accepted range; It ";
8757fa27ce4SDimitry Andric VC->describe(ValueConstraint::Violation, Call, C.getState(), Summary,
8767fa27ce4SDimitry Andric MsgOs);
8777fa27ce4SDimitry Andric Msg[0] = toupper(Msg[0]);
87877dbea07SDimitry Andric auto R = std::make_unique<PathSensitiveBugReport>(BT_InvalidArg, Msg, N);
879344a3780SDimitry Andric
8807fa27ce4SDimitry Andric for (ArgNo ArgN : VC->getArgsToTrack()) {
881344a3780SDimitry Andric bugreporter::trackExpressionValue(N, Call.getArgExpr(ArgN), *R);
8827fa27ce4SDimitry Andric R->markInteresting(Call.getArgSVal(ArgN));
8837fa27ce4SDimitry Andric // All tracked arguments are important, highlight them.
8847fa27ce4SDimitry Andric R->addRange(Call.getArgSourceRange(ArgN));
8857fa27ce4SDimitry Andric }
886344a3780SDimitry Andric
887cfca06d7SDimitry Andric C.emitReport(std::move(R));
888cfca06d7SDimitry Andric }
889145449b1SDimitry Andric
890145449b1SDimitry Andric /// These are the errno constraints that can be passed to summary cases.
891145449b1SDimitry Andric /// One of these should fit for a single summary case.
892145449b1SDimitry Andric /// Usually if a failure return value exists for function, that function
893145449b1SDimitry Andric /// needs different cases for success and failure with different errno
894145449b1SDimitry Andric /// constraints (and different return value constraints).
895e3b55780SDimitry Andric const NoErrnoConstraint ErrnoUnchanged{};
896e3b55780SDimitry Andric const ResetErrnoConstraint ErrnoIrrelevant{};
897e3b55780SDimitry Andric const ErrnoMustBeCheckedConstraint ErrnoMustBeChecked{};
898e3b55780SDimitry Andric const SuccessErrnoConstraint ErrnoMustNotBeChecked{};
899e3b55780SDimitry Andric const FailureErrnoConstraint ErrnoNEZeroIrrelevant{};
900bab175ecSDimitry Andric };
901cfca06d7SDimitry Andric
902145449b1SDimitry Andric int StdLibraryFunctionsChecker::ErrnoConstraintBase::Tag = 0;
903145449b1SDimitry Andric
904cfca06d7SDimitry Andric const StdLibraryFunctionsChecker::ArgNo StdLibraryFunctionsChecker::Ret =
905cfca06d7SDimitry Andric std::numeric_limits<ArgNo>::max();
906cfca06d7SDimitry Andric
getBVF(ProgramStateRef State)907344a3780SDimitry Andric static BasicValueFactory &getBVF(ProgramStateRef State) {
908344a3780SDimitry Andric ProgramStateManager &Mgr = State->getStateManager();
909344a3780SDimitry Andric SValBuilder &SVB = Mgr.getSValBuilder();
910344a3780SDimitry Andric return SVB.getBasicValueFactory();
911344a3780SDimitry Andric }
912344a3780SDimitry Andric
9137fa27ce4SDimitry Andric } // end of anonymous namespace
9147fa27ce4SDimitry Andric
printArgDesc(StdLibraryFunctionsChecker::ArgNo ArgN,llvm::raw_ostream & Out)9157fa27ce4SDimitry Andric void StdLibraryFunctionsChecker::printArgDesc(
9167fa27ce4SDimitry Andric StdLibraryFunctionsChecker::ArgNo ArgN, llvm::raw_ostream &Out) {
9177fa27ce4SDimitry Andric Out << std::to_string(ArgN + 1);
9187fa27ce4SDimitry Andric Out << llvm::getOrdinalSuffix(ArgN + 1);
9197fa27ce4SDimitry Andric Out << " argument";
920344a3780SDimitry Andric }
921344a3780SDimitry Andric
printArgValueInfo(ArgNo ArgN,ProgramStateRef State,const CallEvent & Call,llvm::raw_ostream & Out)9227fa27ce4SDimitry Andric void StdLibraryFunctionsChecker::printArgValueInfo(ArgNo ArgN,
9237fa27ce4SDimitry Andric ProgramStateRef State,
9247fa27ce4SDimitry Andric const CallEvent &Call,
9257fa27ce4SDimitry Andric llvm::raw_ostream &Out) {
9267fa27ce4SDimitry Andric if (const llvm::APSInt *Val =
9277fa27ce4SDimitry Andric State->getStateManager().getSValBuilder().getKnownValue(
9287fa27ce4SDimitry Andric State, getArgSVal(Call, ArgN)))
9297fa27ce4SDimitry Andric Out << " (which is " << *Val << ")";
9307fa27ce4SDimitry Andric }
9317fa27ce4SDimitry Andric
appendInsideRangeDesc(llvm::APSInt RMin,llvm::APSInt RMax,QualType ArgT,BasicValueFactory & BVF,llvm::raw_ostream & Out)9327fa27ce4SDimitry Andric void StdLibraryFunctionsChecker::appendInsideRangeDesc(llvm::APSInt RMin,
9337fa27ce4SDimitry Andric llvm::APSInt RMax,
9347fa27ce4SDimitry Andric QualType ArgT,
9357fa27ce4SDimitry Andric BasicValueFactory &BVF,
9367fa27ce4SDimitry Andric llvm::raw_ostream &Out) {
9377fa27ce4SDimitry Andric if (RMin.isZero() && RMax.isZero())
9387fa27ce4SDimitry Andric Out << "zero";
9397fa27ce4SDimitry Andric else if (RMin == RMax)
9407fa27ce4SDimitry Andric Out << RMin;
9417fa27ce4SDimitry Andric else if (RMin == BVF.getMinValue(ArgT)) {
9427fa27ce4SDimitry Andric if (RMax == -1)
9437fa27ce4SDimitry Andric Out << "< 0";
9447fa27ce4SDimitry Andric else
9457fa27ce4SDimitry Andric Out << "<= " << RMax;
9467fa27ce4SDimitry Andric } else if (RMax == BVF.getMaxValue(ArgT)) {
9477fa27ce4SDimitry Andric if (RMin.isOne())
9487fa27ce4SDimitry Andric Out << "> 0";
9497fa27ce4SDimitry Andric else
9507fa27ce4SDimitry Andric Out << ">= " << RMin;
9517fa27ce4SDimitry Andric } else if (RMin.isNegative() == RMax.isNegative() &&
9527fa27ce4SDimitry Andric RMin.getLimitedValue() == RMax.getLimitedValue() - 1) {
9537fa27ce4SDimitry Andric Out << RMin << " or " << RMax;
9547fa27ce4SDimitry Andric } else {
9557fa27ce4SDimitry Andric Out << "between " << RMin << " and " << RMax;
9567fa27ce4SDimitry Andric }
9577fa27ce4SDimitry Andric }
9587fa27ce4SDimitry Andric
appendOutOfRangeDesc(llvm::APSInt RMin,llvm::APSInt RMax,QualType ArgT,BasicValueFactory & BVF,llvm::raw_ostream & Out)9597fa27ce4SDimitry Andric void StdLibraryFunctionsChecker::appendOutOfRangeDesc(llvm::APSInt RMin,
9607fa27ce4SDimitry Andric llvm::APSInt RMax,
9617fa27ce4SDimitry Andric QualType ArgT,
9627fa27ce4SDimitry Andric BasicValueFactory &BVF,
9637fa27ce4SDimitry Andric llvm::raw_ostream &Out) {
9647fa27ce4SDimitry Andric if (RMin.isZero() && RMax.isZero())
9657fa27ce4SDimitry Andric Out << "nonzero";
9667fa27ce4SDimitry Andric else if (RMin == RMax) {
9677fa27ce4SDimitry Andric Out << "not equal to " << RMin;
9687fa27ce4SDimitry Andric } else if (RMin == BVF.getMinValue(ArgT)) {
9697fa27ce4SDimitry Andric if (RMax == -1)
9707fa27ce4SDimitry Andric Out << ">= 0";
9717fa27ce4SDimitry Andric else
9727fa27ce4SDimitry Andric Out << "> " << RMax;
9737fa27ce4SDimitry Andric } else if (RMax == BVF.getMaxValue(ArgT)) {
9747fa27ce4SDimitry Andric if (RMin.isOne())
9757fa27ce4SDimitry Andric Out << "<= 0";
9767fa27ce4SDimitry Andric else
9777fa27ce4SDimitry Andric Out << "< " << RMin;
9787fa27ce4SDimitry Andric } else if (RMin.isNegative() == RMax.isNegative() &&
9797fa27ce4SDimitry Andric RMin.getLimitedValue() == RMax.getLimitedValue() - 1) {
9807fa27ce4SDimitry Andric Out << "not " << RMin << " and not " << RMax;
9817fa27ce4SDimitry Andric } else {
9827fa27ce4SDimitry Andric Out << "not between " << RMin << " and " << RMax;
9837fa27ce4SDimitry Andric }
9847fa27ce4SDimitry Andric }
9857fa27ce4SDimitry Andric
applyOnWithinRange(BasicValueFactory & BVF,QualType ArgT,const RangeApplyFunction & F) const9867fa27ce4SDimitry Andric void StdLibraryFunctionsChecker::RangeConstraint::applyOnWithinRange(
9877fa27ce4SDimitry Andric BasicValueFactory &BVF, QualType ArgT, const RangeApplyFunction &F) const {
9887fa27ce4SDimitry Andric if (Ranges.empty())
9897fa27ce4SDimitry Andric return;
9907fa27ce4SDimitry Andric
9917fa27ce4SDimitry Andric for (auto [Start, End] : getRanges()) {
9927fa27ce4SDimitry Andric const llvm::APSInt &Min = BVF.getValue(Start, ArgT);
9937fa27ce4SDimitry Andric const llvm::APSInt &Max = BVF.getValue(End, ArgT);
9947fa27ce4SDimitry Andric assert(Min <= Max);
9957fa27ce4SDimitry Andric if (!F(Min, Max))
9967fa27ce4SDimitry Andric return;
9977fa27ce4SDimitry Andric }
9987fa27ce4SDimitry Andric }
9997fa27ce4SDimitry Andric
applyOnOutOfRange(BasicValueFactory & BVF,QualType ArgT,const RangeApplyFunction & F) const10007fa27ce4SDimitry Andric void StdLibraryFunctionsChecker::RangeConstraint::applyOnOutOfRange(
10017fa27ce4SDimitry Andric BasicValueFactory &BVF, QualType ArgT, const RangeApplyFunction &F) const {
10027fa27ce4SDimitry Andric if (Ranges.empty())
10037fa27ce4SDimitry Andric return;
10047fa27ce4SDimitry Andric
10057fa27ce4SDimitry Andric const IntRangeVector &R = getRanges();
10067fa27ce4SDimitry Andric size_t E = R.size();
10077fa27ce4SDimitry Andric
10087fa27ce4SDimitry Andric const llvm::APSInt &MinusInf = BVF.getMinValue(ArgT);
10097fa27ce4SDimitry Andric const llvm::APSInt &PlusInf = BVF.getMaxValue(ArgT);
10107fa27ce4SDimitry Andric
10117fa27ce4SDimitry Andric const llvm::APSInt &RangeLeft = BVF.getValue(R[0].first - 1ULL, ArgT);
10127fa27ce4SDimitry Andric const llvm::APSInt &RangeRight = BVF.getValue(R[E - 1].second + 1ULL, ArgT);
10137fa27ce4SDimitry Andric
10147fa27ce4SDimitry Andric // Iterate over the "holes" between intervals.
10157fa27ce4SDimitry Andric for (size_t I = 1; I != E; ++I) {
10167fa27ce4SDimitry Andric const llvm::APSInt &Min = BVF.getValue(R[I - 1].second + 1ULL, ArgT);
10177fa27ce4SDimitry Andric const llvm::APSInt &Max = BVF.getValue(R[I].first - 1ULL, ArgT);
10187fa27ce4SDimitry Andric if (Min <= Max) {
10197fa27ce4SDimitry Andric if (!F(Min, Max))
10207fa27ce4SDimitry Andric return;
10217fa27ce4SDimitry Andric }
10227fa27ce4SDimitry Andric }
10237fa27ce4SDimitry Andric // Check the interval [T_MIN, min(R) - 1].
10247fa27ce4SDimitry Andric if (RangeLeft != PlusInf) {
10257fa27ce4SDimitry Andric assert(MinusInf <= RangeLeft);
10267fa27ce4SDimitry Andric if (!F(MinusInf, RangeLeft))
10277fa27ce4SDimitry Andric return;
10287fa27ce4SDimitry Andric }
10297fa27ce4SDimitry Andric // Check the interval [max(R) + 1, T_MAX],
10307fa27ce4SDimitry Andric if (RangeRight != MinusInf) {
10317fa27ce4SDimitry Andric assert(RangeRight <= PlusInf);
10327fa27ce4SDimitry Andric if (!F(RangeRight, PlusInf))
10337fa27ce4SDimitry Andric return;
10347fa27ce4SDimitry Andric }
10357fa27ce4SDimitry Andric }
10367fa27ce4SDimitry Andric
apply(ProgramStateRef State,const CallEvent & Call,const Summary & Summary,CheckerContext & C) const10377fa27ce4SDimitry Andric ProgramStateRef StdLibraryFunctionsChecker::RangeConstraint::apply(
10387fa27ce4SDimitry Andric ProgramStateRef State, const CallEvent &Call, const Summary &Summary,
10397fa27ce4SDimitry Andric CheckerContext &C) const {
10407fa27ce4SDimitry Andric ConstraintManager &CM = C.getConstraintManager();
10417fa27ce4SDimitry Andric SVal V = getArgSVal(Call, getArgNo());
10427fa27ce4SDimitry Andric QualType T = Summary.getArgType(getArgNo());
10437fa27ce4SDimitry Andric
10447fa27ce4SDimitry Andric if (auto N = V.getAs<NonLoc>()) {
10457fa27ce4SDimitry Andric auto ExcludeRangeFromArg = [&](const llvm::APSInt &Min,
10467fa27ce4SDimitry Andric const llvm::APSInt &Max) {
10477fa27ce4SDimitry Andric State = CM.assumeInclusiveRange(State, *N, Min, Max, false);
10487fa27ce4SDimitry Andric return static_cast<bool>(State);
10497fa27ce4SDimitry Andric };
10507fa27ce4SDimitry Andric // "OutOfRange R" is handled by excluding all ranges in R.
10517fa27ce4SDimitry Andric // "WithinRange R" is treated as "OutOfRange [T_MIN, T_MAX] \ R".
10527fa27ce4SDimitry Andric applyOnRange(negateKind(Kind), C.getSValBuilder().getBasicValueFactory(), T,
10537fa27ce4SDimitry Andric ExcludeRangeFromArg);
10547fa27ce4SDimitry Andric }
10557fa27ce4SDimitry Andric
10567fa27ce4SDimitry Andric return State;
10577fa27ce4SDimitry Andric }
10587fa27ce4SDimitry Andric
describe(DescriptionKind DK,const CallEvent & Call,ProgramStateRef State,const Summary & Summary,llvm::raw_ostream & Out) const10597fa27ce4SDimitry Andric void StdLibraryFunctionsChecker::RangeConstraint::describe(
10607fa27ce4SDimitry Andric DescriptionKind DK, const CallEvent &Call, ProgramStateRef State,
10617fa27ce4SDimitry Andric const Summary &Summary, llvm::raw_ostream &Out) const {
1062344a3780SDimitry Andric
1063344a3780SDimitry Andric BasicValueFactory &BVF = getBVF(State);
1064344a3780SDimitry Andric QualType T = Summary.getArgType(getArgNo());
1065344a3780SDimitry Andric
10667fa27ce4SDimitry Andric Out << ((DK == Violation) ? "should be " : "is ");
10677fa27ce4SDimitry Andric if (!Description.empty()) {
10687fa27ce4SDimitry Andric Out << Description;
10697fa27ce4SDimitry Andric } else {
1070344a3780SDimitry Andric unsigned I = Ranges.size();
10717fa27ce4SDimitry Andric if (Kind == WithinRange) {
1072344a3780SDimitry Andric for (const std::pair<RangeInt, RangeInt> &R : Ranges) {
10737fa27ce4SDimitry Andric appendInsideRangeDesc(BVF.getValue(R.first, T),
10747fa27ce4SDimitry Andric BVF.getValue(R.second, T), T, BVF, Out);
1075344a3780SDimitry Andric if (--I > 0)
10767fa27ce4SDimitry Andric Out << " or ";
1077344a3780SDimitry Andric }
10787fa27ce4SDimitry Andric } else {
10797fa27ce4SDimitry Andric for (const std::pair<RangeInt, RangeInt> &R : Ranges) {
10807fa27ce4SDimitry Andric appendOutOfRangeDesc(BVF.getValue(R.first, T),
10817fa27ce4SDimitry Andric BVF.getValue(R.second, T), T, BVF, Out);
10827fa27ce4SDimitry Andric if (--I > 0)
10837fa27ce4SDimitry Andric Out << " and ";
10847fa27ce4SDimitry Andric }
10857fa27ce4SDimitry Andric }
10867fa27ce4SDimitry Andric }
1087344a3780SDimitry Andric }
1088344a3780SDimitry Andric
describeArgumentValue(const CallEvent & Call,ProgramStateRef State,const Summary & Summary,llvm::raw_ostream & Out) const10897fa27ce4SDimitry Andric bool StdLibraryFunctionsChecker::RangeConstraint::describeArgumentValue(
10907fa27ce4SDimitry Andric const CallEvent &Call, ProgramStateRef State, const Summary &Summary,
10917fa27ce4SDimitry Andric llvm::raw_ostream &Out) const {
10927fa27ce4SDimitry Andric unsigned int NRanges = 0;
10937fa27ce4SDimitry Andric bool HaveAllRanges = true;
1094bab175ecSDimitry Andric
1095bab175ecSDimitry Andric ProgramStateManager &Mgr = State->getStateManager();
10967fa27ce4SDimitry Andric BasicValueFactory &BVF = Mgr.getSValBuilder().getBasicValueFactory();
1097bab175ecSDimitry Andric ConstraintManager &CM = Mgr.getConstraintManager();
1098bab175ecSDimitry Andric SVal V = getArgSVal(Call, getArgNo());
1099bab175ecSDimitry Andric
1100bab175ecSDimitry Andric if (auto N = V.getAs<NonLoc>()) {
11017fa27ce4SDimitry Andric if (const llvm::APSInt *Int = N->getAsInteger()) {
11027fa27ce4SDimitry Andric Out << "is ";
11037fa27ce4SDimitry Andric Out << *Int;
11047fa27ce4SDimitry Andric return true;
1105bab175ecSDimitry Andric }
1106cfca06d7SDimitry Andric QualType T = Summary.getArgType(getArgNo());
11077fa27ce4SDimitry Andric SmallString<128> MoreInfo;
11087fa27ce4SDimitry Andric llvm::raw_svector_ostream MoreInfoOs(MoreInfo);
11097fa27ce4SDimitry Andric auto ApplyF = [&](const llvm::APSInt &Min, const llvm::APSInt &Max) {
11107fa27ce4SDimitry Andric if (CM.assumeInclusiveRange(State, *N, Min, Max, true)) {
11117fa27ce4SDimitry Andric if (NRanges > 0)
11127fa27ce4SDimitry Andric MoreInfoOs << " or ";
11137fa27ce4SDimitry Andric appendInsideRangeDesc(Min, Max, T, BVF, MoreInfoOs);
11147fa27ce4SDimitry Andric ++NRanges;
11157fa27ce4SDimitry Andric } else {
11167fa27ce4SDimitry Andric HaveAllRanges = false;
1117bab175ecSDimitry Andric }
11187fa27ce4SDimitry Andric return true;
11197fa27ce4SDimitry Andric };
1120bab175ecSDimitry Andric
11217fa27ce4SDimitry Andric applyOnRange(Kind, BVF, T, ApplyF);
11227fa27ce4SDimitry Andric assert(NRanges > 0);
11237fa27ce4SDimitry Andric if (!HaveAllRanges || NRanges == 1) {
11247fa27ce4SDimitry Andric Out << "is ";
11257fa27ce4SDimitry Andric Out << MoreInfo;
11267fa27ce4SDimitry Andric return true;
1127bab175ecSDimitry Andric }
1128bab175ecSDimitry Andric }
11297fa27ce4SDimitry Andric return false;
1130bab175ecSDimitry Andric }
1131bab175ecSDimitry Andric
apply(ProgramStateRef State,const CallEvent & Call,const Summary & Summary,CheckerContext & C) const1132cfca06d7SDimitry Andric ProgramStateRef StdLibraryFunctionsChecker::ComparisonConstraint::apply(
1133cfca06d7SDimitry Andric ProgramStateRef State, const CallEvent &Call, const Summary &Summary,
1134cfca06d7SDimitry Andric CheckerContext &C) const {
1135bab175ecSDimitry Andric
1136bab175ecSDimitry Andric ProgramStateManager &Mgr = State->getStateManager();
1137bab175ecSDimitry Andric SValBuilder &SVB = Mgr.getSValBuilder();
1138bab175ecSDimitry Andric QualType CondT = SVB.getConditionType();
1139cfca06d7SDimitry Andric QualType T = Summary.getArgType(getArgNo());
1140bab175ecSDimitry Andric SVal V = getArgSVal(Call, getArgNo());
1141bab175ecSDimitry Andric
1142bab175ecSDimitry Andric BinaryOperator::Opcode Op = getOpcode();
1143cfca06d7SDimitry Andric ArgNo OtherArg = getOtherArgNo();
1144bab175ecSDimitry Andric SVal OtherV = getArgSVal(Call, OtherArg);
1145cfca06d7SDimitry Andric QualType OtherT = Summary.getArgType(OtherArg);
1146bab175ecSDimitry Andric // Note: we avoid integral promotion for comparison.
1147bab175ecSDimitry Andric OtherV = SVB.evalCast(OtherV, T, OtherT);
1148bab175ecSDimitry Andric if (auto CompV = SVB.evalBinOp(State, Op, V, OtherV, CondT)
1149bab175ecSDimitry Andric .getAs<DefinedOrUnknownSVal>())
1150bab175ecSDimitry Andric State = State->assume(*CompV, true);
1151bab175ecSDimitry Andric return State;
1152bab175ecSDimitry Andric }
1153bab175ecSDimitry Andric
apply(ProgramStateRef State,const CallEvent & Call,const Summary & Summary,CheckerContext & C) const11547fa27ce4SDimitry Andric ProgramStateRef StdLibraryFunctionsChecker::NotNullConstraint::apply(
11557fa27ce4SDimitry Andric ProgramStateRef State, const CallEvent &Call, const Summary &Summary,
11567fa27ce4SDimitry Andric CheckerContext &C) const {
11577fa27ce4SDimitry Andric SVal V = getArgSVal(Call, getArgNo());
11587fa27ce4SDimitry Andric if (V.isUndef())
11597fa27ce4SDimitry Andric return State;
11607fa27ce4SDimitry Andric
11617fa27ce4SDimitry Andric DefinedOrUnknownSVal L = V.castAs<DefinedOrUnknownSVal>();
11627fa27ce4SDimitry Andric if (!isa<Loc>(L))
11637fa27ce4SDimitry Andric return State;
11647fa27ce4SDimitry Andric
11657fa27ce4SDimitry Andric return State->assume(L, CannotBeNull);
11667fa27ce4SDimitry Andric }
11677fa27ce4SDimitry Andric
describe(DescriptionKind DK,const CallEvent & Call,ProgramStateRef State,const Summary & Summary,llvm::raw_ostream & Out) const11687fa27ce4SDimitry Andric void StdLibraryFunctionsChecker::NotNullConstraint::describe(
11697fa27ce4SDimitry Andric DescriptionKind DK, const CallEvent &Call, ProgramStateRef State,
11707fa27ce4SDimitry Andric const Summary &Summary, llvm::raw_ostream &Out) const {
11717fa27ce4SDimitry Andric assert(CannotBeNull &&
11727fa27ce4SDimitry Andric "Describe should not be used when the value must be NULL");
11737fa27ce4SDimitry Andric if (DK == Violation)
11747fa27ce4SDimitry Andric Out << "should not be NULL";
11757fa27ce4SDimitry Andric else
11767fa27ce4SDimitry Andric Out << "is not NULL";
11777fa27ce4SDimitry Andric }
11787fa27ce4SDimitry Andric
describeArgumentValue(const CallEvent & Call,ProgramStateRef State,const Summary & Summary,llvm::raw_ostream & Out) const11797fa27ce4SDimitry Andric bool StdLibraryFunctionsChecker::NotNullConstraint::describeArgumentValue(
11807fa27ce4SDimitry Andric const CallEvent &Call, ProgramStateRef State, const Summary &Summary,
11817fa27ce4SDimitry Andric llvm::raw_ostream &Out) const {
11827fa27ce4SDimitry Andric assert(!CannotBeNull && "This function is used when the value is NULL");
11837fa27ce4SDimitry Andric Out << "is NULL";
11847fa27ce4SDimitry Andric return true;
11857fa27ce4SDimitry Andric }
11867fa27ce4SDimitry Andric
apply(ProgramStateRef State,const CallEvent & Call,const Summary & Summary,CheckerContext & C) const11877fa27ce4SDimitry Andric ProgramStateRef StdLibraryFunctionsChecker::NotNullBufferConstraint::apply(
11887fa27ce4SDimitry Andric ProgramStateRef State, const CallEvent &Call, const Summary &Summary,
11897fa27ce4SDimitry Andric CheckerContext &C) const {
11907fa27ce4SDimitry Andric SVal V = getArgSVal(Call, getArgNo());
11917fa27ce4SDimitry Andric if (V.isUndef())
11927fa27ce4SDimitry Andric return State;
11937fa27ce4SDimitry Andric DefinedOrUnknownSVal L = V.castAs<DefinedOrUnknownSVal>();
11947fa27ce4SDimitry Andric if (!isa<Loc>(L))
11957fa27ce4SDimitry Andric return State;
11967fa27ce4SDimitry Andric
11977fa27ce4SDimitry Andric std::optional<DefinedOrUnknownSVal> SizeArg1 =
11987fa27ce4SDimitry Andric getArgSVal(Call, SizeArg1N).getAs<DefinedOrUnknownSVal>();
11997fa27ce4SDimitry Andric std::optional<DefinedOrUnknownSVal> SizeArg2;
12007fa27ce4SDimitry Andric if (SizeArg2N)
12017fa27ce4SDimitry Andric SizeArg2 = getArgSVal(Call, *SizeArg2N).getAs<DefinedOrUnknownSVal>();
12027fa27ce4SDimitry Andric
12037fa27ce4SDimitry Andric auto IsArgZero = [State](std::optional<DefinedOrUnknownSVal> Val) {
12047fa27ce4SDimitry Andric if (!Val)
12057fa27ce4SDimitry Andric return false;
12067fa27ce4SDimitry Andric auto [IsNonNull, IsNull] = State->assume(*Val);
12077fa27ce4SDimitry Andric return IsNull && !IsNonNull;
12087fa27ce4SDimitry Andric };
12097fa27ce4SDimitry Andric
12107fa27ce4SDimitry Andric if (IsArgZero(SizeArg1) || IsArgZero(SizeArg2))
12117fa27ce4SDimitry Andric return State;
12127fa27ce4SDimitry Andric
12137fa27ce4SDimitry Andric return State->assume(L, CannotBeNull);
12147fa27ce4SDimitry Andric }
12157fa27ce4SDimitry Andric
describe(DescriptionKind DK,const CallEvent & Call,ProgramStateRef State,const Summary & Summary,llvm::raw_ostream & Out) const12167fa27ce4SDimitry Andric void StdLibraryFunctionsChecker::NotNullBufferConstraint::describe(
12177fa27ce4SDimitry Andric DescriptionKind DK, const CallEvent &Call, ProgramStateRef State,
12187fa27ce4SDimitry Andric const Summary &Summary, llvm::raw_ostream &Out) const {
12197fa27ce4SDimitry Andric assert(CannotBeNull &&
12207fa27ce4SDimitry Andric "Describe should not be used when the value must be NULL");
12217fa27ce4SDimitry Andric if (DK == Violation)
12227fa27ce4SDimitry Andric Out << "should not be NULL";
12237fa27ce4SDimitry Andric else
12247fa27ce4SDimitry Andric Out << "is not NULL";
12257fa27ce4SDimitry Andric }
12267fa27ce4SDimitry Andric
describeArgumentValue(const CallEvent & Call,ProgramStateRef State,const Summary & Summary,llvm::raw_ostream & Out) const12277fa27ce4SDimitry Andric bool StdLibraryFunctionsChecker::NotNullBufferConstraint::describeArgumentValue(
12287fa27ce4SDimitry Andric const CallEvent &Call, ProgramStateRef State, const Summary &Summary,
12297fa27ce4SDimitry Andric llvm::raw_ostream &Out) const {
12307fa27ce4SDimitry Andric assert(!CannotBeNull && "This function is used when the value is NULL");
12317fa27ce4SDimitry Andric Out << "is NULL";
12327fa27ce4SDimitry Andric return true;
12337fa27ce4SDimitry Andric }
12347fa27ce4SDimitry Andric
apply(ProgramStateRef State,const CallEvent & Call,const Summary & Summary,CheckerContext & C) const12357fa27ce4SDimitry Andric ProgramStateRef StdLibraryFunctionsChecker::BufferSizeConstraint::apply(
12367fa27ce4SDimitry Andric ProgramStateRef State, const CallEvent &Call, const Summary &Summary,
12377fa27ce4SDimitry Andric CheckerContext &C) const {
12387fa27ce4SDimitry Andric SValBuilder &SvalBuilder = C.getSValBuilder();
12397fa27ce4SDimitry Andric // The buffer argument.
12407fa27ce4SDimitry Andric SVal BufV = getArgSVal(Call, getArgNo());
12417fa27ce4SDimitry Andric
12427fa27ce4SDimitry Andric // Get the size constraint.
12437fa27ce4SDimitry Andric const SVal SizeV = [this, &State, &Call, &Summary, &SvalBuilder]() {
12447fa27ce4SDimitry Andric if (ConcreteSize) {
12457fa27ce4SDimitry Andric return SVal(SvalBuilder.makeIntVal(*ConcreteSize));
12467fa27ce4SDimitry Andric }
12477fa27ce4SDimitry Andric assert(SizeArgN && "The constraint must be either a concrete value or "
12487fa27ce4SDimitry Andric "encoded in an argument.");
12497fa27ce4SDimitry Andric // The size argument.
12507fa27ce4SDimitry Andric SVal SizeV = getArgSVal(Call, *SizeArgN);
12517fa27ce4SDimitry Andric // Multiply with another argument if given.
12527fa27ce4SDimitry Andric if (SizeMultiplierArgN) {
12537fa27ce4SDimitry Andric SVal SizeMulV = getArgSVal(Call, *SizeMultiplierArgN);
12547fa27ce4SDimitry Andric SizeV = SvalBuilder.evalBinOp(State, BO_Mul, SizeV, SizeMulV,
12557fa27ce4SDimitry Andric Summary.getArgType(*SizeArgN));
12567fa27ce4SDimitry Andric }
12577fa27ce4SDimitry Andric return SizeV;
12587fa27ce4SDimitry Andric }();
12597fa27ce4SDimitry Andric
12607fa27ce4SDimitry Andric // The dynamic size of the buffer argument, got from the analyzer engine.
12617fa27ce4SDimitry Andric SVal BufDynSize = getDynamicExtentWithOffset(State, BufV);
12627fa27ce4SDimitry Andric
12637fa27ce4SDimitry Andric SVal Feasible = SvalBuilder.evalBinOp(State, Op, SizeV, BufDynSize,
12647fa27ce4SDimitry Andric SvalBuilder.getContext().BoolTy);
12657fa27ce4SDimitry Andric if (auto F = Feasible.getAs<DefinedOrUnknownSVal>())
12667fa27ce4SDimitry Andric return State->assume(*F, true);
12677fa27ce4SDimitry Andric
12687fa27ce4SDimitry Andric // We can get here only if the size argument or the dynamic size is
12697fa27ce4SDimitry Andric // undefined. But the dynamic size should never be undefined, only
12707fa27ce4SDimitry Andric // unknown. So, here, the size of the argument is undefined, i.e. we
12717fa27ce4SDimitry Andric // cannot apply the constraint. Actually, other checkers like
12727fa27ce4SDimitry Andric // CallAndMessage should catch this situation earlier, because we call a
12737fa27ce4SDimitry Andric // function with an uninitialized argument.
12747fa27ce4SDimitry Andric llvm_unreachable("Size argument or the dynamic size is Undefined");
12757fa27ce4SDimitry Andric }
12767fa27ce4SDimitry Andric
describe(DescriptionKind DK,const CallEvent & Call,ProgramStateRef State,const Summary & Summary,llvm::raw_ostream & Out) const12777fa27ce4SDimitry Andric void StdLibraryFunctionsChecker::BufferSizeConstraint::describe(
12787fa27ce4SDimitry Andric DescriptionKind DK, const CallEvent &Call, ProgramStateRef State,
12797fa27ce4SDimitry Andric const Summary &Summary, llvm::raw_ostream &Out) const {
12807fa27ce4SDimitry Andric Out << ((DK == Violation) ? "should be " : "is ");
12817fa27ce4SDimitry Andric Out << "a buffer with size equal to or greater than ";
12827fa27ce4SDimitry Andric if (ConcreteSize) {
12837fa27ce4SDimitry Andric Out << *ConcreteSize;
12847fa27ce4SDimitry Andric } else if (SizeArgN) {
12857fa27ce4SDimitry Andric Out << "the value of the ";
12867fa27ce4SDimitry Andric printArgDesc(*SizeArgN, Out);
12877fa27ce4SDimitry Andric printArgValueInfo(*SizeArgN, State, Call, Out);
12887fa27ce4SDimitry Andric if (SizeMultiplierArgN) {
12897fa27ce4SDimitry Andric Out << " times the ";
12907fa27ce4SDimitry Andric printArgDesc(*SizeMultiplierArgN, Out);
12917fa27ce4SDimitry Andric printArgValueInfo(*SizeMultiplierArgN, State, Call, Out);
12927fa27ce4SDimitry Andric }
12937fa27ce4SDimitry Andric }
12947fa27ce4SDimitry Andric }
12957fa27ce4SDimitry Andric
describeArgumentValue(const CallEvent & Call,ProgramStateRef State,const Summary & Summary,llvm::raw_ostream & Out) const12967fa27ce4SDimitry Andric bool StdLibraryFunctionsChecker::BufferSizeConstraint::describeArgumentValue(
12977fa27ce4SDimitry Andric const CallEvent &Call, ProgramStateRef State, const Summary &Summary,
12987fa27ce4SDimitry Andric llvm::raw_ostream &Out) const {
12997fa27ce4SDimitry Andric SVal BufV = getArgSVal(Call, getArgNo());
13007fa27ce4SDimitry Andric SVal BufDynSize = getDynamicExtentWithOffset(State, BufV);
13017fa27ce4SDimitry Andric if (const llvm::APSInt *Val =
13027fa27ce4SDimitry Andric State->getStateManager().getSValBuilder().getKnownValue(State,
13037fa27ce4SDimitry Andric BufDynSize)) {
13047fa27ce4SDimitry Andric Out << "is a buffer with size " << *Val;
13057fa27ce4SDimitry Andric return true;
13067fa27ce4SDimitry Andric }
13077fa27ce4SDimitry Andric return false;
13087fa27ce4SDimitry Andric }
13097fa27ce4SDimitry Andric
checkPreCall(const CallEvent & Call,CheckerContext & C) const1310cfca06d7SDimitry Andric void StdLibraryFunctionsChecker::checkPreCall(const CallEvent &Call,
1311bab175ecSDimitry Andric CheckerContext &C) const {
1312e3b55780SDimitry Andric std::optional<Summary> FoundSummary = findFunctionSummary(Call, C);
1313bab175ecSDimitry Andric if (!FoundSummary)
1314bab175ecSDimitry Andric return;
1315bab175ecSDimitry Andric
1316cfca06d7SDimitry Andric const Summary &Summary = *FoundSummary;
1317bab175ecSDimitry Andric ProgramStateRef State = C.getState();
1318bab175ecSDimitry Andric
1319bab175ecSDimitry Andric ProgramStateRef NewState = State;
1320e3b55780SDimitry Andric ExplodedNode *NewNode = C.getPredecessor();
1321cfca06d7SDimitry Andric for (const ValueConstraintPtr &Constraint : Summary.getArgConstraints()) {
13227fa27ce4SDimitry Andric ValueConstraintPtr NegatedConstraint = Constraint->negate();
1323cfca06d7SDimitry Andric ProgramStateRef SuccessSt = Constraint->apply(NewState, Call, Summary, C);
1324cfca06d7SDimitry Andric ProgramStateRef FailureSt =
13257fa27ce4SDimitry Andric NegatedConstraint->apply(NewState, Call, Summary, C);
1326cfca06d7SDimitry Andric // The argument constraint is not satisfied.
1327cfca06d7SDimitry Andric if (FailureSt && !SuccessSt) {
13287fa27ce4SDimitry Andric if (ExplodedNode *N = C.generateErrorNode(State, NewNode))
13297fa27ce4SDimitry Andric reportBug(Call, N, Constraint.get(), NegatedConstraint.get(), Summary,
13307fa27ce4SDimitry Andric C);
1331cfca06d7SDimitry Andric break;
1332e3b55780SDimitry Andric }
1333cfca06d7SDimitry Andric // We will apply the constraint even if we cannot reason about the
1334cfca06d7SDimitry Andric // argument. This means both SuccessSt and FailureSt can be true. If we
1335cfca06d7SDimitry Andric // weren't applying the constraint that would mean that symbolic
1336cfca06d7SDimitry Andric // execution continues on a code whose behaviour is undefined.
1337cfca06d7SDimitry Andric assert(SuccessSt);
1338cfca06d7SDimitry Andric NewState = SuccessSt;
1339e3b55780SDimitry Andric if (NewState != State) {
13407fa27ce4SDimitry Andric SmallString<128> Msg;
13417fa27ce4SDimitry Andric llvm::raw_svector_ostream Os(Msg);
13427fa27ce4SDimitry Andric Os << "Assuming that the ";
13437fa27ce4SDimitry Andric printArgDesc(Constraint->getArgNo(), Os);
13447fa27ce4SDimitry Andric Os << " to '";
13457fa27ce4SDimitry Andric Os << getFunctionName(Call);
13467fa27ce4SDimitry Andric Os << "' ";
13477fa27ce4SDimitry Andric Constraint->describe(ValueConstraint::Assumption, Call, NewState, Summary,
13487fa27ce4SDimitry Andric Os);
1349e3b55780SDimitry Andric const auto ArgSVal = Call.getArgSVal(Constraint->getArgNo());
1350e3b55780SDimitry Andric NewNode = C.addTransition(
1351e3b55780SDimitry Andric NewState, NewNode,
1352e3b55780SDimitry Andric C.getNoteTag([Msg = std::move(Msg), ArgSVal](
1353e3b55780SDimitry Andric PathSensitiveBugReport &BR, llvm::raw_ostream &OS) {
1354e3b55780SDimitry Andric if (BR.isInteresting(ArgSVal))
1355e3b55780SDimitry Andric OS << Msg;
1356e3b55780SDimitry Andric }));
1357cfca06d7SDimitry Andric }
1358cfca06d7SDimitry Andric }
1359cfca06d7SDimitry Andric }
1360cfca06d7SDimitry Andric
checkPostCall(const CallEvent & Call,CheckerContext & C) const1361cfca06d7SDimitry Andric void StdLibraryFunctionsChecker::checkPostCall(const CallEvent &Call,
1362cfca06d7SDimitry Andric CheckerContext &C) const {
1363e3b55780SDimitry Andric std::optional<Summary> FoundSummary = findFunctionSummary(Call, C);
1364cfca06d7SDimitry Andric if (!FoundSummary)
1365cfca06d7SDimitry Andric return;
1366cfca06d7SDimitry Andric
1367cfca06d7SDimitry Andric // Now apply the constraints.
1368cfca06d7SDimitry Andric const Summary &Summary = *FoundSummary;
1369cfca06d7SDimitry Andric ProgramStateRef State = C.getState();
13707fa27ce4SDimitry Andric ExplodedNode *Node = C.getPredecessor();
1371cfca06d7SDimitry Andric
1372cfca06d7SDimitry Andric // Apply case/branch specifications.
1373145449b1SDimitry Andric for (const SummaryCase &Case : Summary.getCases()) {
1374cfca06d7SDimitry Andric ProgramStateRef NewState = State;
1375145449b1SDimitry Andric for (const ValueConstraintPtr &Constraint : Case.getConstraints()) {
1376cfca06d7SDimitry Andric NewState = Constraint->apply(NewState, Call, Summary, C);
1377bab175ecSDimitry Andric if (!NewState)
1378bab175ecSDimitry Andric break;
1379bab175ecSDimitry Andric }
1380bab175ecSDimitry Andric
1381145449b1SDimitry Andric if (NewState)
1382145449b1SDimitry Andric NewState = Case.getErrnoConstraint().apply(NewState, Call, Summary, C);
1383145449b1SDimitry Andric
13847fa27ce4SDimitry Andric if (!NewState)
13857fa27ce4SDimitry Andric continue;
13867fa27ce4SDimitry Andric
1387b1c73532SDimitry Andric // Here it's possible that NewState == State, e.g. when other checkers
1388b1c73532SDimitry Andric // already applied the same constraints (or stricter ones).
13897fa27ce4SDimitry Andric // Still add these note tags, the other checker should add only its
13907fa27ce4SDimitry Andric // specialized note tags. These general note tags are handled always by
13917fa27ce4SDimitry Andric // StdLibraryFunctionsChecker.
1392b1c73532SDimitry Andric
13937fa27ce4SDimitry Andric ExplodedNode *Pred = Node;
1394b1c73532SDimitry Andric DeclarationName FunctionName =
1395b1c73532SDimitry Andric cast<NamedDecl>(Call.getDecl())->getDeclName();
1396b1c73532SDimitry Andric
1397b1c73532SDimitry Andric std::string ErrnoNote = Case.getErrnoConstraint().describe(C);
1398b1c73532SDimitry Andric std::string CaseNote;
1399b1c73532SDimitry Andric if (Case.getNote().empty()) {
1400b1c73532SDimitry Andric if (!ErrnoNote.empty())
1401b1c73532SDimitry Andric ErrnoNote =
1402b1c73532SDimitry Andric llvm::formatv("After calling '{0}' {1}", FunctionName, ErrnoNote);
1403b1c73532SDimitry Andric } else {
1404b1c73532SDimitry Andric CaseNote = llvm::formatv(Case.getNote().str().c_str(), FunctionName);
1405b1c73532SDimitry Andric }
14067fa27ce4SDimitry Andric const SVal RV = Call.getReturnValue();
1407b1c73532SDimitry Andric
14087fa27ce4SDimitry Andric if (Summary.getInvalidationKd() == EvalCallAsPure) {
1409b1c73532SDimitry Andric // Do not expect that errno is interesting (the "pure" functions do not
1410b1c73532SDimitry Andric // affect it).
1411b1c73532SDimitry Andric if (!CaseNote.empty()) {
1412145449b1SDimitry Andric const NoteTag *Tag = C.getNoteTag(
1413b1c73532SDimitry Andric [Node, CaseNote, RV](PathSensitiveBugReport &BR) -> std::string {
14147fa27ce4SDimitry Andric // Try to omit the note if we know in advance which branch is
14157fa27ce4SDimitry Andric // taken (this means, only one branch exists).
14167fa27ce4SDimitry Andric // This check is performed inside the lambda, after other
14177fa27ce4SDimitry Andric // (or this) checkers had a chance to add other successors.
14187fa27ce4SDimitry Andric // Dereferencing the saved node object is valid because it's part
14197fa27ce4SDimitry Andric // of a bug report call sequence.
14207fa27ce4SDimitry Andric // FIXME: This check is not exact. We may be here after a state
14217fa27ce4SDimitry Andric // split that was performed by another checker (and can not find
14227fa27ce4SDimitry Andric // the successors). This is why this check is only used in the
14237fa27ce4SDimitry Andric // EvalCallAsPure case.
14247fa27ce4SDimitry Andric if (BR.isInteresting(RV) && Node->succ_size() > 1)
1425b1c73532SDimitry Andric return CaseNote;
14267fa27ce4SDimitry Andric return "";
14277fa27ce4SDimitry Andric });
14287fa27ce4SDimitry Andric Pred = C.addTransition(NewState, Pred, Tag);
1429b1c73532SDimitry Andric }
14307fa27ce4SDimitry Andric } else {
1431b1c73532SDimitry Andric if (!CaseNote.empty() || !ErrnoNote.empty()) {
14327fa27ce4SDimitry Andric const NoteTag *Tag =
1433b1c73532SDimitry Andric C.getNoteTag([CaseNote, ErrnoNote,
1434b1c73532SDimitry Andric RV](PathSensitiveBugReport &BR) -> std::string {
1435b1c73532SDimitry Andric // If 'errno' is interesting, show the user a note about the case
1436b1c73532SDimitry Andric // (what happened at the function call) and about how 'errno'
1437b1c73532SDimitry Andric // causes the problem. ErrnoChecker sets the errno (but not RV) to
1438b1c73532SDimitry Andric // interesting.
1439b1c73532SDimitry Andric // If only the return value is interesting, show only the case
1440b1c73532SDimitry Andric // note.
1441b1c73532SDimitry Andric std::optional<Loc> ErrnoLoc =
1442b1c73532SDimitry Andric errno_modeling::getErrnoLoc(BR.getErrorNode()->getState());
1443b1c73532SDimitry Andric bool ErrnoImportant = !ErrnoNote.empty() && ErrnoLoc &&
1444b1c73532SDimitry Andric BR.isInteresting(ErrnoLoc->getAsRegion());
1445b1c73532SDimitry Andric if (ErrnoImportant) {
1446b1c73532SDimitry Andric BR.markNotInteresting(ErrnoLoc->getAsRegion());
1447b1c73532SDimitry Andric if (CaseNote.empty())
1448b1c73532SDimitry Andric return ErrnoNote;
1449b1c73532SDimitry Andric return llvm::formatv("{0}; {1}", CaseNote, ErrnoNote);
1450b1c73532SDimitry Andric } else {
14517fa27ce4SDimitry Andric if (BR.isInteresting(RV))
1452b1c73532SDimitry Andric return CaseNote;
1453b1c73532SDimitry Andric }
14547fa27ce4SDimitry Andric return "";
14557fa27ce4SDimitry Andric });
14567fa27ce4SDimitry Andric Pred = C.addTransition(NewState, Pred, Tag);
1457145449b1SDimitry Andric }
14587fa27ce4SDimitry Andric }
14597fa27ce4SDimitry Andric
1460b1c73532SDimitry Andric // Add the transition if no note tag was added.
14617fa27ce4SDimitry Andric if (Pred == Node && NewState != State)
14627fa27ce4SDimitry Andric C.addTransition(NewState);
1463bab175ecSDimitry Andric }
1464bab175ecSDimitry Andric }
1465bab175ecSDimitry Andric
evalCall(const CallEvent & Call,CheckerContext & C) const146622989816SDimitry Andric bool StdLibraryFunctionsChecker::evalCall(const CallEvent &Call,
1467bab175ecSDimitry Andric CheckerContext &C) const {
1468e3b55780SDimitry Andric std::optional<Summary> FoundSummary = findFunctionSummary(Call, C);
1469bab175ecSDimitry Andric if (!FoundSummary)
1470bab175ecSDimitry Andric return false;
1471bab175ecSDimitry Andric
1472cfca06d7SDimitry Andric const Summary &Summary = *FoundSummary;
1473cfca06d7SDimitry Andric switch (Summary.getInvalidationKd()) {
1474bab175ecSDimitry Andric case EvalCallAsPure: {
1475bab175ecSDimitry Andric ProgramStateRef State = C.getState();
1476bab175ecSDimitry Andric const LocationContext *LC = C.getLocationContext();
1477b60736ecSDimitry Andric const auto *CE = cast<CallExpr>(Call.getOriginExpr());
1478bab175ecSDimitry Andric SVal V = C.getSValBuilder().conjureSymbolVal(
1479bab175ecSDimitry Andric CE, LC, CE->getType().getCanonicalType(), C.blockCount());
1480bab175ecSDimitry Andric State = State->BindExpr(CE, LC, V);
1481145449b1SDimitry Andric
1482bab175ecSDimitry Andric C.addTransition(State);
1483145449b1SDimitry Andric
1484bab175ecSDimitry Andric return true;
1485bab175ecSDimitry Andric }
1486bab175ecSDimitry Andric case NoEvalCall:
1487bab175ecSDimitry Andric // Summary tells us to avoid performing eval::Call. The function is possibly
1488bab175ecSDimitry Andric // evaluated by another checker, or evaluated conservatively.
1489bab175ecSDimitry Andric return false;
1490bab175ecSDimitry Andric }
1491bab175ecSDimitry Andric llvm_unreachable("Unknown invalidation kind!");
1492bab175ecSDimitry Andric }
1493bab175ecSDimitry Andric
matches(const FunctionDecl * FD) const1494cfca06d7SDimitry Andric bool StdLibraryFunctionsChecker::Signature::matches(
1495cfca06d7SDimitry Andric const FunctionDecl *FD) const {
1496b60736ecSDimitry Andric assert(!isInvalid());
1497b60736ecSDimitry Andric // Check the number of arguments.
1498cfca06d7SDimitry Andric if (FD->param_size() != ArgTys.size())
1499bab175ecSDimitry Andric return false;
1500bab175ecSDimitry Andric
1501b60736ecSDimitry Andric // The "restrict" keyword is illegal in C++, however, many libc
1502b60736ecSDimitry Andric // implementations use the "__restrict" compiler intrinsic in functions
1503b60736ecSDimitry Andric // prototypes. The "__restrict" keyword qualifies a type as a restricted type
1504b60736ecSDimitry Andric // even in C++.
1505b60736ecSDimitry Andric // In case of any non-C99 languages, we don't want to match based on the
1506b60736ecSDimitry Andric // restrict qualifier because we cannot know if the given libc implementation
1507b60736ecSDimitry Andric // qualifies the paramter type or not.
1508b60736ecSDimitry Andric auto RemoveRestrict = [&FD](QualType T) {
1509b60736ecSDimitry Andric if (!FD->getASTContext().getLangOpts().C99)
1510b60736ecSDimitry Andric T.removeLocalRestrict();
1511b60736ecSDimitry Andric return T;
1512b60736ecSDimitry Andric };
1513bab175ecSDimitry Andric
1514b60736ecSDimitry Andric // Check the return type.
1515b60736ecSDimitry Andric if (!isIrrelevant(RetTy)) {
1516b60736ecSDimitry Andric QualType FDRetTy = RemoveRestrict(FD->getReturnType().getCanonicalType());
1517b60736ecSDimitry Andric if (RetTy != FDRetTy)
1518b60736ecSDimitry Andric return false;
1519b60736ecSDimitry Andric }
1520b60736ecSDimitry Andric
1521b60736ecSDimitry Andric // Check the argument types.
15227fa27ce4SDimitry Andric for (auto [Idx, ArgTy] : llvm::enumerate(ArgTys)) {
1523cfca06d7SDimitry Andric if (isIrrelevant(ArgTy))
1524bab175ecSDimitry Andric continue;
1525b60736ecSDimitry Andric QualType FDArgTy =
15267fa27ce4SDimitry Andric RemoveRestrict(FD->getParamDecl(Idx)->getType().getCanonicalType());
1527b60736ecSDimitry Andric if (ArgTy != FDArgTy)
1528bab175ecSDimitry Andric return false;
1529bab175ecSDimitry Andric }
1530bab175ecSDimitry Andric
1531bab175ecSDimitry Andric return true;
1532bab175ecSDimitry Andric }
1533bab175ecSDimitry Andric
1534e3b55780SDimitry Andric std::optional<StdLibraryFunctionsChecker::Summary>
findFunctionSummary(const FunctionDecl * FD,CheckerContext & C) const1535bab175ecSDimitry Andric StdLibraryFunctionsChecker::findFunctionSummary(const FunctionDecl *FD,
1536bab175ecSDimitry Andric CheckerContext &C) const {
1537bab175ecSDimitry Andric if (!FD)
1538e3b55780SDimitry Andric return std::nullopt;
1539bab175ecSDimitry Andric
1540cfca06d7SDimitry Andric initFunctionSummaries(C);
1541bab175ecSDimitry Andric
1542cfca06d7SDimitry Andric auto FSMI = FunctionSummaryMap.find(FD->getCanonicalDecl());
1543bab175ecSDimitry Andric if (FSMI == FunctionSummaryMap.end())
1544e3b55780SDimitry Andric return std::nullopt;
1545cfca06d7SDimitry Andric return FSMI->second;
1546cfca06d7SDimitry Andric }
1547bab175ecSDimitry Andric
1548e3b55780SDimitry Andric std::optional<StdLibraryFunctionsChecker::Summary>
findFunctionSummary(const CallEvent & Call,CheckerContext & C) const1549cfca06d7SDimitry Andric StdLibraryFunctionsChecker::findFunctionSummary(const CallEvent &Call,
1550cfca06d7SDimitry Andric CheckerContext &C) const {
1551cfca06d7SDimitry Andric const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
1552cfca06d7SDimitry Andric if (!FD)
1553e3b55780SDimitry Andric return std::nullopt;
1554cfca06d7SDimitry Andric return findFunctionSummary(FD, C);
1555cfca06d7SDimitry Andric }
1556bab175ecSDimitry Andric
initFunctionSummaries(CheckerContext & C) const1557b60736ecSDimitry Andric void StdLibraryFunctionsChecker::initFunctionSummaries(
1558b60736ecSDimitry Andric CheckerContext &C) const {
1559344a3780SDimitry Andric if (SummariesInitialized)
1560b60736ecSDimitry Andric return;
15617fa27ce4SDimitry Andric SummariesInitialized = true;
1562b60736ecSDimitry Andric
1563b60736ecSDimitry Andric SValBuilder &SVB = C.getSValBuilder();
1564b60736ecSDimitry Andric BasicValueFactory &BVF = SVB.getBasicValueFactory();
1565b60736ecSDimitry Andric const ASTContext &ACtx = BVF.getContext();
15667fa27ce4SDimitry Andric Preprocessor &PP = C.getPreprocessor();
1567b60736ecSDimitry Andric
1568b60736ecSDimitry Andric // Helper class to lookup a type by its name.
1569b60736ecSDimitry Andric class LookupType {
1570b60736ecSDimitry Andric const ASTContext &ACtx;
1571b60736ecSDimitry Andric
1572b60736ecSDimitry Andric public:
1573b60736ecSDimitry Andric LookupType(const ASTContext &ACtx) : ACtx(ACtx) {}
1574b60736ecSDimitry Andric
1575b60736ecSDimitry Andric // Find the type. If not found then the optional is not set.
1576e3b55780SDimitry Andric std::optional<QualType> operator()(StringRef Name) {
1577cfca06d7SDimitry Andric IdentifierInfo &II = ACtx.Idents.get(Name);
1578cfca06d7SDimitry Andric auto LookupRes = ACtx.getTranslationUnitDecl()->lookup(&II);
1579344a3780SDimitry Andric if (LookupRes.empty())
1580e3b55780SDimitry Andric return std::nullopt;
1581cfca06d7SDimitry Andric
1582cfca06d7SDimitry Andric // Prioritze typedef declarations.
1583cfca06d7SDimitry Andric // This is needed in case of C struct typedefs. E.g.:
1584cfca06d7SDimitry Andric // typedef struct FILE FILE;
1585b60736ecSDimitry Andric // In this case, we have a RecordDecl 'struct FILE' with the name 'FILE'
1586b60736ecSDimitry Andric // and we have a TypedefDecl with the name 'FILE'.
1587cfca06d7SDimitry Andric for (Decl *D : LookupRes)
1588cfca06d7SDimitry Andric if (auto *TD = dyn_cast<TypedefNameDecl>(D))
1589cfca06d7SDimitry Andric return ACtx.getTypeDeclType(TD).getCanonicalType();
1590cfca06d7SDimitry Andric
1591cfca06d7SDimitry Andric // Find the first TypeDecl.
1592cfca06d7SDimitry Andric // There maybe cases when a function has the same name as a struct.
1593cfca06d7SDimitry Andric // E.g. in POSIX: `struct stat` and the function `stat()`:
1594cfca06d7SDimitry Andric // int stat(const char *restrict path, struct stat *restrict buf);
1595cfca06d7SDimitry Andric for (Decl *D : LookupRes)
1596cfca06d7SDimitry Andric if (auto *TD = dyn_cast<TypeDecl>(D))
1597cfca06d7SDimitry Andric return ACtx.getTypeDeclType(TD).getCanonicalType();
1598e3b55780SDimitry Andric return std::nullopt;
1599bab175ecSDimitry Andric }
1600b60736ecSDimitry Andric } lookupTy(ACtx);
1601bab175ecSDimitry Andric
1602b60736ecSDimitry Andric // Below are auxiliary classes to handle optional types that we get as a
1603b60736ecSDimitry Andric // result of the lookup.
1604b60736ecSDimitry Andric class GetRestrictTy {
1605b60736ecSDimitry Andric const ASTContext &ACtx;
1606bab175ecSDimitry Andric
1607b60736ecSDimitry Andric public:
1608b60736ecSDimitry Andric GetRestrictTy(const ASTContext &ACtx) : ACtx(ACtx) {}
1609b60736ecSDimitry Andric QualType operator()(QualType Ty) {
1610b60736ecSDimitry Andric return ACtx.getLangOpts().C99 ? ACtx.getRestrictType(Ty) : Ty;
1611b60736ecSDimitry Andric }
1612e3b55780SDimitry Andric std::optional<QualType> operator()(std::optional<QualType> Ty) {
1613b60736ecSDimitry Andric if (Ty)
1614b60736ecSDimitry Andric return operator()(*Ty);
1615e3b55780SDimitry Andric return std::nullopt;
1616b60736ecSDimitry Andric }
1617b60736ecSDimitry Andric } getRestrictTy(ACtx);
1618b60736ecSDimitry Andric class GetPointerTy {
1619b60736ecSDimitry Andric const ASTContext &ACtx;
1620b60736ecSDimitry Andric
1621b60736ecSDimitry Andric public:
1622b60736ecSDimitry Andric GetPointerTy(const ASTContext &ACtx) : ACtx(ACtx) {}
1623b60736ecSDimitry Andric QualType operator()(QualType Ty) { return ACtx.getPointerType(Ty); }
1624e3b55780SDimitry Andric std::optional<QualType> operator()(std::optional<QualType> Ty) {
1625b60736ecSDimitry Andric if (Ty)
1626b60736ecSDimitry Andric return operator()(*Ty);
1627e3b55780SDimitry Andric return std::nullopt;
1628b60736ecSDimitry Andric }
1629b60736ecSDimitry Andric } getPointerTy(ACtx);
1630b60736ecSDimitry Andric class {
1631b60736ecSDimitry Andric public:
1632e3b55780SDimitry Andric std::optional<QualType> operator()(std::optional<QualType> Ty) {
1633e3b55780SDimitry Andric return Ty ? std::optional<QualType>(Ty->withConst()) : std::nullopt;
1634b60736ecSDimitry Andric }
1635b60736ecSDimitry Andric QualType operator()(QualType Ty) { return Ty.withConst(); }
1636b60736ecSDimitry Andric } getConstTy;
1637b60736ecSDimitry Andric class GetMaxValue {
1638b60736ecSDimitry Andric BasicValueFactory &BVF;
1639b60736ecSDimitry Andric
1640b60736ecSDimitry Andric public:
1641b60736ecSDimitry Andric GetMaxValue(BasicValueFactory &BVF) : BVF(BVF) {}
1642e3b55780SDimitry Andric std::optional<RangeInt> operator()(QualType Ty) {
1643b60736ecSDimitry Andric return BVF.getMaxValue(Ty).getLimitedValue();
1644b60736ecSDimitry Andric }
1645e3b55780SDimitry Andric std::optional<RangeInt> operator()(std::optional<QualType> Ty) {
1646b60736ecSDimitry Andric if (Ty) {
1647b60736ecSDimitry Andric return operator()(*Ty);
1648b60736ecSDimitry Andric }
1649e3b55780SDimitry Andric return std::nullopt;
1650b60736ecSDimitry Andric }
1651b60736ecSDimitry Andric } getMaxValue(BVF);
1652bab175ecSDimitry Andric
1653bab175ecSDimitry Andric // These types are useful for writing specifications quickly,
1654bab175ecSDimitry Andric // New specifications should probably introduce more types.
1655bab175ecSDimitry Andric // Some types are hard to obtain from the AST, eg. "ssize_t".
1656bab175ecSDimitry Andric // In such cases it should be possible to provide multiple variants
1657bab175ecSDimitry Andric // of function summary for common cases (eg. ssize_t could be int or long
1658bab175ecSDimitry Andric // or long long, so three summary variants would be enough).
1659bab175ecSDimitry Andric // Of course, function variants are also useful for C++ overloads.
1660cfca06d7SDimitry Andric const QualType VoidTy = ACtx.VoidTy;
1661b60736ecSDimitry Andric const QualType CharTy = ACtx.CharTy;
1662b60736ecSDimitry Andric const QualType WCharTy = ACtx.WCharTy;
1663cfca06d7SDimitry Andric const QualType IntTy = ACtx.IntTy;
1664cfca06d7SDimitry Andric const QualType UnsignedIntTy = ACtx.UnsignedIntTy;
1665cfca06d7SDimitry Andric const QualType LongTy = ACtx.LongTy;
1666cfca06d7SDimitry Andric const QualType SizeTy = ACtx.getSizeType();
1667bab175ecSDimitry Andric
1668b60736ecSDimitry Andric const QualType VoidPtrTy = getPointerTy(VoidTy); // void *
1669b60736ecSDimitry Andric const QualType IntPtrTy = getPointerTy(IntTy); // int *
1670cfca06d7SDimitry Andric const QualType UnsignedIntPtrTy =
1671b60736ecSDimitry Andric getPointerTy(UnsignedIntTy); // unsigned int *
1672b60736ecSDimitry Andric const QualType VoidPtrRestrictTy = getRestrictTy(VoidPtrTy);
1673cfca06d7SDimitry Andric const QualType ConstVoidPtrTy =
1674b60736ecSDimitry Andric getPointerTy(getConstTy(VoidTy)); // const void *
1675b60736ecSDimitry Andric const QualType CharPtrTy = getPointerTy(CharTy); // char *
1676b60736ecSDimitry Andric const QualType CharPtrRestrictTy = getRestrictTy(CharPtrTy);
1677cfca06d7SDimitry Andric const QualType ConstCharPtrTy =
1678b60736ecSDimitry Andric getPointerTy(getConstTy(CharTy)); // const char *
1679b60736ecSDimitry Andric const QualType ConstCharPtrRestrictTy = getRestrictTy(ConstCharPtrTy);
1680b60736ecSDimitry Andric const QualType Wchar_tPtrTy = getPointerTy(WCharTy); // wchar_t *
1681cfca06d7SDimitry Andric const QualType ConstWchar_tPtrTy =
1682b60736ecSDimitry Andric getPointerTy(getConstTy(WCharTy)); // const wchar_t *
1683b60736ecSDimitry Andric const QualType ConstVoidPtrRestrictTy = getRestrictTy(ConstVoidPtrTy);
1684b60736ecSDimitry Andric const QualType SizePtrTy = getPointerTy(SizeTy);
1685b60736ecSDimitry Andric const QualType SizePtrRestrictTy = getRestrictTy(SizePtrTy);
1686cfca06d7SDimitry Andric
1687cfca06d7SDimitry Andric const RangeInt IntMax = BVF.getMaxValue(IntTy).getLimitedValue();
1688cfca06d7SDimitry Andric const RangeInt UnsignedIntMax =
1689cfca06d7SDimitry Andric BVF.getMaxValue(UnsignedIntTy).getLimitedValue();
1690cfca06d7SDimitry Andric const RangeInt LongMax = BVF.getMaxValue(LongTy).getLimitedValue();
1691cfca06d7SDimitry Andric const RangeInt SizeMax = BVF.getMaxValue(SizeTy).getLimitedValue();
1692cfca06d7SDimitry Andric
1693cfca06d7SDimitry Andric // Set UCharRangeMax to min of int or uchar maximum value.
1694cfca06d7SDimitry Andric // The C standard states that the arguments of functions like isalpha must
1695cfca06d7SDimitry Andric // be representable as an unsigned char. Their type is 'int', so the max
1696cfca06d7SDimitry Andric // value of the argument should be min(UCharMax, IntMax). This just happen
1697cfca06d7SDimitry Andric // to be true for commonly used and well tested instruction set
1698cfca06d7SDimitry Andric // architectures, but not for others.
1699cfca06d7SDimitry Andric const RangeInt UCharRangeMax =
1700cfca06d7SDimitry Andric std::min(BVF.getMaxValue(ACtx.UnsignedCharTy).getLimitedValue(), IntMax);
1701cfca06d7SDimitry Andric
17027fa27ce4SDimitry Andric // Get platform dependent values of some macros.
17037fa27ce4SDimitry Andric // Try our best to parse this from the Preprocessor, otherwise fallback to a
17047fa27ce4SDimitry Andric // default value (what is found in a library header).
17057fa27ce4SDimitry Andric const auto EOFv = tryExpandAsInteger("EOF", PP).value_or(-1);
17067fa27ce4SDimitry Andric const auto AT_FDCWDv = tryExpandAsInteger("AT_FDCWD", PP).value_or(-100);
1707cfca06d7SDimitry Andric
1708cfca06d7SDimitry Andric // Auxiliary class to aid adding summaries to the summary map.
1709cfca06d7SDimitry Andric struct AddToFunctionSummaryMap {
1710cfca06d7SDimitry Andric const ASTContext &ACtx;
1711cfca06d7SDimitry Andric FunctionSummaryMapType ⤅
1712cfca06d7SDimitry Andric bool DisplayLoadedSummaries;
1713cfca06d7SDimitry Andric AddToFunctionSummaryMap(const ASTContext &ACtx, FunctionSummaryMapType &FSM,
1714cfca06d7SDimitry Andric bool DisplayLoadedSummaries)
1715cfca06d7SDimitry Andric : ACtx(ACtx), Map(FSM), DisplayLoadedSummaries(DisplayLoadedSummaries) {
1716cfca06d7SDimitry Andric }
1717cfca06d7SDimitry Andric
1718cfca06d7SDimitry Andric // Add a summary to a FunctionDecl found by lookup. The lookup is performed
1719cfca06d7SDimitry Andric // by the given Name, and in the global scope. The summary will be attached
1720cfca06d7SDimitry Andric // to the found FunctionDecl only if the signatures match.
1721b60736ecSDimitry Andric //
1722b60736ecSDimitry Andric // Returns true if the summary has been added, false otherwise.
1723b60736ecSDimitry Andric bool operator()(StringRef Name, Signature Sign, Summary Sum) {
1724b60736ecSDimitry Andric if (Sign.isInvalid())
1725b60736ecSDimitry Andric return false;
1726cfca06d7SDimitry Andric IdentifierInfo &II = ACtx.Idents.get(Name);
1727cfca06d7SDimitry Andric auto LookupRes = ACtx.getTranslationUnitDecl()->lookup(&II);
1728344a3780SDimitry Andric if (LookupRes.empty())
1729b60736ecSDimitry Andric return false;
1730cfca06d7SDimitry Andric for (Decl *D : LookupRes) {
1731cfca06d7SDimitry Andric if (auto *FD = dyn_cast<FunctionDecl>(D)) {
1732b60736ecSDimitry Andric if (Sum.matchesAndSet(Sign, FD)) {
1733b60736ecSDimitry Andric auto Res = Map.insert({FD->getCanonicalDecl(), Sum});
1734cfca06d7SDimitry Andric assert(Res.second && "Function already has a summary set!");
1735cfca06d7SDimitry Andric (void)Res;
1736cfca06d7SDimitry Andric if (DisplayLoadedSummaries) {
1737cfca06d7SDimitry Andric llvm::errs() << "Loaded summary for: ";
1738cfca06d7SDimitry Andric FD->print(llvm::errs());
1739cfca06d7SDimitry Andric llvm::errs() << "\n";
1740cfca06d7SDimitry Andric }
1741b60736ecSDimitry Andric return true;
1742cfca06d7SDimitry Andric }
1743cfca06d7SDimitry Andric }
1744cfca06d7SDimitry Andric }
1745b60736ecSDimitry Andric return false;
1746cfca06d7SDimitry Andric }
1747b60736ecSDimitry Andric // Add the same summary for different names with the Signature explicitly
1748b60736ecSDimitry Andric // given.
1749ac9a064cSDimitry Andric void operator()(ArrayRef<StringRef> Names, Signature Sign, Summary Sum) {
1750b60736ecSDimitry Andric for (StringRef Name : Names)
1751b60736ecSDimitry Andric operator()(Name, Sign, Sum);
1752cfca06d7SDimitry Andric }
1753cfca06d7SDimitry Andric } addToFunctionSummaryMap(ACtx, FunctionSummaryMap, DisplayLoadedSummaries);
1754bab175ecSDimitry Andric
1755cfca06d7SDimitry Andric // Below are helpers functions to create the summaries.
17567fa27ce4SDimitry Andric auto ArgumentCondition = [](ArgNo ArgN, RangeKind Kind, IntRangeVector Ranges,
17577fa27ce4SDimitry Andric StringRef Desc = "") {
17587fa27ce4SDimitry Andric return std::make_shared<RangeConstraint>(ArgN, Kind, Ranges, Desc);
1759cfca06d7SDimitry Andric };
1760cfca06d7SDimitry Andric auto BufferSize = [](auto... Args) {
1761cfca06d7SDimitry Andric return std::make_shared<BufferSizeConstraint>(Args...);
1762cfca06d7SDimitry Andric };
1763cfca06d7SDimitry Andric struct {
1764cfca06d7SDimitry Andric auto operator()(RangeKind Kind, IntRangeVector Ranges) {
1765cfca06d7SDimitry Andric return std::make_shared<RangeConstraint>(Ret, Kind, Ranges);
1766cfca06d7SDimitry Andric }
1767cfca06d7SDimitry Andric auto operator()(BinaryOperator::Opcode Op, ArgNo OtherArgN) {
1768cfca06d7SDimitry Andric return std::make_shared<ComparisonConstraint>(Ret, Op, OtherArgN);
1769cfca06d7SDimitry Andric }
1770cfca06d7SDimitry Andric } ReturnValueCondition;
1771b60736ecSDimitry Andric struct {
1772b60736ecSDimitry Andric auto operator()(RangeInt b, RangeInt e) {
1773cfca06d7SDimitry Andric return IntRangeVector{std::pair<RangeInt, RangeInt>{b, e}};
1774b60736ecSDimitry Andric }
1775e3b55780SDimitry Andric auto operator()(RangeInt b, std::optional<RangeInt> e) {
1776b60736ecSDimitry Andric if (e)
1777b60736ecSDimitry Andric return IntRangeVector{std::pair<RangeInt, RangeInt>{b, *e}};
1778b60736ecSDimitry Andric return IntRangeVector{};
1779b60736ecSDimitry Andric }
1780b60736ecSDimitry Andric auto operator()(std::pair<RangeInt, RangeInt> i0,
1781e3b55780SDimitry Andric std::pair<RangeInt, std::optional<RangeInt>> i1) {
1782b60736ecSDimitry Andric if (i1.second)
1783b60736ecSDimitry Andric return IntRangeVector{i0, {i1.first, *(i1.second)}};
1784b60736ecSDimitry Andric return IntRangeVector{i0};
1785b60736ecSDimitry Andric }
1786b60736ecSDimitry Andric } Range;
1787cfca06d7SDimitry Andric auto SingleValue = [](RangeInt v) {
1788cfca06d7SDimitry Andric return IntRangeVector{std::pair<RangeInt, RangeInt>{v, v}};
1789cfca06d7SDimitry Andric };
1790cfca06d7SDimitry Andric auto LessThanOrEq = BO_LE;
1791cfca06d7SDimitry Andric auto NotNull = [&](ArgNo ArgN) {
1792cfca06d7SDimitry Andric return std::make_shared<NotNullConstraint>(ArgN);
1793cfca06d7SDimitry Andric };
1794e3b55780SDimitry Andric auto IsNull = [&](ArgNo ArgN) {
1795e3b55780SDimitry Andric return std::make_shared<NotNullConstraint>(ArgN, false);
1796e3b55780SDimitry Andric };
17977fa27ce4SDimitry Andric auto NotNullBuffer = [&](ArgNo ArgN, ArgNo SizeArg1N, ArgNo SizeArg2N) {
17987fa27ce4SDimitry Andric return std::make_shared<NotNullBufferConstraint>(ArgN, SizeArg1N,
17997fa27ce4SDimitry Andric SizeArg2N);
18007fa27ce4SDimitry Andric };
1801bab175ecSDimitry Andric
1802e3b55780SDimitry Andric std::optional<QualType> FileTy = lookupTy("FILE");
1803e3b55780SDimitry Andric std::optional<QualType> FilePtrTy = getPointerTy(FileTy);
1804e3b55780SDimitry Andric std::optional<QualType> FilePtrRestrictTy = getRestrictTy(FilePtrTy);
1805e3b55780SDimitry Andric
1806e3b55780SDimitry Andric std::optional<QualType> FPosTTy = lookupTy("fpos_t");
1807e3b55780SDimitry Andric std::optional<QualType> FPosTPtrTy = getPointerTy(FPosTTy);
1808e3b55780SDimitry Andric std::optional<QualType> ConstFPosTPtrTy = getPointerTy(getConstTy(FPosTTy));
1809e3b55780SDimitry Andric std::optional<QualType> FPosTPtrRestrictTy = getRestrictTy(FPosTPtrTy);
1810cfca06d7SDimitry Andric
18117fa27ce4SDimitry Andric constexpr llvm::StringLiteral GenericSuccessMsg(
18127fa27ce4SDimitry Andric "Assuming that '{0}' is successful");
18137fa27ce4SDimitry Andric constexpr llvm::StringLiteral GenericFailureMsg("Assuming that '{0}' fails");
18147fa27ce4SDimitry Andric
1815b60736ecSDimitry Andric // We are finally ready to define specifications for all supported functions.
1816b60736ecSDimitry Andric //
1817b60736ecSDimitry Andric // Argument ranges should always cover all variants. If return value
1818b60736ecSDimitry Andric // is completely unknown, omit it from the respective range set.
1819b60736ecSDimitry Andric //
1820b60736ecSDimitry Andric // Every item in the list of range sets represents a particular
1821b60736ecSDimitry Andric // execution path the analyzer would need to explore once
1822b60736ecSDimitry Andric // the call is modeled - a new program state is constructed
1823b60736ecSDimitry Andric // for every range set, and each range line in the range set
1824b60736ecSDimitry Andric // corresponds to a specific constraint within this state.
1825cfca06d7SDimitry Andric
1826bab175ecSDimitry Andric // The isascii() family of functions.
1827cfca06d7SDimitry Andric // The behavior is undefined if the value of the argument is not
1828cfca06d7SDimitry Andric // representable as unsigned char or is not equal to EOF. See e.g. C99
1829cfca06d7SDimitry Andric // 7.4.1.2 The isalpha function (p: 181-182).
1830cfca06d7SDimitry Andric addToFunctionSummaryMap(
1831b60736ecSDimitry Andric "isalnum", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1832b60736ecSDimitry Andric Summary(EvalCallAsPure)
1833cfca06d7SDimitry Andric // Boils down to isupper() or islower() or isdigit().
1834cfca06d7SDimitry Andric .Case({ArgumentCondition(0U, WithinRange,
1835cfca06d7SDimitry Andric {{'0', '9'}, {'A', 'Z'}, {'a', 'z'}}),
1836145449b1SDimitry Andric ReturnValueCondition(OutOfRange, SingleValue(0))},
1837145449b1SDimitry Andric ErrnoIrrelevant, "Assuming the character is alphanumeric")
1838cfca06d7SDimitry Andric // The locale-specific range.
1839bab175ecSDimitry Andric // No post-condition. We are completely unaware of
1840bab175ecSDimitry Andric // locale-specific return values.
1841145449b1SDimitry Andric .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})},
1842145449b1SDimitry Andric ErrnoIrrelevant)
1843cfca06d7SDimitry Andric .Case(
1844cfca06d7SDimitry Andric {ArgumentCondition(
1845cfca06d7SDimitry Andric 0U, OutOfRange,
1846cfca06d7SDimitry Andric {{'0', '9'}, {'A', 'Z'}, {'a', 'z'}, {128, UCharRangeMax}}),
1847145449b1SDimitry Andric ReturnValueCondition(WithinRange, SingleValue(0))},
1848145449b1SDimitry Andric ErrnoIrrelevant, "Assuming the character is non-alphanumeric")
18497fa27ce4SDimitry Andric .ArgConstraint(ArgumentCondition(0U, WithinRange,
18507fa27ce4SDimitry Andric {{EOFv, EOFv}, {0, UCharRangeMax}},
18517fa27ce4SDimitry Andric "an unsigned char value or EOF")));
1852cfca06d7SDimitry Andric addToFunctionSummaryMap(
1853b60736ecSDimitry Andric "isalpha", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1854b60736ecSDimitry Andric Summary(EvalCallAsPure)
1855cfca06d7SDimitry Andric .Case({ArgumentCondition(0U, WithinRange, {{'A', 'Z'}, {'a', 'z'}}),
1856145449b1SDimitry Andric ReturnValueCondition(OutOfRange, SingleValue(0))},
1857145449b1SDimitry Andric ErrnoIrrelevant, "Assuming the character is alphabetical")
1858cfca06d7SDimitry Andric // The locale-specific range.
1859145449b1SDimitry Andric .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})},
1860145449b1SDimitry Andric ErrnoIrrelevant)
1861cfca06d7SDimitry Andric .Case({ArgumentCondition(
1862cfca06d7SDimitry Andric 0U, OutOfRange,
1863cfca06d7SDimitry Andric {{'A', 'Z'}, {'a', 'z'}, {128, UCharRangeMax}}),
1864145449b1SDimitry Andric ReturnValueCondition(WithinRange, SingleValue(0))},
1865145449b1SDimitry Andric ErrnoIrrelevant, "Assuming the character is non-alphabetical"));
1866cfca06d7SDimitry Andric addToFunctionSummaryMap(
1867b60736ecSDimitry Andric "isascii", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1868b60736ecSDimitry Andric Summary(EvalCallAsPure)
1869cfca06d7SDimitry Andric .Case({ArgumentCondition(0U, WithinRange, Range(0, 127)),
1870145449b1SDimitry Andric ReturnValueCondition(OutOfRange, SingleValue(0))},
1871145449b1SDimitry Andric ErrnoIrrelevant, "Assuming the character is an ASCII character")
1872cfca06d7SDimitry Andric .Case({ArgumentCondition(0U, OutOfRange, Range(0, 127)),
1873145449b1SDimitry Andric ReturnValueCondition(WithinRange, SingleValue(0))},
1874145449b1SDimitry Andric ErrnoIrrelevant,
1875145449b1SDimitry Andric "Assuming the character is not an ASCII character"));
1876cfca06d7SDimitry Andric addToFunctionSummaryMap(
1877b60736ecSDimitry Andric "isblank", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1878b60736ecSDimitry Andric Summary(EvalCallAsPure)
1879cfca06d7SDimitry Andric .Case({ArgumentCondition(0U, WithinRange, {{'\t', '\t'}, {' ', ' '}}),
1880145449b1SDimitry Andric ReturnValueCondition(OutOfRange, SingleValue(0))},
1881145449b1SDimitry Andric ErrnoIrrelevant, "Assuming the character is a blank character")
1882cfca06d7SDimitry Andric .Case({ArgumentCondition(0U, OutOfRange, {{'\t', '\t'}, {' ', ' '}}),
1883145449b1SDimitry Andric ReturnValueCondition(WithinRange, SingleValue(0))},
1884145449b1SDimitry Andric ErrnoIrrelevant,
1885145449b1SDimitry Andric "Assuming the character is not a blank character"));
1886cfca06d7SDimitry Andric addToFunctionSummaryMap(
1887b60736ecSDimitry Andric "iscntrl", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1888b60736ecSDimitry Andric Summary(EvalCallAsPure)
1889cfca06d7SDimitry Andric .Case({ArgumentCondition(0U, WithinRange, {{0, 32}, {127, 127}}),
1890145449b1SDimitry Andric ReturnValueCondition(OutOfRange, SingleValue(0))},
1891145449b1SDimitry Andric ErrnoIrrelevant,
1892145449b1SDimitry Andric "Assuming the character is a control character")
1893cfca06d7SDimitry Andric .Case({ArgumentCondition(0U, OutOfRange, {{0, 32}, {127, 127}}),
1894145449b1SDimitry Andric ReturnValueCondition(WithinRange, SingleValue(0))},
1895145449b1SDimitry Andric ErrnoIrrelevant,
1896145449b1SDimitry Andric "Assuming the character is not a control character"));
1897cfca06d7SDimitry Andric addToFunctionSummaryMap(
1898b60736ecSDimitry Andric "isdigit", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1899b60736ecSDimitry Andric Summary(EvalCallAsPure)
1900cfca06d7SDimitry Andric .Case({ArgumentCondition(0U, WithinRange, Range('0', '9')),
1901145449b1SDimitry Andric ReturnValueCondition(OutOfRange, SingleValue(0))},
1902145449b1SDimitry Andric ErrnoIrrelevant, "Assuming the character is a digit")
1903cfca06d7SDimitry Andric .Case({ArgumentCondition(0U, OutOfRange, Range('0', '9')),
1904145449b1SDimitry Andric ReturnValueCondition(WithinRange, SingleValue(0))},
1905145449b1SDimitry Andric ErrnoIrrelevant, "Assuming the character is not a digit"));
1906cfca06d7SDimitry Andric addToFunctionSummaryMap(
1907b60736ecSDimitry Andric "isgraph", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1908b60736ecSDimitry Andric Summary(EvalCallAsPure)
1909cfca06d7SDimitry Andric .Case({ArgumentCondition(0U, WithinRange, Range(33, 126)),
1910145449b1SDimitry Andric ReturnValueCondition(OutOfRange, SingleValue(0))},
1911145449b1SDimitry Andric ErrnoIrrelevant,
1912145449b1SDimitry Andric "Assuming the character has graphical representation")
1913145449b1SDimitry Andric .Case(
1914145449b1SDimitry Andric {ArgumentCondition(0U, OutOfRange, Range(33, 126)),
1915145449b1SDimitry Andric ReturnValueCondition(WithinRange, SingleValue(0))},
1916145449b1SDimitry Andric ErrnoIrrelevant,
1917145449b1SDimitry Andric "Assuming the character does not have graphical representation"));
1918cfca06d7SDimitry Andric addToFunctionSummaryMap(
1919b60736ecSDimitry Andric "islower", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1920b60736ecSDimitry Andric Summary(EvalCallAsPure)
1921cfca06d7SDimitry Andric // Is certainly lowercase.
1922cfca06d7SDimitry Andric .Case({ArgumentCondition(0U, WithinRange, Range('a', 'z')),
1923145449b1SDimitry Andric ReturnValueCondition(OutOfRange, SingleValue(0))},
1924145449b1SDimitry Andric ErrnoIrrelevant, "Assuming the character is a lowercase letter")
1925cfca06d7SDimitry Andric // Is ascii but not lowercase.
1926cfca06d7SDimitry Andric .Case({ArgumentCondition(0U, WithinRange, Range(0, 127)),
1927cfca06d7SDimitry Andric ArgumentCondition(0U, OutOfRange, Range('a', 'z')),
1928145449b1SDimitry Andric ReturnValueCondition(WithinRange, SingleValue(0))},
1929145449b1SDimitry Andric ErrnoIrrelevant,
1930145449b1SDimitry Andric "Assuming the character is not a lowercase letter")
1931cfca06d7SDimitry Andric // The locale-specific range.
1932145449b1SDimitry Andric .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})},
1933145449b1SDimitry Andric ErrnoIrrelevant)
1934cfca06d7SDimitry Andric // Is not an unsigned char.
1935cfca06d7SDimitry Andric .Case({ArgumentCondition(0U, OutOfRange, Range(0, UCharRangeMax)),
1936145449b1SDimitry Andric ReturnValueCondition(WithinRange, SingleValue(0))},
1937145449b1SDimitry Andric ErrnoIrrelevant));
1938cfca06d7SDimitry Andric addToFunctionSummaryMap(
1939b60736ecSDimitry Andric "isprint", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1940b60736ecSDimitry Andric Summary(EvalCallAsPure)
1941cfca06d7SDimitry Andric .Case({ArgumentCondition(0U, WithinRange, Range(32, 126)),
1942145449b1SDimitry Andric ReturnValueCondition(OutOfRange, SingleValue(0))},
1943145449b1SDimitry Andric ErrnoIrrelevant, "Assuming the character is printable")
1944cfca06d7SDimitry Andric .Case({ArgumentCondition(0U, OutOfRange, Range(32, 126)),
1945145449b1SDimitry Andric ReturnValueCondition(WithinRange, SingleValue(0))},
1946145449b1SDimitry Andric ErrnoIrrelevant, "Assuming the character is non-printable"));
1947cfca06d7SDimitry Andric addToFunctionSummaryMap(
1948b60736ecSDimitry Andric "ispunct", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1949b60736ecSDimitry Andric Summary(EvalCallAsPure)
1950cfca06d7SDimitry Andric .Case({ArgumentCondition(
1951cfca06d7SDimitry Andric 0U, WithinRange,
1952cfca06d7SDimitry Andric {{'!', '/'}, {':', '@'}, {'[', '`'}, {'{', '~'}}),
1953145449b1SDimitry Andric ReturnValueCondition(OutOfRange, SingleValue(0))},
1954145449b1SDimitry Andric ErrnoIrrelevant, "Assuming the character is a punctuation mark")
1955cfca06d7SDimitry Andric .Case({ArgumentCondition(
1956cfca06d7SDimitry Andric 0U, OutOfRange,
1957cfca06d7SDimitry Andric {{'!', '/'}, {':', '@'}, {'[', '`'}, {'{', '~'}}),
1958145449b1SDimitry Andric ReturnValueCondition(WithinRange, SingleValue(0))},
1959145449b1SDimitry Andric ErrnoIrrelevant,
1960145449b1SDimitry Andric "Assuming the character is not a punctuation mark"));
1961cfca06d7SDimitry Andric addToFunctionSummaryMap(
1962b60736ecSDimitry Andric "isspace", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1963b60736ecSDimitry Andric Summary(EvalCallAsPure)
1964cfca06d7SDimitry Andric // Space, '\f', '\n', '\r', '\t', '\v'.
1965cfca06d7SDimitry Andric .Case({ArgumentCondition(0U, WithinRange, {{9, 13}, {' ', ' '}}),
1966145449b1SDimitry Andric ReturnValueCondition(OutOfRange, SingleValue(0))},
1967145449b1SDimitry Andric ErrnoIrrelevant,
1968145449b1SDimitry Andric "Assuming the character is a whitespace character")
1969cfca06d7SDimitry Andric // The locale-specific range.
1970145449b1SDimitry Andric .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})},
1971145449b1SDimitry Andric ErrnoIrrelevant)
1972cfca06d7SDimitry Andric .Case({ArgumentCondition(0U, OutOfRange,
1973cfca06d7SDimitry Andric {{9, 13}, {' ', ' '}, {128, UCharRangeMax}}),
1974145449b1SDimitry Andric ReturnValueCondition(WithinRange, SingleValue(0))},
1975145449b1SDimitry Andric ErrnoIrrelevant,
1976145449b1SDimitry Andric "Assuming the character is not a whitespace character"));
1977cfca06d7SDimitry Andric addToFunctionSummaryMap(
1978b60736ecSDimitry Andric "isupper", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1979b60736ecSDimitry Andric Summary(EvalCallAsPure)
1980cfca06d7SDimitry Andric // Is certainly uppercase.
1981cfca06d7SDimitry Andric .Case({ArgumentCondition(0U, WithinRange, Range('A', 'Z')),
1982145449b1SDimitry Andric ReturnValueCondition(OutOfRange, SingleValue(0))},
1983145449b1SDimitry Andric ErrnoIrrelevant,
1984145449b1SDimitry Andric "Assuming the character is an uppercase letter")
1985cfca06d7SDimitry Andric // The locale-specific range.
1986145449b1SDimitry Andric .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})},
1987145449b1SDimitry Andric ErrnoIrrelevant)
1988cfca06d7SDimitry Andric // Other.
1989cfca06d7SDimitry Andric .Case({ArgumentCondition(0U, OutOfRange,
1990cfca06d7SDimitry Andric {{'A', 'Z'}, {128, UCharRangeMax}}),
1991145449b1SDimitry Andric ReturnValueCondition(WithinRange, SingleValue(0))},
1992145449b1SDimitry Andric ErrnoIrrelevant,
1993145449b1SDimitry Andric "Assuming the character is not an uppercase letter"));
1994cfca06d7SDimitry Andric addToFunctionSummaryMap(
1995b60736ecSDimitry Andric "isxdigit", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1996b60736ecSDimitry Andric Summary(EvalCallAsPure)
1997cfca06d7SDimitry Andric .Case({ArgumentCondition(0U, WithinRange,
1998cfca06d7SDimitry Andric {{'0', '9'}, {'A', 'F'}, {'a', 'f'}}),
1999145449b1SDimitry Andric ReturnValueCondition(OutOfRange, SingleValue(0))},
2000145449b1SDimitry Andric ErrnoIrrelevant,
2001145449b1SDimitry Andric "Assuming the character is a hexadecimal digit")
2002cfca06d7SDimitry Andric .Case({ArgumentCondition(0U, OutOfRange,
2003cfca06d7SDimitry Andric {{'0', '9'}, {'A', 'F'}, {'a', 'f'}}),
2004145449b1SDimitry Andric ReturnValueCondition(WithinRange, SingleValue(0))},
2005145449b1SDimitry Andric ErrnoIrrelevant,
2006145449b1SDimitry Andric "Assuming the character is not a hexadecimal digit"));
2007b60736ecSDimitry Andric addToFunctionSummaryMap(
2008b60736ecSDimitry Andric "toupper", Signature(ArgTypes{IntTy}, RetType{IntTy}),
2009b60736ecSDimitry Andric Summary(EvalCallAsPure)
20107fa27ce4SDimitry Andric .ArgConstraint(ArgumentCondition(0U, WithinRange,
20117fa27ce4SDimitry Andric {{EOFv, EOFv}, {0, UCharRangeMax}},
20127fa27ce4SDimitry Andric "an unsigned char value or EOF")));
2013b60736ecSDimitry Andric addToFunctionSummaryMap(
2014b60736ecSDimitry Andric "tolower", Signature(ArgTypes{IntTy}, RetType{IntTy}),
2015b60736ecSDimitry Andric Summary(EvalCallAsPure)
20167fa27ce4SDimitry Andric .ArgConstraint(ArgumentCondition(0U, WithinRange,
20177fa27ce4SDimitry Andric {{EOFv, EOFv}, {0, UCharRangeMax}},
20187fa27ce4SDimitry Andric "an unsigned char value or EOF")));
2019b60736ecSDimitry Andric addToFunctionSummaryMap(
2020b60736ecSDimitry Andric "toascii", Signature(ArgTypes{IntTy}, RetType{IntTy}),
2021b60736ecSDimitry Andric Summary(EvalCallAsPure)
20227fa27ce4SDimitry Andric .ArgConstraint(ArgumentCondition(0U, WithinRange,
20237fa27ce4SDimitry Andric {{EOFv, EOFv}, {0, UCharRangeMax}},
20247fa27ce4SDimitry Andric "an unsigned char value or EOF")));
2025bab175ecSDimitry Andric
2026b60736ecSDimitry Andric addToFunctionSummaryMap(
2027b60736ecSDimitry Andric "getchar", Signature(ArgTypes{}, RetType{IntTy}),
2028b60736ecSDimitry Andric Summary(NoEvalCall)
2029b60736ecSDimitry Andric .Case({ReturnValueCondition(WithinRange,
2030145449b1SDimitry Andric {{EOFv, EOFv}, {0, UCharRangeMax}})},
2031145449b1SDimitry Andric ErrnoIrrelevant));
2032bab175ecSDimitry Andric
2033bab175ecSDimitry Andric // read()-like functions that never return more than buffer size.
2034b60736ecSDimitry Andric auto FreadSummary =
2035b60736ecSDimitry Andric Summary(NoEvalCall)
2036e3b55780SDimitry Andric .Case({ArgumentCondition(1U, WithinRange, Range(1, SizeMax)),
2037e3b55780SDimitry Andric ArgumentCondition(2U, WithinRange, Range(1, SizeMax)),
2038e3b55780SDimitry Andric ReturnValueCondition(BO_LT, ArgNo(2)),
2039145449b1SDimitry Andric ReturnValueCondition(WithinRange, Range(0, SizeMax))},
20407fa27ce4SDimitry Andric ErrnoNEZeroIrrelevant, GenericFailureMsg)
2041e3b55780SDimitry Andric .Case({ArgumentCondition(1U, WithinRange, Range(1, SizeMax)),
2042e3b55780SDimitry Andric ReturnValueCondition(BO_EQ, ArgNo(2)),
2043e3b55780SDimitry Andric ReturnValueCondition(WithinRange, Range(0, SizeMax))},
20447fa27ce4SDimitry Andric ErrnoMustNotBeChecked, GenericSuccessMsg)
2045e3b55780SDimitry Andric .Case({ArgumentCondition(1U, WithinRange, SingleValue(0)),
2046e3b55780SDimitry Andric ReturnValueCondition(WithinRange, SingleValue(0))},
2047b1c73532SDimitry Andric ErrnoMustNotBeChecked,
2048b1c73532SDimitry Andric "Assuming that argument 'size' to '{0}' is 0")
20497fa27ce4SDimitry Andric .ArgConstraint(NotNullBuffer(ArgNo(0), ArgNo(1), ArgNo(2)))
2050b60736ecSDimitry Andric .ArgConstraint(NotNull(ArgNo(3)))
2051b60736ecSDimitry Andric .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1),
2052b60736ecSDimitry Andric /*BufSizeMultiplier=*/ArgNo(2)));
2053cfca06d7SDimitry Andric
2054b60736ecSDimitry Andric // size_t fread(void *restrict ptr, size_t size, size_t nitems,
2055b60736ecSDimitry Andric // FILE *restrict stream);
2056b60736ecSDimitry Andric addToFunctionSummaryMap(
2057b60736ecSDimitry Andric "fread",
2058b60736ecSDimitry Andric Signature(ArgTypes{VoidPtrRestrictTy, SizeTy, SizeTy, FilePtrRestrictTy},
2059b60736ecSDimitry Andric RetType{SizeTy}),
2060b60736ecSDimitry Andric FreadSummary);
2061b60736ecSDimitry Andric // size_t fwrite(const void *restrict ptr, size_t size, size_t nitems,
2062b60736ecSDimitry Andric // FILE *restrict stream);
2063b60736ecSDimitry Andric addToFunctionSummaryMap("fwrite",
2064b60736ecSDimitry Andric Signature(ArgTypes{ConstVoidPtrRestrictTy, SizeTy,
2065b60736ecSDimitry Andric SizeTy, FilePtrRestrictTy},
2066b60736ecSDimitry Andric RetType{SizeTy}),
2067b60736ecSDimitry Andric FreadSummary);
2068b60736ecSDimitry Andric
2069e3b55780SDimitry Andric std::optional<QualType> Ssize_tTy = lookupTy("ssize_t");
2070e3b55780SDimitry Andric std::optional<RangeInt> Ssize_tMax = getMaxValue(Ssize_tTy);
2071b60736ecSDimitry Andric
2072b60736ecSDimitry Andric auto ReadSummary =
2073b60736ecSDimitry Andric Summary(NoEvalCall)
2074b60736ecSDimitry Andric .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)),
2075145449b1SDimitry Andric ReturnValueCondition(WithinRange, Range(-1, Ssize_tMax))},
2076145449b1SDimitry Andric ErrnoIrrelevant);
2077b60736ecSDimitry Andric
2078cfca06d7SDimitry Andric // FIXME these are actually defined by POSIX and not by the C standard, we
2079cfca06d7SDimitry Andric // should handle them together with the rest of the POSIX functions.
2080b60736ecSDimitry Andric // ssize_t read(int fildes, void *buf, size_t nbyte);
2081b60736ecSDimitry Andric addToFunctionSummaryMap(
2082b60736ecSDimitry Andric "read", Signature(ArgTypes{IntTy, VoidPtrTy, SizeTy}, RetType{Ssize_tTy}),
2083b60736ecSDimitry Andric ReadSummary);
2084b60736ecSDimitry Andric // ssize_t write(int fildes, const void *buf, size_t nbyte);
2085b60736ecSDimitry Andric addToFunctionSummaryMap(
2086b60736ecSDimitry Andric "write",
2087b60736ecSDimitry Andric Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTy}, RetType{Ssize_tTy}),
2088b60736ecSDimitry Andric ReadSummary);
2089b60736ecSDimitry Andric
2090b60736ecSDimitry Andric auto GetLineSummary =
2091b60736ecSDimitry Andric Summary(NoEvalCall)
2092b60736ecSDimitry Andric .Case({ReturnValueCondition(WithinRange,
2093145449b1SDimitry Andric Range({-1, -1}, {1, Ssize_tMax}))},
2094145449b1SDimitry Andric ErrnoIrrelevant);
2095b60736ecSDimitry Andric
2096b60736ecSDimitry Andric QualType CharPtrPtrRestrictTy = getRestrictTy(getPointerTy(CharPtrTy));
2097bab175ecSDimitry Andric
2098bab175ecSDimitry Andric // getline()-like functions either fail or read at least the delimiter.
2099cfca06d7SDimitry Andric // FIXME these are actually defined by POSIX and not by the C standard, we
2100cfca06d7SDimitry Andric // should handle them together with the rest of the POSIX functions.
2101b60736ecSDimitry Andric // ssize_t getline(char **restrict lineptr, size_t *restrict n,
2102b60736ecSDimitry Andric // FILE *restrict stream);
2103b60736ecSDimitry Andric addToFunctionSummaryMap(
2104b60736ecSDimitry Andric "getline",
2105b60736ecSDimitry Andric Signature(
2106b60736ecSDimitry Andric ArgTypes{CharPtrPtrRestrictTy, SizePtrRestrictTy, FilePtrRestrictTy},
2107b60736ecSDimitry Andric RetType{Ssize_tTy}),
2108b60736ecSDimitry Andric GetLineSummary);
2109b60736ecSDimitry Andric // ssize_t getdelim(char **restrict lineptr, size_t *restrict n,
2110b60736ecSDimitry Andric // int delimiter, FILE *restrict stream);
2111b60736ecSDimitry Andric addToFunctionSummaryMap(
2112b60736ecSDimitry Andric "getdelim",
2113b60736ecSDimitry Andric Signature(ArgTypes{CharPtrPtrRestrictTy, SizePtrRestrictTy, IntTy,
2114b60736ecSDimitry Andric FilePtrRestrictTy},
2115b60736ecSDimitry Andric RetType{Ssize_tTy}),
2116b60736ecSDimitry Andric GetLineSummary);
2117cfca06d7SDimitry Andric
2118c0981da4SDimitry Andric {
2119145449b1SDimitry Andric Summary GetenvSummary =
2120145449b1SDimitry Andric Summary(NoEvalCall)
2121c0981da4SDimitry Andric .ArgConstraint(NotNull(ArgNo(0)))
2122145449b1SDimitry Andric .Case({NotNull(Ret)}, ErrnoIrrelevant,
2123145449b1SDimitry Andric "Assuming the environment variable exists");
2124c0981da4SDimitry Andric // In untrusted environments the envvar might not exist.
2125c0981da4SDimitry Andric if (!ShouldAssumeControlledEnvironment)
2126145449b1SDimitry Andric GetenvSummary.Case({NotNull(Ret)->negate()}, ErrnoIrrelevant,
2127145449b1SDimitry Andric "Assuming the environment variable does not exist");
2128c0981da4SDimitry Andric
2129c0981da4SDimitry Andric // char *getenv(const char *name);
2130c0981da4SDimitry Andric addToFunctionSummaryMap(
2131c0981da4SDimitry Andric "getenv", Signature(ArgTypes{ConstCharPtrTy}, RetType{CharPtrTy}),
2132c0981da4SDimitry Andric std::move(GetenvSummary));
2133c0981da4SDimitry Andric }
2134c0981da4SDimitry Andric
2135ac9a064cSDimitry Andric if (!ModelPOSIX) {
2136ac9a064cSDimitry Andric // Without POSIX use of 'errno' is not specified (in these cases).
2137ac9a064cSDimitry Andric // Add these functions without 'errno' checks.
2138ac9a064cSDimitry Andric addToFunctionSummaryMap(
2139ac9a064cSDimitry Andric {"getc", "fgetc"}, Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
2140ac9a064cSDimitry Andric Summary(NoEvalCall)
2141ac9a064cSDimitry Andric .Case({ReturnValueCondition(WithinRange,
2142ac9a064cSDimitry Andric {{EOFv, EOFv}, {0, UCharRangeMax}})},
2143ac9a064cSDimitry Andric ErrnoIrrelevant)
2144ac9a064cSDimitry Andric .ArgConstraint(NotNull(ArgNo(0))));
2145ac9a064cSDimitry Andric } else {
2146e3b55780SDimitry Andric const auto ReturnsZeroOrMinusOne =
2147e3b55780SDimitry Andric ConstraintSet{ReturnValueCondition(WithinRange, Range(-1, 0))};
2148e3b55780SDimitry Andric const auto ReturnsZero =
2149e3b55780SDimitry Andric ConstraintSet{ReturnValueCondition(WithinRange, SingleValue(0))};
2150e3b55780SDimitry Andric const auto ReturnsMinusOne =
2151e3b55780SDimitry Andric ConstraintSet{ReturnValueCondition(WithinRange, SingleValue(-1))};
21524df029ccSDimitry Andric const auto ReturnsEOF =
21534df029ccSDimitry Andric ConstraintSet{ReturnValueCondition(WithinRange, SingleValue(EOFv))};
2154e3b55780SDimitry Andric const auto ReturnsNonnegative =
2155e3b55780SDimitry Andric ConstraintSet{ReturnValueCondition(WithinRange, Range(0, IntMax))};
2156e3b55780SDimitry Andric const auto ReturnsNonZero =
2157e3b55780SDimitry Andric ConstraintSet{ReturnValueCondition(OutOfRange, SingleValue(0))};
2158e3b55780SDimitry Andric const auto ReturnsFileDescriptor =
2159e3b55780SDimitry Andric ConstraintSet{ReturnValueCondition(WithinRange, Range(-1, IntMax))};
2160e3b55780SDimitry Andric const auto &ReturnsValidFileDescriptor = ReturnsNonnegative;
2161e3b55780SDimitry Andric
21627fa27ce4SDimitry Andric auto ValidFileDescriptorOrAtFdcwd = [&](ArgNo ArgN) {
21637fa27ce4SDimitry Andric return std::make_shared<RangeConstraint>(
21647fa27ce4SDimitry Andric ArgN, WithinRange, Range({AT_FDCWDv, AT_FDCWDv}, {0, IntMax}),
21657fa27ce4SDimitry Andric "a valid file descriptor or AT_FDCWD");
21667fa27ce4SDimitry Andric };
21677fa27ce4SDimitry Andric
2168e3b55780SDimitry Andric // FILE *fopen(const char *restrict pathname, const char *restrict mode);
2169e3b55780SDimitry Andric addToFunctionSummaryMap(
2170e3b55780SDimitry Andric "fopen",
2171e3b55780SDimitry Andric Signature(ArgTypes{ConstCharPtrRestrictTy, ConstCharPtrRestrictTy},
2172e3b55780SDimitry Andric RetType{FilePtrTy}),
2173e3b55780SDimitry Andric Summary(NoEvalCall)
21747fa27ce4SDimitry Andric .Case({NotNull(Ret)}, ErrnoMustNotBeChecked, GenericSuccessMsg)
21757fa27ce4SDimitry Andric .Case({IsNull(Ret)}, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2176e3b55780SDimitry Andric .ArgConstraint(NotNull(ArgNo(0)))
2177e3b55780SDimitry Andric .ArgConstraint(NotNull(ArgNo(1))));
2178e3b55780SDimitry Andric
21794df029ccSDimitry Andric // FILE *fdopen(int fd, const char *mode);
21804df029ccSDimitry Andric addToFunctionSummaryMap(
21814df029ccSDimitry Andric "fdopen",
21824df029ccSDimitry Andric Signature(ArgTypes{IntTy, ConstCharPtrTy}, RetType{FilePtrTy}),
21834df029ccSDimitry Andric Summary(NoEvalCall)
21844df029ccSDimitry Andric .Case({NotNull(Ret)}, ErrnoMustNotBeChecked, GenericSuccessMsg)
21854df029ccSDimitry Andric .Case({IsNull(Ret)}, ErrnoNEZeroIrrelevant, GenericFailureMsg)
21864df029ccSDimitry Andric .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
21874df029ccSDimitry Andric .ArgConstraint(NotNull(ArgNo(1))));
21884df029ccSDimitry Andric
2189e3b55780SDimitry Andric // FILE *tmpfile(void);
21907fa27ce4SDimitry Andric addToFunctionSummaryMap(
21917fa27ce4SDimitry Andric "tmpfile", Signature(ArgTypes{}, RetType{FilePtrTy}),
2192e3b55780SDimitry Andric Summary(NoEvalCall)
21937fa27ce4SDimitry Andric .Case({NotNull(Ret)}, ErrnoMustNotBeChecked, GenericSuccessMsg)
21947fa27ce4SDimitry Andric .Case({IsNull(Ret)}, ErrnoNEZeroIrrelevant, GenericFailureMsg));
2195e3b55780SDimitry Andric
2196e3b55780SDimitry Andric // FILE *freopen(const char *restrict pathname, const char *restrict mode,
2197e3b55780SDimitry Andric // FILE *restrict stream);
2198e3b55780SDimitry Andric addToFunctionSummaryMap(
2199e3b55780SDimitry Andric "freopen",
2200e3b55780SDimitry Andric Signature(ArgTypes{ConstCharPtrRestrictTy, ConstCharPtrRestrictTy,
2201e3b55780SDimitry Andric FilePtrRestrictTy},
2202e3b55780SDimitry Andric RetType{FilePtrTy}),
2203e3b55780SDimitry Andric Summary(NoEvalCall)
2204e3b55780SDimitry Andric .Case({ReturnValueCondition(BO_EQ, ArgNo(2))},
22057fa27ce4SDimitry Andric ErrnoMustNotBeChecked, GenericSuccessMsg)
22067fa27ce4SDimitry Andric .Case({IsNull(Ret)}, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2207e3b55780SDimitry Andric .ArgConstraint(NotNull(ArgNo(1)))
2208e3b55780SDimitry Andric .ArgConstraint(NotNull(ArgNo(2))));
2209e3b55780SDimitry Andric
2210ac9a064cSDimitry Andric // FILE *popen(const char *command, const char *type);
2211ac9a064cSDimitry Andric addToFunctionSummaryMap(
2212ac9a064cSDimitry Andric "popen",
2213ac9a064cSDimitry Andric Signature(ArgTypes{ConstCharPtrTy, ConstCharPtrTy}, RetType{FilePtrTy}),
2214ac9a064cSDimitry Andric Summary(NoEvalCall)
2215ac9a064cSDimitry Andric .Case({NotNull(Ret)}, ErrnoMustNotBeChecked, GenericSuccessMsg)
2216ac9a064cSDimitry Andric .Case({IsNull(Ret)}, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2217ac9a064cSDimitry Andric .ArgConstraint(NotNull(ArgNo(0)))
2218ac9a064cSDimitry Andric .ArgConstraint(NotNull(ArgNo(1))));
2219ac9a064cSDimitry Andric
2220e3b55780SDimitry Andric // int fclose(FILE *stream);
2221e3b55780SDimitry Andric addToFunctionSummaryMap(
2222e3b55780SDimitry Andric "fclose", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
2223e3b55780SDimitry Andric Summary(NoEvalCall)
22247fa27ce4SDimitry Andric .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
22254df029ccSDimitry Andric .Case(ReturnsEOF, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2226e3b55780SDimitry Andric .ArgConstraint(NotNull(ArgNo(0))));
2227e3b55780SDimitry Andric
2228ac9a064cSDimitry Andric // int pclose(FILE *stream);
2229ac9a064cSDimitry Andric addToFunctionSummaryMap(
2230ac9a064cSDimitry Andric "pclose", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
2231ac9a064cSDimitry Andric Summary(NoEvalCall)
2232ac9a064cSDimitry Andric .Case({ReturnValueCondition(WithinRange, {{0, IntMax}})},
2233ac9a064cSDimitry Andric ErrnoMustNotBeChecked, GenericSuccessMsg)
2234ac9a064cSDimitry Andric .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2235ac9a064cSDimitry Andric .ArgConstraint(NotNull(ArgNo(0))));
2236ac9a064cSDimitry Andric
2237ac9a064cSDimitry Andric std::optional<QualType> Off_tTy = lookupTy("off_t");
2238ac9a064cSDimitry Andric std::optional<RangeInt> Off_tMax = getMaxValue(Off_tTy);
2239ac9a064cSDimitry Andric
2240ac9a064cSDimitry Andric // int fgetc(FILE *stream);
2241ac9a064cSDimitry Andric // 'getc' is the same as 'fgetc' but may be a macro
2242ac9a064cSDimitry Andric addToFunctionSummaryMap(
2243ac9a064cSDimitry Andric {"getc", "fgetc"}, Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
2244ac9a064cSDimitry Andric Summary(NoEvalCall)
2245ac9a064cSDimitry Andric .Case({ReturnValueCondition(WithinRange, {{0, UCharRangeMax}})},
2246ac9a064cSDimitry Andric ErrnoMustNotBeChecked, GenericSuccessMsg)
2247ac9a064cSDimitry Andric .Case({ReturnValueCondition(WithinRange, SingleValue(EOFv))},
2248ac9a064cSDimitry Andric ErrnoIrrelevant, GenericFailureMsg)
2249ac9a064cSDimitry Andric .ArgConstraint(NotNull(ArgNo(0))));
2250ac9a064cSDimitry Andric
2251ac9a064cSDimitry Andric // int fputc(int c, FILE *stream);
2252ac9a064cSDimitry Andric // 'putc' is the same as 'fputc' but may be a macro
2253ac9a064cSDimitry Andric addToFunctionSummaryMap(
2254ac9a064cSDimitry Andric {"putc", "fputc"},
2255ac9a064cSDimitry Andric Signature(ArgTypes{IntTy, FilePtrTy}, RetType{IntTy}),
2256ac9a064cSDimitry Andric Summary(NoEvalCall)
2257ac9a064cSDimitry Andric .Case({ArgumentCondition(0, WithinRange, Range(0, UCharRangeMax)),
2258ac9a064cSDimitry Andric ReturnValueCondition(BO_EQ, ArgNo(0))},
2259ac9a064cSDimitry Andric ErrnoMustNotBeChecked, GenericSuccessMsg)
2260ac9a064cSDimitry Andric .Case({ArgumentCondition(0, OutOfRange, Range(0, UCharRangeMax)),
2261ac9a064cSDimitry Andric ReturnValueCondition(WithinRange, Range(0, UCharRangeMax))},
2262ac9a064cSDimitry Andric ErrnoMustNotBeChecked, GenericSuccessMsg)
2263ac9a064cSDimitry Andric .Case({ReturnValueCondition(WithinRange, SingleValue(EOFv))},
2264ac9a064cSDimitry Andric ErrnoNEZeroIrrelevant, GenericFailureMsg)
2265ac9a064cSDimitry Andric .ArgConstraint(NotNull(ArgNo(1))));
2266ac9a064cSDimitry Andric
2267ac9a064cSDimitry Andric // char *fgets(char *restrict s, int n, FILE *restrict stream);
2268ac9a064cSDimitry Andric addToFunctionSummaryMap(
2269ac9a064cSDimitry Andric "fgets",
2270ac9a064cSDimitry Andric Signature(ArgTypes{CharPtrRestrictTy, IntTy, FilePtrRestrictTy},
2271ac9a064cSDimitry Andric RetType{CharPtrTy}),
2272ac9a064cSDimitry Andric Summary(NoEvalCall)
2273ac9a064cSDimitry Andric .Case({ReturnValueCondition(BO_EQ, ArgNo(0))},
2274ac9a064cSDimitry Andric ErrnoMustNotBeChecked, GenericSuccessMsg)
2275ac9a064cSDimitry Andric .Case({IsNull(Ret)}, ErrnoIrrelevant, GenericFailureMsg)
2276ac9a064cSDimitry Andric .ArgConstraint(NotNull(ArgNo(0)))
2277ac9a064cSDimitry Andric .ArgConstraint(ArgumentCondition(1, WithinRange, Range(0, IntMax)))
2278ac9a064cSDimitry Andric .ArgConstraint(
2279ac9a064cSDimitry Andric BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1)))
2280ac9a064cSDimitry Andric .ArgConstraint(NotNull(ArgNo(2))));
2281ac9a064cSDimitry Andric
2282ac9a064cSDimitry Andric // int fputs(const char *restrict s, FILE *restrict stream);
2283ac9a064cSDimitry Andric addToFunctionSummaryMap(
2284ac9a064cSDimitry Andric "fputs",
2285ac9a064cSDimitry Andric Signature(ArgTypes{ConstCharPtrRestrictTy, FilePtrRestrictTy},
2286ac9a064cSDimitry Andric RetType{IntTy}),
2287ac9a064cSDimitry Andric Summary(NoEvalCall)
2288ac9a064cSDimitry Andric .Case(ReturnsNonnegative, ErrnoMustNotBeChecked, GenericSuccessMsg)
2289ac9a064cSDimitry Andric .Case({ReturnValueCondition(WithinRange, SingleValue(EOFv))},
2290ac9a064cSDimitry Andric ErrnoNEZeroIrrelevant, GenericFailureMsg)
2291ac9a064cSDimitry Andric .ArgConstraint(NotNull(ArgNo(0)))
2292ac9a064cSDimitry Andric .ArgConstraint(NotNull(ArgNo(1))));
2293ac9a064cSDimitry Andric
2294950076cdSDimitry Andric // int ungetc(int c, FILE *stream);
2295950076cdSDimitry Andric addToFunctionSummaryMap(
2296950076cdSDimitry Andric "ungetc", Signature(ArgTypes{IntTy, FilePtrTy}, RetType{IntTy}),
2297950076cdSDimitry Andric Summary(NoEvalCall)
2298950076cdSDimitry Andric .Case({ReturnValueCondition(BO_EQ, ArgNo(0)),
2299950076cdSDimitry Andric ArgumentCondition(0, WithinRange, {{0, UCharRangeMax}})},
2300950076cdSDimitry Andric ErrnoMustNotBeChecked, GenericSuccessMsg)
2301950076cdSDimitry Andric .Case({ReturnValueCondition(WithinRange, SingleValue(EOFv)),
23024df029ccSDimitry Andric ArgumentCondition(0, WithinRange, SingleValue(EOFv))},
2303950076cdSDimitry Andric ErrnoNEZeroIrrelevant,
2304950076cdSDimitry Andric "Assuming that 'ungetc' fails because EOF was passed as "
2305950076cdSDimitry Andric "character")
2306950076cdSDimitry Andric .Case({ReturnValueCondition(WithinRange, SingleValue(EOFv)),
2307950076cdSDimitry Andric ArgumentCondition(0, WithinRange, {{0, UCharRangeMax}})},
2308950076cdSDimitry Andric ErrnoNEZeroIrrelevant, GenericFailureMsg)
2309950076cdSDimitry Andric .ArgConstraint(ArgumentCondition(
2310950076cdSDimitry Andric 0, WithinRange, {{EOFv, EOFv}, {0, UCharRangeMax}}))
2311950076cdSDimitry Andric .ArgConstraint(NotNull(ArgNo(1))));
2312950076cdSDimitry Andric
2313e3b55780SDimitry Andric // int fseek(FILE *stream, long offset, int whence);
2314e3b55780SDimitry Andric // FIXME: It can be possible to get the 'SEEK_' values (like EOFv) and use
2315e3b55780SDimitry Andric // these for condition of arg 2.
2316e3b55780SDimitry Andric // Now the range [0,2] is used (the `SEEK_*` constants are usually 0,1,2).
2317e3b55780SDimitry Andric addToFunctionSummaryMap(
2318e3b55780SDimitry Andric "fseek", Signature(ArgTypes{FilePtrTy, LongTy, IntTy}, RetType{IntTy}),
2319e3b55780SDimitry Andric Summary(NoEvalCall)
23207fa27ce4SDimitry Andric .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
23217fa27ce4SDimitry Andric .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2322e3b55780SDimitry Andric .ArgConstraint(NotNull(ArgNo(0)))
2323e3b55780SDimitry Andric .ArgConstraint(ArgumentCondition(2, WithinRange, {{0, 2}})));
2324e3b55780SDimitry Andric
23254df029ccSDimitry Andric // int fseeko(FILE *stream, off_t offset, int whence);
23264df029ccSDimitry Andric addToFunctionSummaryMap(
23274df029ccSDimitry Andric "fseeko",
23284df029ccSDimitry Andric Signature(ArgTypes{FilePtrTy, Off_tTy, IntTy}, RetType{IntTy}),
23294df029ccSDimitry Andric Summary(NoEvalCall)
23304df029ccSDimitry Andric .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
23314df029ccSDimitry Andric .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
23324df029ccSDimitry Andric .ArgConstraint(NotNull(ArgNo(0)))
23334df029ccSDimitry Andric .ArgConstraint(ArgumentCondition(2, WithinRange, {{0, 2}})));
23344df029ccSDimitry Andric
2335e3b55780SDimitry Andric // int fgetpos(FILE *restrict stream, fpos_t *restrict pos);
2336e3b55780SDimitry Andric // From 'The Open Group Base Specifications Issue 7, 2018 edition':
2337e3b55780SDimitry Andric // "The fgetpos() function shall not change the setting of errno if
2338e3b55780SDimitry Andric // successful."
2339e3b55780SDimitry Andric addToFunctionSummaryMap(
2340e3b55780SDimitry Andric "fgetpos",
2341e3b55780SDimitry Andric Signature(ArgTypes{FilePtrRestrictTy, FPosTPtrRestrictTy},
2342e3b55780SDimitry Andric RetType{IntTy}),
2343e3b55780SDimitry Andric Summary(NoEvalCall)
23447fa27ce4SDimitry Andric .Case(ReturnsZero, ErrnoUnchanged, GenericSuccessMsg)
23457fa27ce4SDimitry Andric .Case(ReturnsNonZero, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2346e3b55780SDimitry Andric .ArgConstraint(NotNull(ArgNo(0)))
2347e3b55780SDimitry Andric .ArgConstraint(NotNull(ArgNo(1))));
2348e3b55780SDimitry Andric
2349e3b55780SDimitry Andric // int fsetpos(FILE *stream, const fpos_t *pos);
2350e3b55780SDimitry Andric // From 'The Open Group Base Specifications Issue 7, 2018 edition':
2351e3b55780SDimitry Andric // "The fsetpos() function shall not change the setting of errno if
2352e3b55780SDimitry Andric // successful."
2353e3b55780SDimitry Andric addToFunctionSummaryMap(
2354e3b55780SDimitry Andric "fsetpos",
2355e3b55780SDimitry Andric Signature(ArgTypes{FilePtrTy, ConstFPosTPtrTy}, RetType{IntTy}),
2356e3b55780SDimitry Andric Summary(NoEvalCall)
23577fa27ce4SDimitry Andric .Case(ReturnsZero, ErrnoUnchanged, GenericSuccessMsg)
23587fa27ce4SDimitry Andric .Case(ReturnsNonZero, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2359e3b55780SDimitry Andric .ArgConstraint(NotNull(ArgNo(0)))
2360e3b55780SDimitry Andric .ArgConstraint(NotNull(ArgNo(1))));
2361e3b55780SDimitry Andric
236277dbea07SDimitry Andric // int fflush(FILE *stream);
236377dbea07SDimitry Andric addToFunctionSummaryMap(
236477dbea07SDimitry Andric "fflush", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
236577dbea07SDimitry Andric Summary(NoEvalCall)
236677dbea07SDimitry Andric .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
23674df029ccSDimitry Andric .Case(ReturnsEOF, ErrnoNEZeroIrrelevant, GenericFailureMsg));
236877dbea07SDimitry Andric
2369e3b55780SDimitry Andric // long ftell(FILE *stream);
2370e3b55780SDimitry Andric // From 'The Open Group Base Specifications Issue 7, 2018 edition':
2371e3b55780SDimitry Andric // "The ftell() function shall not change the setting of errno if
2372e3b55780SDimitry Andric // successful."
2373e3b55780SDimitry Andric addToFunctionSummaryMap(
2374e3b55780SDimitry Andric "ftell", Signature(ArgTypes{FilePtrTy}, RetType{LongTy}),
2375e3b55780SDimitry Andric Summary(NoEvalCall)
2376950076cdSDimitry Andric .Case({ReturnValueCondition(WithinRange, Range(0, LongMax))},
23777fa27ce4SDimitry Andric ErrnoUnchanged, GenericSuccessMsg)
23787fa27ce4SDimitry Andric .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2379e3b55780SDimitry Andric .ArgConstraint(NotNull(ArgNo(0))));
2380e3b55780SDimitry Andric
23814df029ccSDimitry Andric // off_t ftello(FILE *stream);
23824df029ccSDimitry Andric addToFunctionSummaryMap(
23834df029ccSDimitry Andric "ftello", Signature(ArgTypes{FilePtrTy}, RetType{Off_tTy}),
23844df029ccSDimitry Andric Summary(NoEvalCall)
23854df029ccSDimitry Andric .Case({ReturnValueCondition(WithinRange, Range(0, Off_tMax))},
23864df029ccSDimitry Andric ErrnoMustNotBeChecked, GenericSuccessMsg)
23874df029ccSDimitry Andric .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
23884df029ccSDimitry Andric .ArgConstraint(NotNull(ArgNo(0))));
23894df029ccSDimitry Andric
2390e3b55780SDimitry Andric // int fileno(FILE *stream);
2391ac9a064cSDimitry Andric // According to POSIX 'fileno' may fail and set 'errno'.
2392ac9a064cSDimitry Andric // But in Linux it may fail only if the specified file pointer is invalid.
2393ac9a064cSDimitry Andric // At many places 'fileno' is used without check for failure and a failure
2394ac9a064cSDimitry Andric // case here would produce a large amount of likely false positive warnings.
2395ac9a064cSDimitry Andric // To avoid this, we assume here that it does not fail.
2396e3b55780SDimitry Andric addToFunctionSummaryMap(
2397e3b55780SDimitry Andric "fileno", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
2398e3b55780SDimitry Andric Summary(NoEvalCall)
2399ac9a064cSDimitry Andric .Case(ReturnsValidFileDescriptor, ErrnoUnchanged, GenericSuccessMsg)
2400e3b55780SDimitry Andric .ArgConstraint(NotNull(ArgNo(0))));
2401e3b55780SDimitry Andric
2402e3b55780SDimitry Andric // void rewind(FILE *stream);
2403e3b55780SDimitry Andric // This function indicates error only by setting of 'errno'.
2404e3b55780SDimitry Andric addToFunctionSummaryMap("rewind",
2405e3b55780SDimitry Andric Signature(ArgTypes{FilePtrTy}, RetType{VoidTy}),
2406e3b55780SDimitry Andric Summary(NoEvalCall)
2407e3b55780SDimitry Andric .Case({}, ErrnoMustBeChecked)
2408e3b55780SDimitry Andric .ArgConstraint(NotNull(ArgNo(0))));
2409e3b55780SDimitry Andric
2410e3b55780SDimitry Andric // void clearerr(FILE *stream);
2411e3b55780SDimitry Andric addToFunctionSummaryMap(
2412e3b55780SDimitry Andric "clearerr", Signature(ArgTypes{FilePtrTy}, RetType{VoidTy}),
2413e3b55780SDimitry Andric Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2414e3b55780SDimitry Andric
2415e3b55780SDimitry Andric // int feof(FILE *stream);
2416e3b55780SDimitry Andric addToFunctionSummaryMap(
2417e3b55780SDimitry Andric "feof", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
2418e3b55780SDimitry Andric Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2419e3b55780SDimitry Andric
2420e3b55780SDimitry Andric // int ferror(FILE *stream);
2421e3b55780SDimitry Andric addToFunctionSummaryMap(
2422e3b55780SDimitry Andric "ferror", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
2423e3b55780SDimitry Andric Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2424cfca06d7SDimitry Andric
2425cfca06d7SDimitry Andric // long a64l(const char *str64);
2426cfca06d7SDimitry Andric addToFunctionSummaryMap(
2427b60736ecSDimitry Andric "a64l", Signature(ArgTypes{ConstCharPtrTy}, RetType{LongTy}),
2428b60736ecSDimitry Andric Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2429cfca06d7SDimitry Andric
2430cfca06d7SDimitry Andric // char *l64a(long value);
2431b60736ecSDimitry Andric addToFunctionSummaryMap("l64a",
2432b60736ecSDimitry Andric Signature(ArgTypes{LongTy}, RetType{CharPtrTy}),
2433b60736ecSDimitry Andric Summary(NoEvalCall)
2434b60736ecSDimitry Andric .ArgConstraint(ArgumentCondition(
2435b60736ecSDimitry Andric 0, WithinRange, Range(0, LongMax))));
2436b60736ecSDimitry Andric
24377fa27ce4SDimitry Andric // int open(const char *path, int oflag, ...);
24387fa27ce4SDimitry Andric addToFunctionSummaryMap(
24397fa27ce4SDimitry Andric "open", Signature(ArgTypes{ConstCharPtrTy, IntTy}, RetType{IntTy}),
24407fa27ce4SDimitry Andric Summary(NoEvalCall)
24417fa27ce4SDimitry Andric .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked,
24427fa27ce4SDimitry Andric GenericSuccessMsg)
24437fa27ce4SDimitry Andric .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
24447fa27ce4SDimitry Andric .ArgConstraint(NotNull(ArgNo(0))));
24457fa27ce4SDimitry Andric
24467fa27ce4SDimitry Andric // int openat(int fd, const char *path, int oflag, ...);
24477fa27ce4SDimitry Andric addToFunctionSummaryMap(
24487fa27ce4SDimitry Andric "openat",
24497fa27ce4SDimitry Andric Signature(ArgTypes{IntTy, ConstCharPtrTy, IntTy}, RetType{IntTy}),
24507fa27ce4SDimitry Andric Summary(NoEvalCall)
24517fa27ce4SDimitry Andric .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked,
24527fa27ce4SDimitry Andric GenericSuccessMsg)
24537fa27ce4SDimitry Andric .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
24547fa27ce4SDimitry Andric .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
24557fa27ce4SDimitry Andric .ArgConstraint(NotNull(ArgNo(1))));
24567fa27ce4SDimitry Andric
2457cfca06d7SDimitry Andric // int access(const char *pathname, int amode);
2458b60736ecSDimitry Andric addToFunctionSummaryMap(
2459b60736ecSDimitry Andric "access", Signature(ArgTypes{ConstCharPtrTy, IntTy}, RetType{IntTy}),
2460b60736ecSDimitry Andric Summary(NoEvalCall)
24617fa27ce4SDimitry Andric .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
24627fa27ce4SDimitry Andric .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2463cfca06d7SDimitry Andric .ArgConstraint(NotNull(ArgNo(0))));
2464cfca06d7SDimitry Andric
2465cfca06d7SDimitry Andric // int faccessat(int dirfd, const char *pathname, int mode, int flags);
2466cfca06d7SDimitry Andric addToFunctionSummaryMap(
2467b60736ecSDimitry Andric "faccessat",
2468b60736ecSDimitry Andric Signature(ArgTypes{IntTy, ConstCharPtrTy, IntTy, IntTy},
2469b60736ecSDimitry Andric RetType{IntTy}),
2470b60736ecSDimitry Andric Summary(NoEvalCall)
24717fa27ce4SDimitry Andric .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
24727fa27ce4SDimitry Andric .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
24737fa27ce4SDimitry Andric .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2474cfca06d7SDimitry Andric .ArgConstraint(NotNull(ArgNo(1))));
2475cfca06d7SDimitry Andric
2476cfca06d7SDimitry Andric // int dup(int fildes);
2477145449b1SDimitry Andric addToFunctionSummaryMap(
2478145449b1SDimitry Andric "dup", Signature(ArgTypes{IntTy}, RetType{IntTy}),
2479b60736ecSDimitry Andric Summary(NoEvalCall)
24807fa27ce4SDimitry Andric .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked,
24817fa27ce4SDimitry Andric GenericSuccessMsg)
24827fa27ce4SDimitry Andric .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2483145449b1SDimitry Andric .ArgConstraint(
2484145449b1SDimitry Andric ArgumentCondition(0, WithinRange, Range(0, IntMax))));
2485cfca06d7SDimitry Andric
2486cfca06d7SDimitry Andric // int dup2(int fildes1, int filedes2);
2487cfca06d7SDimitry Andric addToFunctionSummaryMap(
2488b60736ecSDimitry Andric "dup2", Signature(ArgTypes{IntTy, IntTy}, RetType{IntTy}),
2489b60736ecSDimitry Andric Summary(NoEvalCall)
24907fa27ce4SDimitry Andric .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked,
24917fa27ce4SDimitry Andric GenericSuccessMsg)
24927fa27ce4SDimitry Andric .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2493cfca06d7SDimitry Andric .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
2494cfca06d7SDimitry Andric .ArgConstraint(
2495cfca06d7SDimitry Andric ArgumentCondition(1, WithinRange, Range(0, IntMax))));
2496cfca06d7SDimitry Andric
2497cfca06d7SDimitry Andric // int fdatasync(int fildes);
24987fa27ce4SDimitry Andric addToFunctionSummaryMap(
24997fa27ce4SDimitry Andric "fdatasync", Signature(ArgTypes{IntTy}, RetType{IntTy}),
2500b60736ecSDimitry Andric Summary(NoEvalCall)
25017fa27ce4SDimitry Andric .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
25027fa27ce4SDimitry Andric .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
25037fa27ce4SDimitry Andric .ArgConstraint(
25047fa27ce4SDimitry Andric ArgumentCondition(0, WithinRange, Range(0, IntMax))));
2505cfca06d7SDimitry Andric
2506cfca06d7SDimitry Andric // int fnmatch(const char *pattern, const char *string, int flags);
2507cfca06d7SDimitry Andric addToFunctionSummaryMap(
2508b60736ecSDimitry Andric "fnmatch",
2509b60736ecSDimitry Andric Signature(ArgTypes{ConstCharPtrTy, ConstCharPtrTy, IntTy},
2510b60736ecSDimitry Andric RetType{IntTy}),
2511145449b1SDimitry Andric Summary(NoEvalCall)
2512cfca06d7SDimitry Andric .ArgConstraint(NotNull(ArgNo(0)))
2513cfca06d7SDimitry Andric .ArgConstraint(NotNull(ArgNo(1))));
2514cfca06d7SDimitry Andric
2515cfca06d7SDimitry Andric // int fsync(int fildes);
25167fa27ce4SDimitry Andric addToFunctionSummaryMap(
25177fa27ce4SDimitry Andric "fsync", Signature(ArgTypes{IntTy}, RetType{IntTy}),
2518b60736ecSDimitry Andric Summary(NoEvalCall)
25197fa27ce4SDimitry Andric .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
25207fa27ce4SDimitry Andric .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
25217fa27ce4SDimitry Andric .ArgConstraint(
25227fa27ce4SDimitry Andric ArgumentCondition(0, WithinRange, Range(0, IntMax))));
2523cfca06d7SDimitry Andric
2524cfca06d7SDimitry Andric // int truncate(const char *path, off_t length);
2525b60736ecSDimitry Andric addToFunctionSummaryMap(
2526b60736ecSDimitry Andric "truncate",
2527b60736ecSDimitry Andric Signature(ArgTypes{ConstCharPtrTy, Off_tTy}, RetType{IntTy}),
2528b60736ecSDimitry Andric Summary(NoEvalCall)
25297fa27ce4SDimitry Andric .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
25307fa27ce4SDimitry Andric .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2531cfca06d7SDimitry Andric .ArgConstraint(NotNull(ArgNo(0))));
2532cfca06d7SDimitry Andric
2533cfca06d7SDimitry Andric // int symlink(const char *oldpath, const char *newpath);
2534b60736ecSDimitry Andric addToFunctionSummaryMap(
2535b60736ecSDimitry Andric "symlink",
2536b60736ecSDimitry Andric Signature(ArgTypes{ConstCharPtrTy, ConstCharPtrTy}, RetType{IntTy}),
2537b60736ecSDimitry Andric Summary(NoEvalCall)
25387fa27ce4SDimitry Andric .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
25397fa27ce4SDimitry Andric .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2540cfca06d7SDimitry Andric .ArgConstraint(NotNull(ArgNo(0)))
2541cfca06d7SDimitry Andric .ArgConstraint(NotNull(ArgNo(1))));
2542cfca06d7SDimitry Andric
2543cfca06d7SDimitry Andric // int symlinkat(const char *oldpath, int newdirfd, const char *newpath);
2544cfca06d7SDimitry Andric addToFunctionSummaryMap(
2545cfca06d7SDimitry Andric "symlinkat",
2546b60736ecSDimitry Andric Signature(ArgTypes{ConstCharPtrTy, IntTy, ConstCharPtrTy},
2547b60736ecSDimitry Andric RetType{IntTy}),
2548b60736ecSDimitry Andric Summary(NoEvalCall)
25497fa27ce4SDimitry Andric .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
25507fa27ce4SDimitry Andric .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2551cfca06d7SDimitry Andric .ArgConstraint(NotNull(ArgNo(0)))
25527fa27ce4SDimitry Andric .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(1)))
2553cfca06d7SDimitry Andric .ArgConstraint(NotNull(ArgNo(2))));
2554cfca06d7SDimitry Andric
2555cfca06d7SDimitry Andric // int lockf(int fd, int cmd, off_t len);
2556cfca06d7SDimitry Andric addToFunctionSummaryMap(
2557b60736ecSDimitry Andric "lockf", Signature(ArgTypes{IntTy, IntTy, Off_tTy}, RetType{IntTy}),
2558b60736ecSDimitry Andric Summary(NoEvalCall)
25597fa27ce4SDimitry Andric .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
25607fa27ce4SDimitry Andric .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2561cfca06d7SDimitry Andric .ArgConstraint(
2562cfca06d7SDimitry Andric ArgumentCondition(0, WithinRange, Range(0, IntMax))));
2563cfca06d7SDimitry Andric
2564e3b55780SDimitry Andric std::optional<QualType> Mode_tTy = lookupTy("mode_t");
2565cfca06d7SDimitry Andric
2566cfca06d7SDimitry Andric // int creat(const char *pathname, mode_t mode);
2567b60736ecSDimitry Andric addToFunctionSummaryMap(
2568b60736ecSDimitry Andric "creat", Signature(ArgTypes{ConstCharPtrTy, Mode_tTy}, RetType{IntTy}),
2569b60736ecSDimitry Andric Summary(NoEvalCall)
25707fa27ce4SDimitry Andric .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked,
25717fa27ce4SDimitry Andric GenericSuccessMsg)
25727fa27ce4SDimitry Andric .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2573cfca06d7SDimitry Andric .ArgConstraint(NotNull(ArgNo(0))));
2574cfca06d7SDimitry Andric
2575cfca06d7SDimitry Andric // unsigned int sleep(unsigned int seconds);
2576cfca06d7SDimitry Andric addToFunctionSummaryMap(
2577b60736ecSDimitry Andric "sleep", Signature(ArgTypes{UnsignedIntTy}, RetType{UnsignedIntTy}),
2578b60736ecSDimitry Andric Summary(NoEvalCall)
2579cfca06d7SDimitry Andric .ArgConstraint(
2580cfca06d7SDimitry Andric ArgumentCondition(0, WithinRange, Range(0, UnsignedIntMax))));
2581cfca06d7SDimitry Andric
2582e3b55780SDimitry Andric std::optional<QualType> DirTy = lookupTy("DIR");
2583e3b55780SDimitry Andric std::optional<QualType> DirPtrTy = getPointerTy(DirTy);
2584cfca06d7SDimitry Andric
2585cfca06d7SDimitry Andric // int dirfd(DIR *dirp);
2586145449b1SDimitry Andric addToFunctionSummaryMap(
2587145449b1SDimitry Andric "dirfd", Signature(ArgTypes{DirPtrTy}, RetType{IntTy}),
2588b60736ecSDimitry Andric Summary(NoEvalCall)
25897fa27ce4SDimitry Andric .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked,
25907fa27ce4SDimitry Andric GenericSuccessMsg)
25917fa27ce4SDimitry Andric .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2592cfca06d7SDimitry Andric .ArgConstraint(NotNull(ArgNo(0))));
2593cfca06d7SDimitry Andric
2594cfca06d7SDimitry Andric // unsigned int alarm(unsigned int seconds);
2595cfca06d7SDimitry Andric addToFunctionSummaryMap(
2596b60736ecSDimitry Andric "alarm", Signature(ArgTypes{UnsignedIntTy}, RetType{UnsignedIntTy}),
2597b60736ecSDimitry Andric Summary(NoEvalCall)
2598cfca06d7SDimitry Andric .ArgConstraint(
2599cfca06d7SDimitry Andric ArgumentCondition(0, WithinRange, Range(0, UnsignedIntMax))));
2600cfca06d7SDimitry Andric
2601cfca06d7SDimitry Andric // int closedir(DIR *dir);
26027fa27ce4SDimitry Andric addToFunctionSummaryMap(
26037fa27ce4SDimitry Andric "closedir", Signature(ArgTypes{DirPtrTy}, RetType{IntTy}),
2604b60736ecSDimitry Andric Summary(NoEvalCall)
26057fa27ce4SDimitry Andric .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
26067fa27ce4SDimitry Andric .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2607cfca06d7SDimitry Andric .ArgConstraint(NotNull(ArgNo(0))));
2608cfca06d7SDimitry Andric
2609cfca06d7SDimitry Andric // char *strdup(const char *s);
2610b60736ecSDimitry Andric addToFunctionSummaryMap(
2611b60736ecSDimitry Andric "strdup", Signature(ArgTypes{ConstCharPtrTy}, RetType{CharPtrTy}),
2612b60736ecSDimitry Andric Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2613cfca06d7SDimitry Andric
2614cfca06d7SDimitry Andric // char *strndup(const char *s, size_t n);
2615cfca06d7SDimitry Andric addToFunctionSummaryMap(
2616b60736ecSDimitry Andric "strndup",
2617b60736ecSDimitry Andric Signature(ArgTypes{ConstCharPtrTy, SizeTy}, RetType{CharPtrTy}),
2618b60736ecSDimitry Andric Summary(NoEvalCall)
2619cfca06d7SDimitry Andric .ArgConstraint(NotNull(ArgNo(0)))
2620b60736ecSDimitry Andric .ArgConstraint(
2621b60736ecSDimitry Andric ArgumentCondition(1, WithinRange, Range(0, SizeMax))));
2622cfca06d7SDimitry Andric
2623cfca06d7SDimitry Andric // wchar_t *wcsdup(const wchar_t *s);
2624b60736ecSDimitry Andric addToFunctionSummaryMap(
2625b60736ecSDimitry Andric "wcsdup", Signature(ArgTypes{ConstWchar_tPtrTy}, RetType{Wchar_tPtrTy}),
2626b60736ecSDimitry Andric Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2627cfca06d7SDimitry Andric
2628cfca06d7SDimitry Andric // int mkstemp(char *template);
2629145449b1SDimitry Andric addToFunctionSummaryMap(
2630145449b1SDimitry Andric "mkstemp", Signature(ArgTypes{CharPtrTy}, RetType{IntTy}),
2631b60736ecSDimitry Andric Summary(NoEvalCall)
26327fa27ce4SDimitry Andric .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked,
26337fa27ce4SDimitry Andric GenericSuccessMsg)
26347fa27ce4SDimitry Andric .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2635cfca06d7SDimitry Andric .ArgConstraint(NotNull(ArgNo(0))));
2636cfca06d7SDimitry Andric
2637cfca06d7SDimitry Andric // char *mkdtemp(char *template);
2638cfca06d7SDimitry Andric addToFunctionSummaryMap(
2639b60736ecSDimitry Andric "mkdtemp", Signature(ArgTypes{CharPtrTy}, RetType{CharPtrTy}),
2640aca2e42cSDimitry Andric Summary(NoEvalCall)
2641aca2e42cSDimitry Andric .Case({ReturnValueCondition(BO_EQ, ArgNo(0))},
2642aca2e42cSDimitry Andric ErrnoMustNotBeChecked, GenericSuccessMsg)
2643aca2e42cSDimitry Andric .Case({IsNull(Ret)}, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2644aca2e42cSDimitry Andric .ArgConstraint(NotNull(ArgNo(0))));
2645cfca06d7SDimitry Andric
2646cfca06d7SDimitry Andric // char *getcwd(char *buf, size_t size);
2647cfca06d7SDimitry Andric addToFunctionSummaryMap(
2648b60736ecSDimitry Andric "getcwd", Signature(ArgTypes{CharPtrTy, SizeTy}, RetType{CharPtrTy}),
2649b60736ecSDimitry Andric Summary(NoEvalCall)
2650aca2e42cSDimitry Andric .Case({ArgumentCondition(1, WithinRange, Range(1, SizeMax)),
2651aca2e42cSDimitry Andric ReturnValueCondition(BO_EQ, ArgNo(0))},
2652aca2e42cSDimitry Andric ErrnoMustNotBeChecked, GenericSuccessMsg)
2653aca2e42cSDimitry Andric .Case({ArgumentCondition(1, WithinRange, SingleValue(0)),
2654aca2e42cSDimitry Andric IsNull(Ret)},
2655aca2e42cSDimitry Andric ErrnoNEZeroIrrelevant, "Assuming that argument 'size' is 0")
2656aca2e42cSDimitry Andric .Case({ArgumentCondition(1, WithinRange, Range(1, SizeMax)),
2657aca2e42cSDimitry Andric IsNull(Ret)},
2658aca2e42cSDimitry Andric ErrnoNEZeroIrrelevant, GenericFailureMsg)
2659aca2e42cSDimitry Andric .ArgConstraint(NotNull(ArgNo(0)))
2660aca2e42cSDimitry Andric .ArgConstraint(
2661aca2e42cSDimitry Andric BufferSize(/*Buffer*/ ArgNo(0), /*BufSize*/ ArgNo(1)))
2662cfca06d7SDimitry Andric .ArgConstraint(
2663cfca06d7SDimitry Andric ArgumentCondition(1, WithinRange, Range(0, SizeMax))));
2664cfca06d7SDimitry Andric
2665cfca06d7SDimitry Andric // int mkdir(const char *pathname, mode_t mode);
2666b60736ecSDimitry Andric addToFunctionSummaryMap(
2667b60736ecSDimitry Andric "mkdir", Signature(ArgTypes{ConstCharPtrTy, Mode_tTy}, RetType{IntTy}),
2668b60736ecSDimitry Andric Summary(NoEvalCall)
26697fa27ce4SDimitry Andric .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
26707fa27ce4SDimitry Andric .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2671cfca06d7SDimitry Andric .ArgConstraint(NotNull(ArgNo(0))));
2672cfca06d7SDimitry Andric
2673cfca06d7SDimitry Andric // int mkdirat(int dirfd, const char *pathname, mode_t mode);
2674cfca06d7SDimitry Andric addToFunctionSummaryMap(
2675b60736ecSDimitry Andric "mkdirat",
2676b60736ecSDimitry Andric Signature(ArgTypes{IntTy, ConstCharPtrTy, Mode_tTy}, RetType{IntTy}),
2677b60736ecSDimitry Andric Summary(NoEvalCall)
26787fa27ce4SDimitry Andric .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
26797fa27ce4SDimitry Andric .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
26807fa27ce4SDimitry Andric .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2681cfca06d7SDimitry Andric .ArgConstraint(NotNull(ArgNo(1))));
2682cfca06d7SDimitry Andric
2683e3b55780SDimitry Andric std::optional<QualType> Dev_tTy = lookupTy("dev_t");
2684cfca06d7SDimitry Andric
2685cfca06d7SDimitry Andric // int mknod(const char *pathname, mode_t mode, dev_t dev);
2686cfca06d7SDimitry Andric addToFunctionSummaryMap(
2687b60736ecSDimitry Andric "mknod",
2688b60736ecSDimitry Andric Signature(ArgTypes{ConstCharPtrTy, Mode_tTy, Dev_tTy}, RetType{IntTy}),
2689b60736ecSDimitry Andric Summary(NoEvalCall)
26907fa27ce4SDimitry Andric .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
26917fa27ce4SDimitry Andric .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2692cfca06d7SDimitry Andric .ArgConstraint(NotNull(ArgNo(0))));
2693cfca06d7SDimitry Andric
2694cfca06d7SDimitry Andric // int mknodat(int dirfd, const char *pathname, mode_t mode, dev_t dev);
2695b60736ecSDimitry Andric addToFunctionSummaryMap(
2696b60736ecSDimitry Andric "mknodat",
2697b60736ecSDimitry Andric Signature(ArgTypes{IntTy, ConstCharPtrTy, Mode_tTy, Dev_tTy},
2698b60736ecSDimitry Andric RetType{IntTy}),
2699b60736ecSDimitry Andric Summary(NoEvalCall)
27007fa27ce4SDimitry Andric .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
27017fa27ce4SDimitry Andric .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
27027fa27ce4SDimitry Andric .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2703cfca06d7SDimitry Andric .ArgConstraint(NotNull(ArgNo(1))));
2704cfca06d7SDimitry Andric
2705cfca06d7SDimitry Andric // int chmod(const char *path, mode_t mode);
2706b60736ecSDimitry Andric addToFunctionSummaryMap(
2707b60736ecSDimitry Andric "chmod", Signature(ArgTypes{ConstCharPtrTy, Mode_tTy}, RetType{IntTy}),
2708b60736ecSDimitry Andric Summary(NoEvalCall)
27097fa27ce4SDimitry Andric .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
27107fa27ce4SDimitry Andric .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2711cfca06d7SDimitry Andric .ArgConstraint(NotNull(ArgNo(0))));
2712cfca06d7SDimitry Andric
2713cfca06d7SDimitry Andric // int fchmodat(int dirfd, const char *pathname, mode_t mode, int flags);
2714cfca06d7SDimitry Andric addToFunctionSummaryMap(
2715b60736ecSDimitry Andric "fchmodat",
2716b60736ecSDimitry Andric Signature(ArgTypes{IntTy, ConstCharPtrTy, Mode_tTy, IntTy},
2717b60736ecSDimitry Andric RetType{IntTy}),
2718b60736ecSDimitry Andric Summary(NoEvalCall)
27197fa27ce4SDimitry Andric .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
27207fa27ce4SDimitry Andric .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
27217fa27ce4SDimitry Andric .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2722cfca06d7SDimitry Andric .ArgConstraint(NotNull(ArgNo(1))));
2723cfca06d7SDimitry Andric
2724cfca06d7SDimitry Andric // int fchmod(int fildes, mode_t mode);
2725cfca06d7SDimitry Andric addToFunctionSummaryMap(
2726b60736ecSDimitry Andric "fchmod", Signature(ArgTypes{IntTy, Mode_tTy}, RetType{IntTy}),
2727b60736ecSDimitry Andric Summary(NoEvalCall)
27287fa27ce4SDimitry Andric .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
27297fa27ce4SDimitry Andric .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2730cfca06d7SDimitry Andric .ArgConstraint(
2731cfca06d7SDimitry Andric ArgumentCondition(0, WithinRange, Range(0, IntMax))));
2732cfca06d7SDimitry Andric
2733e3b55780SDimitry Andric std::optional<QualType> Uid_tTy = lookupTy("uid_t");
2734e3b55780SDimitry Andric std::optional<QualType> Gid_tTy = lookupTy("gid_t");
2735cfca06d7SDimitry Andric
2736cfca06d7SDimitry Andric // int fchownat(int dirfd, const char *pathname, uid_t owner, gid_t group,
2737cfca06d7SDimitry Andric // int flags);
2738cfca06d7SDimitry Andric addToFunctionSummaryMap(
2739cfca06d7SDimitry Andric "fchownat",
2740b60736ecSDimitry Andric Signature(ArgTypes{IntTy, ConstCharPtrTy, Uid_tTy, Gid_tTy, IntTy},
2741b60736ecSDimitry Andric RetType{IntTy}),
2742b60736ecSDimitry Andric Summary(NoEvalCall)
27437fa27ce4SDimitry Andric .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
27447fa27ce4SDimitry Andric .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
27457fa27ce4SDimitry Andric .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2746cfca06d7SDimitry Andric .ArgConstraint(NotNull(ArgNo(1))));
2747cfca06d7SDimitry Andric
2748cfca06d7SDimitry Andric // int chown(const char *path, uid_t owner, gid_t group);
2749cfca06d7SDimitry Andric addToFunctionSummaryMap(
2750b60736ecSDimitry Andric "chown",
2751b60736ecSDimitry Andric Signature(ArgTypes{ConstCharPtrTy, Uid_tTy, Gid_tTy}, RetType{IntTy}),
2752b60736ecSDimitry Andric Summary(NoEvalCall)
27537fa27ce4SDimitry Andric .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
27547fa27ce4SDimitry Andric .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2755cfca06d7SDimitry Andric .ArgConstraint(NotNull(ArgNo(0))));
2756cfca06d7SDimitry Andric
2757cfca06d7SDimitry Andric // int lchown(const char *path, uid_t owner, gid_t group);
2758cfca06d7SDimitry Andric addToFunctionSummaryMap(
2759b60736ecSDimitry Andric "lchown",
2760b60736ecSDimitry Andric Signature(ArgTypes{ConstCharPtrTy, Uid_tTy, Gid_tTy}, RetType{IntTy}),
2761b60736ecSDimitry Andric Summary(NoEvalCall)
27627fa27ce4SDimitry Andric .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
27637fa27ce4SDimitry Andric .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2764cfca06d7SDimitry Andric .ArgConstraint(NotNull(ArgNo(0))));
2765cfca06d7SDimitry Andric
2766cfca06d7SDimitry Andric // int fchown(int fildes, uid_t owner, gid_t group);
2767cfca06d7SDimitry Andric addToFunctionSummaryMap(
2768b60736ecSDimitry Andric "fchown", Signature(ArgTypes{IntTy, Uid_tTy, Gid_tTy}, RetType{IntTy}),
2769b60736ecSDimitry Andric Summary(NoEvalCall)
27707fa27ce4SDimitry Andric .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
27717fa27ce4SDimitry Andric .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2772b60736ecSDimitry Andric .ArgConstraint(
2773b60736ecSDimitry Andric ArgumentCondition(0, WithinRange, Range(0, IntMax))));
2774cfca06d7SDimitry Andric
2775cfca06d7SDimitry Andric // int rmdir(const char *pathname);
27767fa27ce4SDimitry Andric addToFunctionSummaryMap(
27777fa27ce4SDimitry Andric "rmdir", Signature(ArgTypes{ConstCharPtrTy}, RetType{IntTy}),
2778b60736ecSDimitry Andric Summary(NoEvalCall)
27797fa27ce4SDimitry Andric .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
27807fa27ce4SDimitry Andric .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2781cfca06d7SDimitry Andric .ArgConstraint(NotNull(ArgNo(0))));
2782cfca06d7SDimitry Andric
2783cfca06d7SDimitry Andric // int chdir(const char *path);
27847fa27ce4SDimitry Andric addToFunctionSummaryMap(
27857fa27ce4SDimitry Andric "chdir", Signature(ArgTypes{ConstCharPtrTy}, RetType{IntTy}),
2786b60736ecSDimitry Andric Summary(NoEvalCall)
27877fa27ce4SDimitry Andric .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
27887fa27ce4SDimitry Andric .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2789cfca06d7SDimitry Andric .ArgConstraint(NotNull(ArgNo(0))));
2790cfca06d7SDimitry Andric
2791cfca06d7SDimitry Andric // int link(const char *oldpath, const char *newpath);
2792b60736ecSDimitry Andric addToFunctionSummaryMap(
2793b60736ecSDimitry Andric "link",
2794b60736ecSDimitry Andric Signature(ArgTypes{ConstCharPtrTy, ConstCharPtrTy}, RetType{IntTy}),
2795b60736ecSDimitry Andric Summary(NoEvalCall)
27967fa27ce4SDimitry Andric .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
27977fa27ce4SDimitry Andric .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2798cfca06d7SDimitry Andric .ArgConstraint(NotNull(ArgNo(0)))
2799cfca06d7SDimitry Andric .ArgConstraint(NotNull(ArgNo(1))));
2800cfca06d7SDimitry Andric
2801cfca06d7SDimitry Andric // int linkat(int fd1, const char *path1, int fd2, const char *path2,
2802cfca06d7SDimitry Andric // int flag);
2803cfca06d7SDimitry Andric addToFunctionSummaryMap(
2804cfca06d7SDimitry Andric "linkat",
2805b60736ecSDimitry Andric Signature(ArgTypes{IntTy, ConstCharPtrTy, IntTy, ConstCharPtrTy, IntTy},
2806b60736ecSDimitry Andric RetType{IntTy}),
2807b60736ecSDimitry Andric Summary(NoEvalCall)
28087fa27ce4SDimitry Andric .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
28097fa27ce4SDimitry Andric .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
28107fa27ce4SDimitry Andric .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2811cfca06d7SDimitry Andric .ArgConstraint(NotNull(ArgNo(1)))
28127fa27ce4SDimitry Andric .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(2)))
2813cfca06d7SDimitry Andric .ArgConstraint(NotNull(ArgNo(3))));
2814cfca06d7SDimitry Andric
2815cfca06d7SDimitry Andric // int unlink(const char *pathname);
28167fa27ce4SDimitry Andric addToFunctionSummaryMap(
28177fa27ce4SDimitry Andric "unlink", Signature(ArgTypes{ConstCharPtrTy}, RetType{IntTy}),
2818b60736ecSDimitry Andric Summary(NoEvalCall)
28197fa27ce4SDimitry Andric .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
28207fa27ce4SDimitry Andric .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2821cfca06d7SDimitry Andric .ArgConstraint(NotNull(ArgNo(0))));
2822cfca06d7SDimitry Andric
2823cfca06d7SDimitry Andric // int unlinkat(int fd, const char *path, int flag);
2824cfca06d7SDimitry Andric addToFunctionSummaryMap(
2825cfca06d7SDimitry Andric "unlinkat",
2826b60736ecSDimitry Andric Signature(ArgTypes{IntTy, ConstCharPtrTy, IntTy}, RetType{IntTy}),
2827b60736ecSDimitry Andric Summary(NoEvalCall)
28287fa27ce4SDimitry Andric .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
28297fa27ce4SDimitry Andric .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
28307fa27ce4SDimitry Andric .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2831cfca06d7SDimitry Andric .ArgConstraint(NotNull(ArgNo(1))));
2832cfca06d7SDimitry Andric
2833e3b55780SDimitry Andric std::optional<QualType> StructStatTy = lookupTy("stat");
2834e3b55780SDimitry Andric std::optional<QualType> StructStatPtrTy = getPointerTy(StructStatTy);
2835e3b55780SDimitry Andric std::optional<QualType> StructStatPtrRestrictTy =
2836e3b55780SDimitry Andric getRestrictTy(StructStatPtrTy);
2837cfca06d7SDimitry Andric
2838cfca06d7SDimitry Andric // int fstat(int fd, struct stat *statbuf);
2839cfca06d7SDimitry Andric addToFunctionSummaryMap(
2840b60736ecSDimitry Andric "fstat", Signature(ArgTypes{IntTy, StructStatPtrTy}, RetType{IntTy}),
2841b60736ecSDimitry Andric Summary(NoEvalCall)
28427fa27ce4SDimitry Andric .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
28437fa27ce4SDimitry Andric .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2844b60736ecSDimitry Andric .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
2845cfca06d7SDimitry Andric .ArgConstraint(NotNull(ArgNo(1))));
2846cfca06d7SDimitry Andric
2847cfca06d7SDimitry Andric // int stat(const char *restrict path, struct stat *restrict buf);
2848cfca06d7SDimitry Andric addToFunctionSummaryMap(
2849cfca06d7SDimitry Andric "stat",
2850b60736ecSDimitry Andric Signature(ArgTypes{ConstCharPtrRestrictTy, StructStatPtrRestrictTy},
2851b60736ecSDimitry Andric RetType{IntTy}),
2852b60736ecSDimitry Andric Summary(NoEvalCall)
28537fa27ce4SDimitry Andric .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
28547fa27ce4SDimitry Andric .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2855cfca06d7SDimitry Andric .ArgConstraint(NotNull(ArgNo(0)))
2856cfca06d7SDimitry Andric .ArgConstraint(NotNull(ArgNo(1))));
2857cfca06d7SDimitry Andric
2858cfca06d7SDimitry Andric // int lstat(const char *restrict path, struct stat *restrict buf);
2859cfca06d7SDimitry Andric addToFunctionSummaryMap(
2860cfca06d7SDimitry Andric "lstat",
2861b60736ecSDimitry Andric Signature(ArgTypes{ConstCharPtrRestrictTy, StructStatPtrRestrictTy},
2862b60736ecSDimitry Andric RetType{IntTy}),
2863b60736ecSDimitry Andric Summary(NoEvalCall)
28647fa27ce4SDimitry Andric .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
28657fa27ce4SDimitry Andric .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2866cfca06d7SDimitry Andric .ArgConstraint(NotNull(ArgNo(0)))
2867cfca06d7SDimitry Andric .ArgConstraint(NotNull(ArgNo(1))));
2868cfca06d7SDimitry Andric
2869cfca06d7SDimitry Andric // int fstatat(int fd, const char *restrict path,
2870cfca06d7SDimitry Andric // struct stat *restrict buf, int flag);
2871cfca06d7SDimitry Andric addToFunctionSummaryMap(
2872b60736ecSDimitry Andric "fstatat",
2873b60736ecSDimitry Andric Signature(ArgTypes{IntTy, ConstCharPtrRestrictTy,
2874b60736ecSDimitry Andric StructStatPtrRestrictTy, IntTy},
2875b60736ecSDimitry Andric RetType{IntTy}),
2876b60736ecSDimitry Andric Summary(NoEvalCall)
28777fa27ce4SDimitry Andric .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
28787fa27ce4SDimitry Andric .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
28797fa27ce4SDimitry Andric .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2880cfca06d7SDimitry Andric .ArgConstraint(NotNull(ArgNo(1)))
2881cfca06d7SDimitry Andric .ArgConstraint(NotNull(ArgNo(2))));
2882cfca06d7SDimitry Andric
2883cfca06d7SDimitry Andric // DIR *opendir(const char *name);
2884b60736ecSDimitry Andric addToFunctionSummaryMap(
2885b60736ecSDimitry Andric "opendir", Signature(ArgTypes{ConstCharPtrTy}, RetType{DirPtrTy}),
28864df029ccSDimitry Andric Summary(NoEvalCall)
28874df029ccSDimitry Andric .Case({NotNull(Ret)}, ErrnoMustNotBeChecked, GenericSuccessMsg)
28884df029ccSDimitry Andric .Case({IsNull(Ret)}, ErrnoNEZeroIrrelevant, GenericFailureMsg)
28894df029ccSDimitry Andric .ArgConstraint(NotNull(ArgNo(0))));
2890cfca06d7SDimitry Andric
2891cfca06d7SDimitry Andric // DIR *fdopendir(int fd);
28924df029ccSDimitry Andric addToFunctionSummaryMap(
28934df029ccSDimitry Andric "fdopendir", Signature(ArgTypes{IntTy}, RetType{DirPtrTy}),
2894b60736ecSDimitry Andric Summary(NoEvalCall)
28954df029ccSDimitry Andric .Case({NotNull(Ret)}, ErrnoMustNotBeChecked, GenericSuccessMsg)
28964df029ccSDimitry Andric .Case({IsNull(Ret)}, ErrnoNEZeroIrrelevant, GenericFailureMsg)
28974df029ccSDimitry Andric .ArgConstraint(
28984df029ccSDimitry Andric ArgumentCondition(0, WithinRange, Range(0, IntMax))));
2899cfca06d7SDimitry Andric
2900cfca06d7SDimitry Andric // int isatty(int fildes);
2901cfca06d7SDimitry Andric addToFunctionSummaryMap(
2902b60736ecSDimitry Andric "isatty", Signature(ArgTypes{IntTy}, RetType{IntTy}),
2903b60736ecSDimitry Andric Summary(NoEvalCall)
2904145449b1SDimitry Andric .Case({ReturnValueCondition(WithinRange, Range(0, 1))},
2905145449b1SDimitry Andric ErrnoIrrelevant)
2906cfca06d7SDimitry Andric .ArgConstraint(
2907cfca06d7SDimitry Andric ArgumentCondition(0, WithinRange, Range(0, IntMax))));
2908cfca06d7SDimitry Andric
2909cfca06d7SDimitry Andric // int close(int fildes);
29107fa27ce4SDimitry Andric addToFunctionSummaryMap(
29117fa27ce4SDimitry Andric "close", Signature(ArgTypes{IntTy}, RetType{IntTy}),
2912b60736ecSDimitry Andric Summary(NoEvalCall)
29137fa27ce4SDimitry Andric .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
29147fa27ce4SDimitry Andric .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
29157fa27ce4SDimitry Andric .ArgConstraint(
29167fa27ce4SDimitry Andric ArgumentCondition(0, WithinRange, Range(-1, IntMax))));
2917cfca06d7SDimitry Andric
2918cfca06d7SDimitry Andric // long fpathconf(int fildes, int name);
2919b60736ecSDimitry Andric addToFunctionSummaryMap("fpathconf",
2920b60736ecSDimitry Andric Signature(ArgTypes{IntTy, IntTy}, RetType{LongTy}),
2921b60736ecSDimitry Andric Summary(NoEvalCall)
2922b60736ecSDimitry Andric .ArgConstraint(ArgumentCondition(
2923b60736ecSDimitry Andric 0, WithinRange, Range(0, IntMax))));
2924cfca06d7SDimitry Andric
2925cfca06d7SDimitry Andric // long pathconf(const char *path, int name);
2926b60736ecSDimitry Andric addToFunctionSummaryMap(
2927b60736ecSDimitry Andric "pathconf", Signature(ArgTypes{ConstCharPtrTy, IntTy}, RetType{LongTy}),
2928b60736ecSDimitry Andric Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2929cfca06d7SDimitry Andric
2930cfca06d7SDimitry Andric // void rewinddir(DIR *dir);
2931cfca06d7SDimitry Andric addToFunctionSummaryMap(
2932b60736ecSDimitry Andric "rewinddir", Signature(ArgTypes{DirPtrTy}, RetType{VoidTy}),
2933b60736ecSDimitry Andric Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2934cfca06d7SDimitry Andric
2935cfca06d7SDimitry Andric // void seekdir(DIR *dirp, long loc);
2936b60736ecSDimitry Andric addToFunctionSummaryMap(
2937b60736ecSDimitry Andric "seekdir", Signature(ArgTypes{DirPtrTy, LongTy}, RetType{VoidTy}),
2938b60736ecSDimitry Andric Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2939cfca06d7SDimitry Andric
2940cfca06d7SDimitry Andric // int rand_r(unsigned int *seedp);
2941cfca06d7SDimitry Andric addToFunctionSummaryMap(
2942b60736ecSDimitry Andric "rand_r", Signature(ArgTypes{UnsignedIntPtrTy}, RetType{IntTy}),
2943b60736ecSDimitry Andric Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2944cfca06d7SDimitry Andric
2945cfca06d7SDimitry Andric // void *mmap(void *addr, size_t length, int prot, int flags, int fd,
2946cfca06d7SDimitry Andric // off_t offset);
2947145449b1SDimitry Andric // FIXME: Improve for errno modeling.
2948cfca06d7SDimitry Andric addToFunctionSummaryMap(
2949cfca06d7SDimitry Andric "mmap",
2950b60736ecSDimitry Andric Signature(ArgTypes{VoidPtrTy, SizeTy, IntTy, IntTy, IntTy, Off_tTy},
2951b60736ecSDimitry Andric RetType{VoidPtrTy}),
2952b60736ecSDimitry Andric Summary(NoEvalCall)
2953b60736ecSDimitry Andric .ArgConstraint(ArgumentCondition(1, WithinRange, Range(1, SizeMax)))
2954cfca06d7SDimitry Andric .ArgConstraint(
2955b60736ecSDimitry Andric ArgumentCondition(4, WithinRange, Range(-1, IntMax))));
2956cfca06d7SDimitry Andric
2957e3b55780SDimitry Andric std::optional<QualType> Off64_tTy = lookupTy("off64_t");
2958cfca06d7SDimitry Andric // void *mmap64(void *addr, size_t length, int prot, int flags, int fd,
2959cfca06d7SDimitry Andric // off64_t offset);
2960145449b1SDimitry Andric // FIXME: Improve for errno modeling.
2961cfca06d7SDimitry Andric addToFunctionSummaryMap(
2962cfca06d7SDimitry Andric "mmap64",
2963b60736ecSDimitry Andric Signature(ArgTypes{VoidPtrTy, SizeTy, IntTy, IntTy, IntTy, Off64_tTy},
2964b60736ecSDimitry Andric RetType{VoidPtrTy}),
2965b60736ecSDimitry Andric Summary(NoEvalCall)
2966b60736ecSDimitry Andric .ArgConstraint(ArgumentCondition(1, WithinRange, Range(1, SizeMax)))
2967cfca06d7SDimitry Andric .ArgConstraint(
2968b60736ecSDimitry Andric ArgumentCondition(4, WithinRange, Range(-1, IntMax))));
2969cfca06d7SDimitry Andric
2970cfca06d7SDimitry Andric // int pipe(int fildes[2]);
29717fa27ce4SDimitry Andric addToFunctionSummaryMap(
29727fa27ce4SDimitry Andric "pipe", Signature(ArgTypes{IntPtrTy}, RetType{IntTy}),
2973b60736ecSDimitry Andric Summary(NoEvalCall)
29747fa27ce4SDimitry Andric .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
29757fa27ce4SDimitry Andric .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2976cfca06d7SDimitry Andric .ArgConstraint(NotNull(ArgNo(0))));
2977cfca06d7SDimitry Andric
2978cfca06d7SDimitry Andric // off_t lseek(int fildes, off_t offset, int whence);
2979145449b1SDimitry Andric // In the first case we can not tell for sure if it failed or not.
2980145449b1SDimitry Andric // A return value different from of the expected offset (that is unknown
2981145449b1SDimitry Andric // here) may indicate failure. For this reason we do not enforce the errno
2982145449b1SDimitry Andric // check (can cause false positive).
2983cfca06d7SDimitry Andric addToFunctionSummaryMap(
2984b60736ecSDimitry Andric "lseek", Signature(ArgTypes{IntTy, Off_tTy, IntTy}, RetType{Off_tTy}),
2985b60736ecSDimitry Andric Summary(NoEvalCall)
2986145449b1SDimitry Andric .Case(ReturnsNonnegative, ErrnoIrrelevant)
29877fa27ce4SDimitry Andric .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2988b60736ecSDimitry Andric .ArgConstraint(
2989b60736ecSDimitry Andric ArgumentCondition(0, WithinRange, Range(0, IntMax))));
2990cfca06d7SDimitry Andric
2991cfca06d7SDimitry Andric // ssize_t readlink(const char *restrict path, char *restrict buf,
2992cfca06d7SDimitry Andric // size_t bufsize);
2993cfca06d7SDimitry Andric addToFunctionSummaryMap(
2994cfca06d7SDimitry Andric "readlink",
2995b60736ecSDimitry Andric Signature(ArgTypes{ConstCharPtrRestrictTy, CharPtrRestrictTy, SizeTy},
2996b60736ecSDimitry Andric RetType{Ssize_tTy}),
2997b60736ecSDimitry Andric Summary(NoEvalCall)
2998b1c73532SDimitry Andric .Case({ArgumentCondition(2, WithinRange, Range(1, IntMax)),
2999b1c73532SDimitry Andric ReturnValueCondition(LessThanOrEq, ArgNo(2)),
3000b1c73532SDimitry Andric ReturnValueCondition(WithinRange, Range(1, Ssize_tMax))},
30017fa27ce4SDimitry Andric ErrnoMustNotBeChecked, GenericSuccessMsg)
3002b1c73532SDimitry Andric .Case({ArgumentCondition(2, WithinRange, SingleValue(0)),
3003b1c73532SDimitry Andric ReturnValueCondition(WithinRange, SingleValue(0))},
3004b1c73532SDimitry Andric ErrnoMustNotBeChecked,
3005b1c73532SDimitry Andric "Assuming that argument 'bufsize' is 0")
30067fa27ce4SDimitry Andric .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3007cfca06d7SDimitry Andric .ArgConstraint(NotNull(ArgNo(0)))
3008cfca06d7SDimitry Andric .ArgConstraint(NotNull(ArgNo(1)))
3009cfca06d7SDimitry Andric .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
3010cfca06d7SDimitry Andric /*BufSize=*/ArgNo(2)))
3011cfca06d7SDimitry Andric .ArgConstraint(
3012cfca06d7SDimitry Andric ArgumentCondition(2, WithinRange, Range(0, SizeMax))));
3013cfca06d7SDimitry Andric
3014cfca06d7SDimitry Andric // ssize_t readlinkat(int fd, const char *restrict path,
3015cfca06d7SDimitry Andric // char *restrict buf, size_t bufsize);
3016cfca06d7SDimitry Andric addToFunctionSummaryMap(
3017b60736ecSDimitry Andric "readlinkat",
3018b60736ecSDimitry Andric Signature(
3019b60736ecSDimitry Andric ArgTypes{IntTy, ConstCharPtrRestrictTy, CharPtrRestrictTy, SizeTy},
3020b60736ecSDimitry Andric RetType{Ssize_tTy}),
3021b60736ecSDimitry Andric Summary(NoEvalCall)
3022b1c73532SDimitry Andric .Case({ArgumentCondition(3, WithinRange, Range(1, IntMax)),
3023b1c73532SDimitry Andric ReturnValueCondition(LessThanOrEq, ArgNo(3)),
3024b1c73532SDimitry Andric ReturnValueCondition(WithinRange, Range(1, Ssize_tMax))},
30257fa27ce4SDimitry Andric ErrnoMustNotBeChecked, GenericSuccessMsg)
3026b1c73532SDimitry Andric .Case({ArgumentCondition(3, WithinRange, SingleValue(0)),
3027b1c73532SDimitry Andric ReturnValueCondition(WithinRange, SingleValue(0))},
3028b1c73532SDimitry Andric ErrnoMustNotBeChecked,
3029b1c73532SDimitry Andric "Assuming that argument 'bufsize' is 0")
30307fa27ce4SDimitry Andric .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
30317fa27ce4SDimitry Andric .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
3032cfca06d7SDimitry Andric .ArgConstraint(NotNull(ArgNo(1)))
3033cfca06d7SDimitry Andric .ArgConstraint(NotNull(ArgNo(2)))
3034cfca06d7SDimitry Andric .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(2),
3035cfca06d7SDimitry Andric /*BufSize=*/ArgNo(3)))
3036b60736ecSDimitry Andric .ArgConstraint(
3037b60736ecSDimitry Andric ArgumentCondition(3, WithinRange, Range(0, SizeMax))));
3038cfca06d7SDimitry Andric
3039cfca06d7SDimitry Andric // int renameat(int olddirfd, const char *oldpath, int newdirfd, const char
3040cfca06d7SDimitry Andric // *newpath);
3041b60736ecSDimitry Andric addToFunctionSummaryMap(
3042b60736ecSDimitry Andric "renameat",
3043b60736ecSDimitry Andric Signature(ArgTypes{IntTy, ConstCharPtrTy, IntTy, ConstCharPtrTy},
3044b60736ecSDimitry Andric RetType{IntTy}),
3045b60736ecSDimitry Andric Summary(NoEvalCall)
30467fa27ce4SDimitry Andric .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
30477fa27ce4SDimitry Andric .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
30487fa27ce4SDimitry Andric .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
3049cfca06d7SDimitry Andric .ArgConstraint(NotNull(ArgNo(1)))
30507fa27ce4SDimitry Andric .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(2)))
3051cfca06d7SDimitry Andric .ArgConstraint(NotNull(ArgNo(3))));
3052cfca06d7SDimitry Andric
3053cfca06d7SDimitry Andric // char *realpath(const char *restrict file_name,
3054cfca06d7SDimitry Andric // char *restrict resolved_name);
3055ac9a064cSDimitry Andric // FIXME: If the argument 'resolved_name' is not NULL, macro 'PATH_MAX'
3056ac9a064cSDimitry Andric // should be defined in "limits.h" to guarrantee a success.
3057cfca06d7SDimitry Andric addToFunctionSummaryMap(
3058b60736ecSDimitry Andric "realpath",
3059b60736ecSDimitry Andric Signature(ArgTypes{ConstCharPtrRestrictTy, CharPtrRestrictTy},
3060b60736ecSDimitry Andric RetType{CharPtrTy}),
3061ac9a064cSDimitry Andric Summary(NoEvalCall)
3062ac9a064cSDimitry Andric .Case({NotNull(Ret)}, ErrnoMustNotBeChecked, GenericSuccessMsg)
3063ac9a064cSDimitry Andric .Case({IsNull(Ret)}, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3064ac9a064cSDimitry Andric .ArgConstraint(NotNull(ArgNo(0))));
3065cfca06d7SDimitry Andric
3066b60736ecSDimitry Andric QualType CharPtrConstPtr = getPointerTy(getConstTy(CharPtrTy));
3067cfca06d7SDimitry Andric
3068cfca06d7SDimitry Andric // int execv(const char *path, char *const argv[]);
3069b60736ecSDimitry Andric addToFunctionSummaryMap(
3070b60736ecSDimitry Andric "execv",
3071b60736ecSDimitry Andric Signature(ArgTypes{ConstCharPtrTy, CharPtrConstPtr}, RetType{IntTy}),
3072b60736ecSDimitry Andric Summary(NoEvalCall)
3073ac9a064cSDimitry Andric .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
3074cfca06d7SDimitry Andric .ArgConstraint(NotNull(ArgNo(0))));
3075cfca06d7SDimitry Andric
3076cfca06d7SDimitry Andric // int execvp(const char *file, char *const argv[]);
3077b60736ecSDimitry Andric addToFunctionSummaryMap(
3078b60736ecSDimitry Andric "execvp",
3079b60736ecSDimitry Andric Signature(ArgTypes{ConstCharPtrTy, CharPtrConstPtr}, RetType{IntTy}),
3080b60736ecSDimitry Andric Summary(NoEvalCall)
3081ac9a064cSDimitry Andric .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
3082cfca06d7SDimitry Andric .ArgConstraint(NotNull(ArgNo(0))));
3083cfca06d7SDimitry Andric
3084cfca06d7SDimitry Andric // int getopt(int argc, char * const argv[], const char *optstring);
3085cfca06d7SDimitry Andric addToFunctionSummaryMap(
3086cfca06d7SDimitry Andric "getopt",
3087b60736ecSDimitry Andric Signature(ArgTypes{IntTy, CharPtrConstPtr, ConstCharPtrTy},
3088b60736ecSDimitry Andric RetType{IntTy}),
3089b60736ecSDimitry Andric Summary(NoEvalCall)
3090145449b1SDimitry Andric .Case({ReturnValueCondition(WithinRange, Range(-1, UCharRangeMax))},
3091145449b1SDimitry Andric ErrnoIrrelevant)
3092cfca06d7SDimitry Andric .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
3093cfca06d7SDimitry Andric .ArgConstraint(NotNull(ArgNo(1)))
3094cfca06d7SDimitry Andric .ArgConstraint(NotNull(ArgNo(2))));
3095b60736ecSDimitry Andric
3096e3b55780SDimitry Andric std::optional<QualType> StructSockaddrTy = lookupTy("sockaddr");
3097e3b55780SDimitry Andric std::optional<QualType> StructSockaddrPtrTy =
3098e3b55780SDimitry Andric getPointerTy(StructSockaddrTy);
3099e3b55780SDimitry Andric std::optional<QualType> ConstStructSockaddrPtrTy =
3100b60736ecSDimitry Andric getPointerTy(getConstTy(StructSockaddrTy));
3101e3b55780SDimitry Andric std::optional<QualType> StructSockaddrPtrRestrictTy =
3102b60736ecSDimitry Andric getRestrictTy(StructSockaddrPtrTy);
3103e3b55780SDimitry Andric std::optional<QualType> ConstStructSockaddrPtrRestrictTy =
3104b60736ecSDimitry Andric getRestrictTy(ConstStructSockaddrPtrTy);
3105e3b55780SDimitry Andric std::optional<QualType> Socklen_tTy = lookupTy("socklen_t");
3106e3b55780SDimitry Andric std::optional<QualType> Socklen_tPtrTy = getPointerTy(Socklen_tTy);
3107e3b55780SDimitry Andric std::optional<QualType> Socklen_tPtrRestrictTy =
3108e3b55780SDimitry Andric getRestrictTy(Socklen_tPtrTy);
3109e3b55780SDimitry Andric std::optional<RangeInt> Socklen_tMax = getMaxValue(Socklen_tTy);
3110b60736ecSDimitry Andric
3111b60736ecSDimitry Andric // In 'socket.h' of some libc implementations with C99, sockaddr parameter
3112b60736ecSDimitry Andric // is a transparent union of the underlying sockaddr_ family of pointers
3113b60736ecSDimitry Andric // instead of being a pointer to struct sockaddr. In these cases, the
3114b60736ecSDimitry Andric // standardized signature will not match, thus we try to match with another
3115b60736ecSDimitry Andric // signature that has the joker Irrelevant type. We also remove those
3116b60736ecSDimitry Andric // constraints which require pointer types for the sockaddr param.
31177fa27ce4SDimitry Andric
31187fa27ce4SDimitry Andric // int socket(int domain, int type, int protocol);
31197fa27ce4SDimitry Andric addToFunctionSummaryMap(
31207fa27ce4SDimitry Andric "socket", Signature(ArgTypes{IntTy, IntTy, IntTy}, RetType{IntTy}),
31217fa27ce4SDimitry Andric Summary(NoEvalCall)
31227fa27ce4SDimitry Andric .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked,
31237fa27ce4SDimitry Andric GenericSuccessMsg)
31247fa27ce4SDimitry Andric .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg));
31257fa27ce4SDimitry Andric
3126b60736ecSDimitry Andric auto Accept =
3127b60736ecSDimitry Andric Summary(NoEvalCall)
31287fa27ce4SDimitry Andric .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked,
31297fa27ce4SDimitry Andric GenericSuccessMsg)
31307fa27ce4SDimitry Andric .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3131b60736ecSDimitry Andric .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)));
3132b60736ecSDimitry Andric if (!addToFunctionSummaryMap(
3133b60736ecSDimitry Andric "accept",
3134b60736ecSDimitry Andric // int accept(int socket, struct sockaddr *restrict address,
3135b60736ecSDimitry Andric // socklen_t *restrict address_len);
3136b60736ecSDimitry Andric Signature(ArgTypes{IntTy, StructSockaddrPtrRestrictTy,
3137b60736ecSDimitry Andric Socklen_tPtrRestrictTy},
3138b60736ecSDimitry Andric RetType{IntTy}),
3139b60736ecSDimitry Andric Accept))
3140b60736ecSDimitry Andric addToFunctionSummaryMap(
3141b60736ecSDimitry Andric "accept",
3142b60736ecSDimitry Andric Signature(ArgTypes{IntTy, Irrelevant, Socklen_tPtrRestrictTy},
3143b60736ecSDimitry Andric RetType{IntTy}),
3144b60736ecSDimitry Andric Accept);
3145b60736ecSDimitry Andric
3146b60736ecSDimitry Andric // int bind(int socket, const struct sockaddr *address, socklen_t
3147b60736ecSDimitry Andric // address_len);
3148b60736ecSDimitry Andric if (!addToFunctionSummaryMap(
3149b60736ecSDimitry Andric "bind",
3150b60736ecSDimitry Andric Signature(ArgTypes{IntTy, ConstStructSockaddrPtrTy, Socklen_tTy},
3151b60736ecSDimitry Andric RetType{IntTy}),
3152b60736ecSDimitry Andric Summary(NoEvalCall)
31537fa27ce4SDimitry Andric .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
31547fa27ce4SDimitry Andric .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3155b60736ecSDimitry Andric .ArgConstraint(
3156b60736ecSDimitry Andric ArgumentCondition(0, WithinRange, Range(0, IntMax)))
3157b60736ecSDimitry Andric .ArgConstraint(NotNull(ArgNo(1)))
3158b60736ecSDimitry Andric .ArgConstraint(
3159b60736ecSDimitry Andric BufferSize(/*Buffer=*/ArgNo(1), /*BufSize=*/ArgNo(2)))
3160b60736ecSDimitry Andric .ArgConstraint(
3161b60736ecSDimitry Andric ArgumentCondition(2, WithinRange, Range(0, Socklen_tMax)))))
3162b60736ecSDimitry Andric // Do not add constraints on sockaddr.
3163b60736ecSDimitry Andric addToFunctionSummaryMap(
3164b60736ecSDimitry Andric "bind",
3165b60736ecSDimitry Andric Signature(ArgTypes{IntTy, Irrelevant, Socklen_tTy}, RetType{IntTy}),
3166b60736ecSDimitry Andric Summary(NoEvalCall)
31677fa27ce4SDimitry Andric .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
31687fa27ce4SDimitry Andric .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3169b60736ecSDimitry Andric .ArgConstraint(
3170b60736ecSDimitry Andric ArgumentCondition(0, WithinRange, Range(0, IntMax)))
3171b60736ecSDimitry Andric .ArgConstraint(
3172b60736ecSDimitry Andric ArgumentCondition(2, WithinRange, Range(0, Socklen_tMax))));
3173b60736ecSDimitry Andric
3174b60736ecSDimitry Andric // int getpeername(int socket, struct sockaddr *restrict address,
3175b60736ecSDimitry Andric // socklen_t *restrict address_len);
3176b60736ecSDimitry Andric if (!addToFunctionSummaryMap(
3177b60736ecSDimitry Andric "getpeername",
3178b60736ecSDimitry Andric Signature(ArgTypes{IntTy, StructSockaddrPtrRestrictTy,
3179b60736ecSDimitry Andric Socklen_tPtrRestrictTy},
3180b60736ecSDimitry Andric RetType{IntTy}),
3181b60736ecSDimitry Andric Summary(NoEvalCall)
31827fa27ce4SDimitry Andric .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
31837fa27ce4SDimitry Andric .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3184b60736ecSDimitry Andric .ArgConstraint(
3185b60736ecSDimitry Andric ArgumentCondition(0, WithinRange, Range(0, IntMax)))
3186b60736ecSDimitry Andric .ArgConstraint(NotNull(ArgNo(1)))
3187b60736ecSDimitry Andric .ArgConstraint(NotNull(ArgNo(2)))))
3188b60736ecSDimitry Andric addToFunctionSummaryMap(
3189b60736ecSDimitry Andric "getpeername",
3190b60736ecSDimitry Andric Signature(ArgTypes{IntTy, Irrelevant, Socklen_tPtrRestrictTy},
3191b60736ecSDimitry Andric RetType{IntTy}),
3192b60736ecSDimitry Andric Summary(NoEvalCall)
31937fa27ce4SDimitry Andric .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
31947fa27ce4SDimitry Andric .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3195b60736ecSDimitry Andric .ArgConstraint(
3196b60736ecSDimitry Andric ArgumentCondition(0, WithinRange, Range(0, IntMax))));
3197b60736ecSDimitry Andric
3198b60736ecSDimitry Andric // int getsockname(int socket, struct sockaddr *restrict address,
3199b60736ecSDimitry Andric // socklen_t *restrict address_len);
3200b60736ecSDimitry Andric if (!addToFunctionSummaryMap(
3201b60736ecSDimitry Andric "getsockname",
3202b60736ecSDimitry Andric Signature(ArgTypes{IntTy, StructSockaddrPtrRestrictTy,
3203b60736ecSDimitry Andric Socklen_tPtrRestrictTy},
3204b60736ecSDimitry Andric RetType{IntTy}),
3205b60736ecSDimitry Andric Summary(NoEvalCall)
32067fa27ce4SDimitry Andric .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
32077fa27ce4SDimitry Andric .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3208b60736ecSDimitry Andric .ArgConstraint(
3209b60736ecSDimitry Andric ArgumentCondition(0, WithinRange, Range(0, IntMax)))
3210b60736ecSDimitry Andric .ArgConstraint(NotNull(ArgNo(1)))
3211b60736ecSDimitry Andric .ArgConstraint(NotNull(ArgNo(2)))))
3212b60736ecSDimitry Andric addToFunctionSummaryMap(
3213b60736ecSDimitry Andric "getsockname",
3214b60736ecSDimitry Andric Signature(ArgTypes{IntTy, Irrelevant, Socklen_tPtrRestrictTy},
3215b60736ecSDimitry Andric RetType{IntTy}),
3216b60736ecSDimitry Andric Summary(NoEvalCall)
32177fa27ce4SDimitry Andric .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
32187fa27ce4SDimitry Andric .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3219b60736ecSDimitry Andric .ArgConstraint(
3220b60736ecSDimitry Andric ArgumentCondition(0, WithinRange, Range(0, IntMax))));
3221b60736ecSDimitry Andric
3222b60736ecSDimitry Andric // int connect(int socket, const struct sockaddr *address, socklen_t
3223b60736ecSDimitry Andric // address_len);
3224b60736ecSDimitry Andric if (!addToFunctionSummaryMap(
3225b60736ecSDimitry Andric "connect",
3226b60736ecSDimitry Andric Signature(ArgTypes{IntTy, ConstStructSockaddrPtrTy, Socklen_tTy},
3227b60736ecSDimitry Andric RetType{IntTy}),
3228b60736ecSDimitry Andric Summary(NoEvalCall)
32297fa27ce4SDimitry Andric .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
32307fa27ce4SDimitry Andric .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3231b60736ecSDimitry Andric .ArgConstraint(
3232b60736ecSDimitry Andric ArgumentCondition(0, WithinRange, Range(0, IntMax)))
3233b60736ecSDimitry Andric .ArgConstraint(NotNull(ArgNo(1)))))
3234b60736ecSDimitry Andric addToFunctionSummaryMap(
3235b60736ecSDimitry Andric "connect",
3236b60736ecSDimitry Andric Signature(ArgTypes{IntTy, Irrelevant, Socklen_tTy}, RetType{IntTy}),
3237b60736ecSDimitry Andric Summary(NoEvalCall)
32387fa27ce4SDimitry Andric .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
32397fa27ce4SDimitry Andric .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3240b60736ecSDimitry Andric .ArgConstraint(
3241b60736ecSDimitry Andric ArgumentCondition(0, WithinRange, Range(0, IntMax))));
3242b60736ecSDimitry Andric
3243b60736ecSDimitry Andric auto Recvfrom =
3244b60736ecSDimitry Andric Summary(NoEvalCall)
3245b60736ecSDimitry Andric .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)),
3246b1c73532SDimitry Andric ReturnValueCondition(WithinRange, Range(1, Ssize_tMax))},
3247b1c73532SDimitry Andric ErrnoMustNotBeChecked, GenericSuccessMsg)
3248b1c73532SDimitry Andric .Case({ReturnValueCondition(WithinRange, SingleValue(0)),
3249b1c73532SDimitry Andric ArgumentCondition(2, WithinRange, SingleValue(0))},
32507fa27ce4SDimitry Andric ErrnoMustNotBeChecked, GenericSuccessMsg)
32517fa27ce4SDimitry Andric .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3252b60736ecSDimitry Andric .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
3253b60736ecSDimitry Andric .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
3254b60736ecSDimitry Andric /*BufSize=*/ArgNo(2)));
3255b60736ecSDimitry Andric if (!addToFunctionSummaryMap(
3256b60736ecSDimitry Andric "recvfrom",
3257b60736ecSDimitry Andric // ssize_t recvfrom(int socket, void *restrict buffer,
3258b60736ecSDimitry Andric // size_t length,
3259b60736ecSDimitry Andric // int flags, struct sockaddr *restrict address,
3260b60736ecSDimitry Andric // socklen_t *restrict address_len);
3261b60736ecSDimitry Andric Signature(ArgTypes{IntTy, VoidPtrRestrictTy, SizeTy, IntTy,
3262b60736ecSDimitry Andric StructSockaddrPtrRestrictTy,
3263b60736ecSDimitry Andric Socklen_tPtrRestrictTy},
3264b60736ecSDimitry Andric RetType{Ssize_tTy}),
3265b60736ecSDimitry Andric Recvfrom))
3266b60736ecSDimitry Andric addToFunctionSummaryMap(
3267b60736ecSDimitry Andric "recvfrom",
3268b60736ecSDimitry Andric Signature(ArgTypes{IntTy, VoidPtrRestrictTy, SizeTy, IntTy,
3269b60736ecSDimitry Andric Irrelevant, Socklen_tPtrRestrictTy},
3270b60736ecSDimitry Andric RetType{Ssize_tTy}),
3271b60736ecSDimitry Andric Recvfrom);
3272b60736ecSDimitry Andric
3273b60736ecSDimitry Andric auto Sendto =
3274b60736ecSDimitry Andric Summary(NoEvalCall)
3275b60736ecSDimitry Andric .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)),
3276b1c73532SDimitry Andric ReturnValueCondition(WithinRange, Range(1, Ssize_tMax))},
3277b1c73532SDimitry Andric ErrnoMustNotBeChecked, GenericSuccessMsg)
3278b1c73532SDimitry Andric .Case({ReturnValueCondition(WithinRange, SingleValue(0)),
3279b1c73532SDimitry Andric ArgumentCondition(2, WithinRange, SingleValue(0))},
32807fa27ce4SDimitry Andric ErrnoMustNotBeChecked, GenericSuccessMsg)
32817fa27ce4SDimitry Andric .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3282b60736ecSDimitry Andric .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
3283b60736ecSDimitry Andric .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
3284b60736ecSDimitry Andric /*BufSize=*/ArgNo(2)));
3285b60736ecSDimitry Andric if (!addToFunctionSummaryMap(
3286b60736ecSDimitry Andric "sendto",
3287b60736ecSDimitry Andric // ssize_t sendto(int socket, const void *message, size_t length,
3288b60736ecSDimitry Andric // int flags, const struct sockaddr *dest_addr,
3289b60736ecSDimitry Andric // socklen_t dest_len);
3290b60736ecSDimitry Andric Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTy, IntTy,
3291b60736ecSDimitry Andric ConstStructSockaddrPtrTy, Socklen_tTy},
3292b60736ecSDimitry Andric RetType{Ssize_tTy}),
3293b60736ecSDimitry Andric Sendto))
3294b60736ecSDimitry Andric addToFunctionSummaryMap(
3295b60736ecSDimitry Andric "sendto",
3296b60736ecSDimitry Andric Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTy, IntTy, Irrelevant,
3297b60736ecSDimitry Andric Socklen_tTy},
3298b60736ecSDimitry Andric RetType{Ssize_tTy}),
3299b60736ecSDimitry Andric Sendto);
3300b60736ecSDimitry Andric
3301b60736ecSDimitry Andric // int listen(int sockfd, int backlog);
33027fa27ce4SDimitry Andric addToFunctionSummaryMap(
33037fa27ce4SDimitry Andric "listen", Signature(ArgTypes{IntTy, IntTy}, RetType{IntTy}),
3304b60736ecSDimitry Andric Summary(NoEvalCall)
33057fa27ce4SDimitry Andric .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
33067fa27ce4SDimitry Andric .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
33077fa27ce4SDimitry Andric .ArgConstraint(
33087fa27ce4SDimitry Andric ArgumentCondition(0, WithinRange, Range(0, IntMax))));
3309b60736ecSDimitry Andric
3310b60736ecSDimitry Andric // ssize_t recv(int sockfd, void *buf, size_t len, int flags);
3311b60736ecSDimitry Andric addToFunctionSummaryMap(
3312b60736ecSDimitry Andric "recv",
3313b60736ecSDimitry Andric Signature(ArgTypes{IntTy, VoidPtrTy, SizeTy, IntTy},
3314b60736ecSDimitry Andric RetType{Ssize_tTy}),
3315b60736ecSDimitry Andric Summary(NoEvalCall)
3316b60736ecSDimitry Andric .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)),
3317b1c73532SDimitry Andric ReturnValueCondition(WithinRange, Range(1, Ssize_tMax))},
3318b1c73532SDimitry Andric ErrnoMustNotBeChecked, GenericSuccessMsg)
3319b1c73532SDimitry Andric .Case({ReturnValueCondition(WithinRange, SingleValue(0)),
3320b1c73532SDimitry Andric ArgumentCondition(2, WithinRange, SingleValue(0))},
33217fa27ce4SDimitry Andric ErrnoMustNotBeChecked, GenericSuccessMsg)
33227fa27ce4SDimitry Andric .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3323b60736ecSDimitry Andric .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
3324b60736ecSDimitry Andric .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
3325b60736ecSDimitry Andric /*BufSize=*/ArgNo(2))));
3326b60736ecSDimitry Andric
3327e3b55780SDimitry Andric std::optional<QualType> StructMsghdrTy = lookupTy("msghdr");
3328e3b55780SDimitry Andric std::optional<QualType> StructMsghdrPtrTy = getPointerTy(StructMsghdrTy);
3329e3b55780SDimitry Andric std::optional<QualType> ConstStructMsghdrPtrTy =
3330b60736ecSDimitry Andric getPointerTy(getConstTy(StructMsghdrTy));
3331b60736ecSDimitry Andric
3332b60736ecSDimitry Andric // ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);
3333b60736ecSDimitry Andric addToFunctionSummaryMap(
3334b60736ecSDimitry Andric "recvmsg",
3335b60736ecSDimitry Andric Signature(ArgTypes{IntTy, StructMsghdrPtrTy, IntTy},
3336b60736ecSDimitry Andric RetType{Ssize_tTy}),
3337b60736ecSDimitry Andric Summary(NoEvalCall)
3338b1c73532SDimitry Andric .Case({ReturnValueCondition(WithinRange, Range(1, Ssize_tMax))},
33397fa27ce4SDimitry Andric ErrnoMustNotBeChecked, GenericSuccessMsg)
33407fa27ce4SDimitry Andric .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3341b60736ecSDimitry Andric .ArgConstraint(
3342b60736ecSDimitry Andric ArgumentCondition(0, WithinRange, Range(0, IntMax))));
3343b60736ecSDimitry Andric
3344b60736ecSDimitry Andric // ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
3345b60736ecSDimitry Andric addToFunctionSummaryMap(
3346b60736ecSDimitry Andric "sendmsg",
3347b60736ecSDimitry Andric Signature(ArgTypes{IntTy, ConstStructMsghdrPtrTy, IntTy},
3348b60736ecSDimitry Andric RetType{Ssize_tTy}),
3349b60736ecSDimitry Andric Summary(NoEvalCall)
3350b1c73532SDimitry Andric .Case({ReturnValueCondition(WithinRange, Range(1, Ssize_tMax))},
33517fa27ce4SDimitry Andric ErrnoMustNotBeChecked, GenericSuccessMsg)
33527fa27ce4SDimitry Andric .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3353b60736ecSDimitry Andric .ArgConstraint(
3354b60736ecSDimitry Andric ArgumentCondition(0, WithinRange, Range(0, IntMax))));
3355b60736ecSDimitry Andric
3356b60736ecSDimitry Andric // int setsockopt(int socket, int level, int option_name,
3357b60736ecSDimitry Andric // const void *option_value, socklen_t option_len);
3358b60736ecSDimitry Andric addToFunctionSummaryMap(
3359b60736ecSDimitry Andric "setsockopt",
3360b60736ecSDimitry Andric Signature(ArgTypes{IntTy, IntTy, IntTy, ConstVoidPtrTy, Socklen_tTy},
3361b60736ecSDimitry Andric RetType{IntTy}),
3362b60736ecSDimitry Andric Summary(NoEvalCall)
33637fa27ce4SDimitry Andric .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
33647fa27ce4SDimitry Andric .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3365b60736ecSDimitry Andric .ArgConstraint(NotNull(ArgNo(3)))
3366b60736ecSDimitry Andric .ArgConstraint(
3367b60736ecSDimitry Andric BufferSize(/*Buffer=*/ArgNo(3), /*BufSize=*/ArgNo(4)))
3368b60736ecSDimitry Andric .ArgConstraint(
3369b60736ecSDimitry Andric ArgumentCondition(4, WithinRange, Range(0, Socklen_tMax))));
3370b60736ecSDimitry Andric
3371b60736ecSDimitry Andric // int getsockopt(int socket, int level, int option_name,
3372b60736ecSDimitry Andric // void *restrict option_value,
3373b60736ecSDimitry Andric // socklen_t *restrict option_len);
3374b60736ecSDimitry Andric addToFunctionSummaryMap(
3375b60736ecSDimitry Andric "getsockopt",
3376b60736ecSDimitry Andric Signature(ArgTypes{IntTy, IntTy, IntTy, VoidPtrRestrictTy,
3377b60736ecSDimitry Andric Socklen_tPtrRestrictTy},
3378b60736ecSDimitry Andric RetType{IntTy}),
3379b60736ecSDimitry Andric Summary(NoEvalCall)
33807fa27ce4SDimitry Andric .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
33817fa27ce4SDimitry Andric .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3382b60736ecSDimitry Andric .ArgConstraint(NotNull(ArgNo(3)))
3383b60736ecSDimitry Andric .ArgConstraint(NotNull(ArgNo(4))));
3384b60736ecSDimitry Andric
3385b60736ecSDimitry Andric // ssize_t send(int sockfd, const void *buf, size_t len, int flags);
3386b60736ecSDimitry Andric addToFunctionSummaryMap(
3387b60736ecSDimitry Andric "send",
3388b60736ecSDimitry Andric Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTy, IntTy},
3389b60736ecSDimitry Andric RetType{Ssize_tTy}),
3390b60736ecSDimitry Andric Summary(NoEvalCall)
3391b60736ecSDimitry Andric .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)),
3392b1c73532SDimitry Andric ReturnValueCondition(WithinRange, Range(1, Ssize_tMax))},
3393b1c73532SDimitry Andric ErrnoMustNotBeChecked, GenericSuccessMsg)
3394b1c73532SDimitry Andric .Case({ReturnValueCondition(WithinRange, SingleValue(0)),
3395b1c73532SDimitry Andric ArgumentCondition(2, WithinRange, SingleValue(0))},
33967fa27ce4SDimitry Andric ErrnoMustNotBeChecked, GenericSuccessMsg)
33977fa27ce4SDimitry Andric .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3398b60736ecSDimitry Andric .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
3399b60736ecSDimitry Andric .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
3400b60736ecSDimitry Andric /*BufSize=*/ArgNo(2))));
3401b60736ecSDimitry Andric
3402b60736ecSDimitry Andric // int socketpair(int domain, int type, int protocol, int sv[2]);
3403b60736ecSDimitry Andric addToFunctionSummaryMap(
3404b60736ecSDimitry Andric "socketpair",
3405b60736ecSDimitry Andric Signature(ArgTypes{IntTy, IntTy, IntTy, IntPtrTy}, RetType{IntTy}),
3406b60736ecSDimitry Andric Summary(NoEvalCall)
34077fa27ce4SDimitry Andric .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
34087fa27ce4SDimitry Andric .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3409b60736ecSDimitry Andric .ArgConstraint(NotNull(ArgNo(3))));
3410b60736ecSDimitry Andric
34117fa27ce4SDimitry Andric // int shutdown(int socket, int how);
34127fa27ce4SDimitry Andric addToFunctionSummaryMap(
34137fa27ce4SDimitry Andric "shutdown", Signature(ArgTypes{IntTy, IntTy}, RetType{IntTy}),
34147fa27ce4SDimitry Andric Summary(NoEvalCall)
34157fa27ce4SDimitry Andric .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
34167fa27ce4SDimitry Andric .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
34177fa27ce4SDimitry Andric .ArgConstraint(
34187fa27ce4SDimitry Andric ArgumentCondition(0, WithinRange, Range(0, IntMax))));
34197fa27ce4SDimitry Andric
3420b60736ecSDimitry Andric // int getnameinfo(const struct sockaddr *restrict sa, socklen_t salen,
3421b60736ecSDimitry Andric // char *restrict node, socklen_t nodelen,
3422b60736ecSDimitry Andric // char *restrict service,
3423b60736ecSDimitry Andric // socklen_t servicelen, int flags);
3424b60736ecSDimitry Andric //
3425b60736ecSDimitry Andric // This is defined in netdb.h. And contrary to 'socket.h', the sockaddr
3426b60736ecSDimitry Andric // parameter is never handled as a transparent union in netdb.h
3427b60736ecSDimitry Andric addToFunctionSummaryMap(
3428b60736ecSDimitry Andric "getnameinfo",
3429b60736ecSDimitry Andric Signature(ArgTypes{ConstStructSockaddrPtrRestrictTy, Socklen_tTy,
3430b60736ecSDimitry Andric CharPtrRestrictTy, Socklen_tTy, CharPtrRestrictTy,
3431b60736ecSDimitry Andric Socklen_tTy, IntTy},
3432b60736ecSDimitry Andric RetType{IntTy}),
3433b60736ecSDimitry Andric Summary(NoEvalCall)
3434b60736ecSDimitry Andric .ArgConstraint(
3435b60736ecSDimitry Andric BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1)))
3436b60736ecSDimitry Andric .ArgConstraint(
3437b60736ecSDimitry Andric ArgumentCondition(1, WithinRange, Range(0, Socklen_tMax)))
3438b60736ecSDimitry Andric .ArgConstraint(
3439b60736ecSDimitry Andric BufferSize(/*Buffer=*/ArgNo(2), /*BufSize=*/ArgNo(3)))
3440b60736ecSDimitry Andric .ArgConstraint(
3441b60736ecSDimitry Andric ArgumentCondition(3, WithinRange, Range(0, Socklen_tMax)))
3442b60736ecSDimitry Andric .ArgConstraint(
3443b60736ecSDimitry Andric BufferSize(/*Buffer=*/ArgNo(4), /*BufSize=*/ArgNo(5)))
3444b60736ecSDimitry Andric .ArgConstraint(
3445b60736ecSDimitry Andric ArgumentCondition(5, WithinRange, Range(0, Socklen_tMax))));
3446b60736ecSDimitry Andric
3447e3b55780SDimitry Andric std::optional<QualType> StructUtimbufTy = lookupTy("utimbuf");
3448e3b55780SDimitry Andric std::optional<QualType> StructUtimbufPtrTy = getPointerTy(StructUtimbufTy);
3449b60736ecSDimitry Andric
3450b60736ecSDimitry Andric // int utime(const char *filename, struct utimbuf *buf);
3451b60736ecSDimitry Andric addToFunctionSummaryMap(
3452b60736ecSDimitry Andric "utime",
3453b60736ecSDimitry Andric Signature(ArgTypes{ConstCharPtrTy, StructUtimbufPtrTy}, RetType{IntTy}),
3454b60736ecSDimitry Andric Summary(NoEvalCall)
34557fa27ce4SDimitry Andric .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
34567fa27ce4SDimitry Andric .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3457b60736ecSDimitry Andric .ArgConstraint(NotNull(ArgNo(0))));
3458b60736ecSDimitry Andric
3459e3b55780SDimitry Andric std::optional<QualType> StructTimespecTy = lookupTy("timespec");
3460e3b55780SDimitry Andric std::optional<QualType> StructTimespecPtrTy =
3461e3b55780SDimitry Andric getPointerTy(StructTimespecTy);
3462e3b55780SDimitry Andric std::optional<QualType> ConstStructTimespecPtrTy =
3463b60736ecSDimitry Andric getPointerTy(getConstTy(StructTimespecTy));
3464b60736ecSDimitry Andric
3465b60736ecSDimitry Andric // int futimens(int fd, const struct timespec times[2]);
3466b60736ecSDimitry Andric addToFunctionSummaryMap(
3467b60736ecSDimitry Andric "futimens",
3468b60736ecSDimitry Andric Signature(ArgTypes{IntTy, ConstStructTimespecPtrTy}, RetType{IntTy}),
3469b60736ecSDimitry Andric Summary(NoEvalCall)
34707fa27ce4SDimitry Andric .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
34717fa27ce4SDimitry Andric .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3472b60736ecSDimitry Andric .ArgConstraint(
3473b60736ecSDimitry Andric ArgumentCondition(0, WithinRange, Range(0, IntMax))));
3474b60736ecSDimitry Andric
3475b60736ecSDimitry Andric // int utimensat(int dirfd, const char *pathname,
3476b60736ecSDimitry Andric // const struct timespec times[2], int flags);
34777fa27ce4SDimitry Andric addToFunctionSummaryMap(
34787fa27ce4SDimitry Andric "utimensat",
34797fa27ce4SDimitry Andric Signature(
34807fa27ce4SDimitry Andric ArgTypes{IntTy, ConstCharPtrTy, ConstStructTimespecPtrTy, IntTy},
3481b60736ecSDimitry Andric RetType{IntTy}),
3482b60736ecSDimitry Andric Summary(NoEvalCall)
34837fa27ce4SDimitry Andric .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
34847fa27ce4SDimitry Andric .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3485b60736ecSDimitry Andric .ArgConstraint(NotNull(ArgNo(1))));
3486b60736ecSDimitry Andric
3487e3b55780SDimitry Andric std::optional<QualType> StructTimevalTy = lookupTy("timeval");
3488e3b55780SDimitry Andric std::optional<QualType> ConstStructTimevalPtrTy =
3489b60736ecSDimitry Andric getPointerTy(getConstTy(StructTimevalTy));
3490b60736ecSDimitry Andric
3491b60736ecSDimitry Andric // int utimes(const char *filename, const struct timeval times[2]);
3492b60736ecSDimitry Andric addToFunctionSummaryMap(
3493b60736ecSDimitry Andric "utimes",
3494b60736ecSDimitry Andric Signature(ArgTypes{ConstCharPtrTy, ConstStructTimevalPtrTy},
3495b60736ecSDimitry Andric RetType{IntTy}),
3496b60736ecSDimitry Andric Summary(NoEvalCall)
34977fa27ce4SDimitry Andric .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
34987fa27ce4SDimitry Andric .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3499b60736ecSDimitry Andric .ArgConstraint(NotNull(ArgNo(0))));
3500b60736ecSDimitry Andric
3501b60736ecSDimitry Andric // int nanosleep(const struct timespec *rqtp, struct timespec *rmtp);
3502b60736ecSDimitry Andric addToFunctionSummaryMap(
3503b60736ecSDimitry Andric "nanosleep",
3504b60736ecSDimitry Andric Signature(ArgTypes{ConstStructTimespecPtrTy, StructTimespecPtrTy},
3505b60736ecSDimitry Andric RetType{IntTy}),
3506b60736ecSDimitry Andric Summary(NoEvalCall)
35077fa27ce4SDimitry Andric .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
35087fa27ce4SDimitry Andric .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3509b60736ecSDimitry Andric .ArgConstraint(NotNull(ArgNo(0))));
3510b60736ecSDimitry Andric
3511e3b55780SDimitry Andric std::optional<QualType> Time_tTy = lookupTy("time_t");
3512e3b55780SDimitry Andric std::optional<QualType> ConstTime_tPtrTy =
3513e3b55780SDimitry Andric getPointerTy(getConstTy(Time_tTy));
3514e3b55780SDimitry Andric std::optional<QualType> ConstTime_tPtrRestrictTy =
3515b60736ecSDimitry Andric getRestrictTy(ConstTime_tPtrTy);
3516b60736ecSDimitry Andric
3517e3b55780SDimitry Andric std::optional<QualType> StructTmTy = lookupTy("tm");
3518e3b55780SDimitry Andric std::optional<QualType> StructTmPtrTy = getPointerTy(StructTmTy);
3519e3b55780SDimitry Andric std::optional<QualType> StructTmPtrRestrictTy =
3520e3b55780SDimitry Andric getRestrictTy(StructTmPtrTy);
3521e3b55780SDimitry Andric std::optional<QualType> ConstStructTmPtrTy =
3522b60736ecSDimitry Andric getPointerTy(getConstTy(StructTmTy));
3523e3b55780SDimitry Andric std::optional<QualType> ConstStructTmPtrRestrictTy =
3524b60736ecSDimitry Andric getRestrictTy(ConstStructTmPtrTy);
3525b60736ecSDimitry Andric
3526b60736ecSDimitry Andric // struct tm * localtime(const time_t *tp);
3527b60736ecSDimitry Andric addToFunctionSummaryMap(
3528b60736ecSDimitry Andric "localtime",
3529b60736ecSDimitry Andric Signature(ArgTypes{ConstTime_tPtrTy}, RetType{StructTmPtrTy}),
3530b60736ecSDimitry Andric Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
3531b60736ecSDimitry Andric
3532b60736ecSDimitry Andric // struct tm *localtime_r(const time_t *restrict timer,
3533b60736ecSDimitry Andric // struct tm *restrict result);
3534b60736ecSDimitry Andric addToFunctionSummaryMap(
3535b60736ecSDimitry Andric "localtime_r",
3536b60736ecSDimitry Andric Signature(ArgTypes{ConstTime_tPtrRestrictTy, StructTmPtrRestrictTy},
3537b60736ecSDimitry Andric RetType{StructTmPtrTy}),
3538b60736ecSDimitry Andric Summary(NoEvalCall)
3539b60736ecSDimitry Andric .ArgConstraint(NotNull(ArgNo(0)))
3540b60736ecSDimitry Andric .ArgConstraint(NotNull(ArgNo(1))));
3541b60736ecSDimitry Andric
3542b60736ecSDimitry Andric // char *asctime_r(const struct tm *restrict tm, char *restrict buf);
3543b60736ecSDimitry Andric addToFunctionSummaryMap(
3544b60736ecSDimitry Andric "asctime_r",
3545b60736ecSDimitry Andric Signature(ArgTypes{ConstStructTmPtrRestrictTy, CharPtrRestrictTy},
3546b60736ecSDimitry Andric RetType{CharPtrTy}),
3547b60736ecSDimitry Andric Summary(NoEvalCall)
3548b60736ecSDimitry Andric .ArgConstraint(NotNull(ArgNo(0)))
3549b60736ecSDimitry Andric .ArgConstraint(NotNull(ArgNo(1)))
3550b60736ecSDimitry Andric .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
3551b60736ecSDimitry Andric /*MinBufSize=*/BVF.getValue(26, IntTy))));
3552b60736ecSDimitry Andric
3553b60736ecSDimitry Andric // char *ctime_r(const time_t *timep, char *buf);
3554b60736ecSDimitry Andric addToFunctionSummaryMap(
3555b60736ecSDimitry Andric "ctime_r",
3556b60736ecSDimitry Andric Signature(ArgTypes{ConstTime_tPtrTy, CharPtrTy}, RetType{CharPtrTy}),
3557b60736ecSDimitry Andric Summary(NoEvalCall)
3558b60736ecSDimitry Andric .ArgConstraint(NotNull(ArgNo(0)))
3559b60736ecSDimitry Andric .ArgConstraint(NotNull(ArgNo(1)))
3560b60736ecSDimitry Andric .ArgConstraint(BufferSize(
3561b60736ecSDimitry Andric /*Buffer=*/ArgNo(1),
3562b60736ecSDimitry Andric /*MinBufSize=*/BVF.getValue(26, IntTy))));
3563b60736ecSDimitry Andric
3564b60736ecSDimitry Andric // struct tm *gmtime_r(const time_t *restrict timer,
3565b60736ecSDimitry Andric // struct tm *restrict result);
3566b60736ecSDimitry Andric addToFunctionSummaryMap(
3567b60736ecSDimitry Andric "gmtime_r",
3568b60736ecSDimitry Andric Signature(ArgTypes{ConstTime_tPtrRestrictTy, StructTmPtrRestrictTy},
3569b60736ecSDimitry Andric RetType{StructTmPtrTy}),
3570b60736ecSDimitry Andric Summary(NoEvalCall)
3571b60736ecSDimitry Andric .ArgConstraint(NotNull(ArgNo(0)))
3572b60736ecSDimitry Andric .ArgConstraint(NotNull(ArgNo(1))));
3573b60736ecSDimitry Andric
3574b60736ecSDimitry Andric // struct tm * gmtime(const time_t *tp);
3575b60736ecSDimitry Andric addToFunctionSummaryMap(
3576b60736ecSDimitry Andric "gmtime", Signature(ArgTypes{ConstTime_tPtrTy}, RetType{StructTmPtrTy}),
3577b60736ecSDimitry Andric Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
3578b60736ecSDimitry Andric
3579e3b55780SDimitry Andric std::optional<QualType> Clockid_tTy = lookupTy("clockid_t");
3580b60736ecSDimitry Andric
3581b60736ecSDimitry Andric // int clock_gettime(clockid_t clock_id, struct timespec *tp);
3582b60736ecSDimitry Andric addToFunctionSummaryMap(
3583b60736ecSDimitry Andric "clock_gettime",
3584b60736ecSDimitry Andric Signature(ArgTypes{Clockid_tTy, StructTimespecPtrTy}, RetType{IntTy}),
3585b60736ecSDimitry Andric Summary(NoEvalCall)
35867fa27ce4SDimitry Andric .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
35877fa27ce4SDimitry Andric .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3588b60736ecSDimitry Andric .ArgConstraint(NotNull(ArgNo(1))));
3589b60736ecSDimitry Andric
3590e3b55780SDimitry Andric std::optional<QualType> StructItimervalTy = lookupTy("itimerval");
3591e3b55780SDimitry Andric std::optional<QualType> StructItimervalPtrTy =
3592e3b55780SDimitry Andric getPointerTy(StructItimervalTy);
3593b60736ecSDimitry Andric
3594b60736ecSDimitry Andric // int getitimer(int which, struct itimerval *curr_value);
3595b60736ecSDimitry Andric addToFunctionSummaryMap(
3596b60736ecSDimitry Andric "getitimer",
3597b60736ecSDimitry Andric Signature(ArgTypes{IntTy, StructItimervalPtrTy}, RetType{IntTy}),
3598b60736ecSDimitry Andric Summary(NoEvalCall)
35997fa27ce4SDimitry Andric .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
36007fa27ce4SDimitry Andric .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3601b60736ecSDimitry Andric .ArgConstraint(NotNull(ArgNo(1))));
3602b60736ecSDimitry Andric
3603e3b55780SDimitry Andric std::optional<QualType> Pthread_cond_tTy = lookupTy("pthread_cond_t");
3604e3b55780SDimitry Andric std::optional<QualType> Pthread_cond_tPtrTy =
3605e3b55780SDimitry Andric getPointerTy(Pthread_cond_tTy);
3606e3b55780SDimitry Andric std::optional<QualType> Pthread_tTy = lookupTy("pthread_t");
3607e3b55780SDimitry Andric std::optional<QualType> Pthread_tPtrTy = getPointerTy(Pthread_tTy);
3608e3b55780SDimitry Andric std::optional<QualType> Pthread_tPtrRestrictTy =
3609e3b55780SDimitry Andric getRestrictTy(Pthread_tPtrTy);
3610e3b55780SDimitry Andric std::optional<QualType> Pthread_mutex_tTy = lookupTy("pthread_mutex_t");
3611e3b55780SDimitry Andric std::optional<QualType> Pthread_mutex_tPtrTy =
3612e3b55780SDimitry Andric getPointerTy(Pthread_mutex_tTy);
3613e3b55780SDimitry Andric std::optional<QualType> Pthread_mutex_tPtrRestrictTy =
3614b60736ecSDimitry Andric getRestrictTy(Pthread_mutex_tPtrTy);
3615e3b55780SDimitry Andric std::optional<QualType> Pthread_attr_tTy = lookupTy("pthread_attr_t");
3616e3b55780SDimitry Andric std::optional<QualType> Pthread_attr_tPtrTy =
3617e3b55780SDimitry Andric getPointerTy(Pthread_attr_tTy);
3618e3b55780SDimitry Andric std::optional<QualType> ConstPthread_attr_tPtrTy =
3619b60736ecSDimitry Andric getPointerTy(getConstTy(Pthread_attr_tTy));
3620e3b55780SDimitry Andric std::optional<QualType> ConstPthread_attr_tPtrRestrictTy =
3621b60736ecSDimitry Andric getRestrictTy(ConstPthread_attr_tPtrTy);
3622e3b55780SDimitry Andric std::optional<QualType> Pthread_mutexattr_tTy =
3623e3b55780SDimitry Andric lookupTy("pthread_mutexattr_t");
3624e3b55780SDimitry Andric std::optional<QualType> ConstPthread_mutexattr_tPtrTy =
3625b60736ecSDimitry Andric getPointerTy(getConstTy(Pthread_mutexattr_tTy));
3626e3b55780SDimitry Andric std::optional<QualType> ConstPthread_mutexattr_tPtrRestrictTy =
3627b60736ecSDimitry Andric getRestrictTy(ConstPthread_mutexattr_tPtrTy);
3628b60736ecSDimitry Andric
3629b60736ecSDimitry Andric QualType PthreadStartRoutineTy = getPointerTy(
3630b60736ecSDimitry Andric ACtx.getFunctionType(/*ResultTy=*/VoidPtrTy, /*Args=*/VoidPtrTy,
3631b60736ecSDimitry Andric FunctionProtoType::ExtProtoInfo()));
3632b60736ecSDimitry Andric
3633b60736ecSDimitry Andric // int pthread_cond_signal(pthread_cond_t *cond);
3634b60736ecSDimitry Andric // int pthread_cond_broadcast(pthread_cond_t *cond);
3635b60736ecSDimitry Andric addToFunctionSummaryMap(
3636b60736ecSDimitry Andric {"pthread_cond_signal", "pthread_cond_broadcast"},
3637b60736ecSDimitry Andric Signature(ArgTypes{Pthread_cond_tPtrTy}, RetType{IntTy}),
3638b60736ecSDimitry Andric Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
3639b60736ecSDimitry Andric
3640b60736ecSDimitry Andric // int pthread_create(pthread_t *restrict thread,
3641b60736ecSDimitry Andric // const pthread_attr_t *restrict attr,
3642b60736ecSDimitry Andric // void *(*start_routine)(void*), void *restrict arg);
3643b60736ecSDimitry Andric addToFunctionSummaryMap(
3644b60736ecSDimitry Andric "pthread_create",
3645b60736ecSDimitry Andric Signature(ArgTypes{Pthread_tPtrRestrictTy,
3646b60736ecSDimitry Andric ConstPthread_attr_tPtrRestrictTy,
3647b60736ecSDimitry Andric PthreadStartRoutineTy, VoidPtrRestrictTy},
3648b60736ecSDimitry Andric RetType{IntTy}),
3649b60736ecSDimitry Andric Summary(NoEvalCall)
3650b60736ecSDimitry Andric .ArgConstraint(NotNull(ArgNo(0)))
3651b60736ecSDimitry Andric .ArgConstraint(NotNull(ArgNo(2))));
3652b60736ecSDimitry Andric
3653b60736ecSDimitry Andric // int pthread_attr_destroy(pthread_attr_t *attr);
3654b60736ecSDimitry Andric // int pthread_attr_init(pthread_attr_t *attr);
3655b60736ecSDimitry Andric addToFunctionSummaryMap(
3656b60736ecSDimitry Andric {"pthread_attr_destroy", "pthread_attr_init"},
3657b60736ecSDimitry Andric Signature(ArgTypes{Pthread_attr_tPtrTy}, RetType{IntTy}),
3658b60736ecSDimitry Andric Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
3659b60736ecSDimitry Andric
3660b60736ecSDimitry Andric // int pthread_attr_getstacksize(const pthread_attr_t *restrict attr,
3661b60736ecSDimitry Andric // size_t *restrict stacksize);
3662b60736ecSDimitry Andric // int pthread_attr_getguardsize(const pthread_attr_t *restrict attr,
3663b60736ecSDimitry Andric // size_t *restrict guardsize);
3664b60736ecSDimitry Andric addToFunctionSummaryMap(
3665b60736ecSDimitry Andric {"pthread_attr_getstacksize", "pthread_attr_getguardsize"},
3666b60736ecSDimitry Andric Signature(ArgTypes{ConstPthread_attr_tPtrRestrictTy, SizePtrRestrictTy},
3667b60736ecSDimitry Andric RetType{IntTy}),
3668b60736ecSDimitry Andric Summary(NoEvalCall)
3669b60736ecSDimitry Andric .ArgConstraint(NotNull(ArgNo(0)))
3670b60736ecSDimitry Andric .ArgConstraint(NotNull(ArgNo(1))));
3671b60736ecSDimitry Andric
3672b60736ecSDimitry Andric // int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize);
3673b60736ecSDimitry Andric // int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize);
3674b60736ecSDimitry Andric addToFunctionSummaryMap(
3675b60736ecSDimitry Andric {"pthread_attr_setstacksize", "pthread_attr_setguardsize"},
3676b60736ecSDimitry Andric Signature(ArgTypes{Pthread_attr_tPtrTy, SizeTy}, RetType{IntTy}),
3677b60736ecSDimitry Andric Summary(NoEvalCall)
3678b60736ecSDimitry Andric .ArgConstraint(NotNull(ArgNo(0)))
3679b60736ecSDimitry Andric .ArgConstraint(
3680b60736ecSDimitry Andric ArgumentCondition(1, WithinRange, Range(0, SizeMax))));
3681b60736ecSDimitry Andric
3682b60736ecSDimitry Andric // int pthread_mutex_init(pthread_mutex_t *restrict mutex, const
3683b60736ecSDimitry Andric // pthread_mutexattr_t *restrict attr);
3684b60736ecSDimitry Andric addToFunctionSummaryMap(
3685b60736ecSDimitry Andric "pthread_mutex_init",
3686b60736ecSDimitry Andric Signature(ArgTypes{Pthread_mutex_tPtrRestrictTy,
3687b60736ecSDimitry Andric ConstPthread_mutexattr_tPtrRestrictTy},
3688b60736ecSDimitry Andric RetType{IntTy}),
3689b60736ecSDimitry Andric Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
3690b60736ecSDimitry Andric
3691b60736ecSDimitry Andric // int pthread_mutex_destroy(pthread_mutex_t *mutex);
3692b60736ecSDimitry Andric // int pthread_mutex_lock(pthread_mutex_t *mutex);
3693b60736ecSDimitry Andric // int pthread_mutex_trylock(pthread_mutex_t *mutex);
3694b60736ecSDimitry Andric // int pthread_mutex_unlock(pthread_mutex_t *mutex);
3695b60736ecSDimitry Andric addToFunctionSummaryMap(
3696b60736ecSDimitry Andric {"pthread_mutex_destroy", "pthread_mutex_lock", "pthread_mutex_trylock",
3697b60736ecSDimitry Andric "pthread_mutex_unlock"},
3698b60736ecSDimitry Andric Signature(ArgTypes{Pthread_mutex_tPtrTy}, RetType{IntTy}),
3699b60736ecSDimitry Andric Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
3700cfca06d7SDimitry Andric }
3701cfca06d7SDimitry Andric
3702cfca06d7SDimitry Andric // Functions for testing.
37037fa27ce4SDimitry Andric if (AddTestFunctions) {
37047fa27ce4SDimitry Andric const RangeInt IntMin = BVF.getMinValue(IntTy).getLimitedValue();
37057fa27ce4SDimitry Andric
3706cfca06d7SDimitry Andric addToFunctionSummaryMap(
3707344a3780SDimitry Andric "__not_null", Signature(ArgTypes{IntPtrTy}, RetType{IntTy}),
3708344a3780SDimitry Andric Summary(EvalCallAsPure).ArgConstraint(NotNull(ArgNo(0))));
3709344a3780SDimitry Andric
37107fa27ce4SDimitry Andric addToFunctionSummaryMap(
37117fa27ce4SDimitry Andric "__not_null_buffer",
37127fa27ce4SDimitry Andric Signature(ArgTypes{VoidPtrTy, IntTy, IntTy}, RetType{IntTy}),
37137fa27ce4SDimitry Andric Summary(EvalCallAsPure)
37147fa27ce4SDimitry Andric .ArgConstraint(NotNullBuffer(ArgNo(0), ArgNo(1), ArgNo(2))));
37157fa27ce4SDimitry Andric
37167fa27ce4SDimitry Andric // Test inside range constraints.
3717344a3780SDimitry Andric addToFunctionSummaryMap(
3718e3b55780SDimitry Andric "__single_val_0", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3719e3b55780SDimitry Andric Summary(EvalCallAsPure)
3720e3b55780SDimitry Andric .ArgConstraint(ArgumentCondition(0U, WithinRange, SingleValue(0))));
3721e3b55780SDimitry Andric addToFunctionSummaryMap(
3722344a3780SDimitry Andric "__single_val_1", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3723344a3780SDimitry Andric Summary(EvalCallAsPure)
3724344a3780SDimitry Andric .ArgConstraint(ArgumentCondition(0U, WithinRange, SingleValue(1))));
3725344a3780SDimitry Andric addToFunctionSummaryMap(
3726344a3780SDimitry Andric "__range_1_2", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3727344a3780SDimitry Andric Summary(EvalCallAsPure)
3728344a3780SDimitry Andric .ArgConstraint(ArgumentCondition(0U, WithinRange, Range(1, 2))));
37297fa27ce4SDimitry Andric addToFunctionSummaryMap(
37307fa27ce4SDimitry Andric "__range_m1_1", Signature(ArgTypes{IntTy}, RetType{IntTy}),
37317fa27ce4SDimitry Andric Summary(EvalCallAsPure)
37327fa27ce4SDimitry Andric .ArgConstraint(ArgumentCondition(0U, WithinRange, Range(-1, 1))));
37337fa27ce4SDimitry Andric addToFunctionSummaryMap(
37347fa27ce4SDimitry Andric "__range_m2_m1", Signature(ArgTypes{IntTy}, RetType{IntTy}),
37357fa27ce4SDimitry Andric Summary(EvalCallAsPure)
37367fa27ce4SDimitry Andric .ArgConstraint(ArgumentCondition(0U, WithinRange, Range(-2, -1))));
37377fa27ce4SDimitry Andric addToFunctionSummaryMap(
37387fa27ce4SDimitry Andric "__range_m10_10", Signature(ArgTypes{IntTy}, RetType{IntTy}),
37397fa27ce4SDimitry Andric Summary(EvalCallAsPure)
37407fa27ce4SDimitry Andric .ArgConstraint(ArgumentCondition(0U, WithinRange, Range(-10, 10))));
37417fa27ce4SDimitry Andric addToFunctionSummaryMap("__range_m1_inf",
3742344a3780SDimitry Andric Signature(ArgTypes{IntTy}, RetType{IntTy}),
3743344a3780SDimitry Andric Summary(EvalCallAsPure)
3744344a3780SDimitry Andric .ArgConstraint(ArgumentCondition(
37457fa27ce4SDimitry Andric 0U, WithinRange, Range(-1, IntMax))));
37467fa27ce4SDimitry Andric addToFunctionSummaryMap("__range_0_inf",
37477fa27ce4SDimitry Andric Signature(ArgTypes{IntTy}, RetType{IntTy}),
37487fa27ce4SDimitry Andric Summary(EvalCallAsPure)
37497fa27ce4SDimitry Andric .ArgConstraint(ArgumentCondition(
37507fa27ce4SDimitry Andric 0U, WithinRange, Range(0, IntMax))));
37517fa27ce4SDimitry Andric addToFunctionSummaryMap("__range_1_inf",
37527fa27ce4SDimitry Andric Signature(ArgTypes{IntTy}, RetType{IntTy}),
37537fa27ce4SDimitry Andric Summary(EvalCallAsPure)
37547fa27ce4SDimitry Andric .ArgConstraint(ArgumentCondition(
37557fa27ce4SDimitry Andric 0U, WithinRange, Range(1, IntMax))));
37567fa27ce4SDimitry Andric addToFunctionSummaryMap("__range_minf_m1",
37577fa27ce4SDimitry Andric Signature(ArgTypes{IntTy}, RetType{IntTy}),
37587fa27ce4SDimitry Andric Summary(EvalCallAsPure)
37597fa27ce4SDimitry Andric .ArgConstraint(ArgumentCondition(
37607fa27ce4SDimitry Andric 0U, WithinRange, Range(IntMin, -1))));
37617fa27ce4SDimitry Andric addToFunctionSummaryMap("__range_minf_0",
37627fa27ce4SDimitry Andric Signature(ArgTypes{IntTy}, RetType{IntTy}),
37637fa27ce4SDimitry Andric Summary(EvalCallAsPure)
37647fa27ce4SDimitry Andric .ArgConstraint(ArgumentCondition(
37657fa27ce4SDimitry Andric 0U, WithinRange, Range(IntMin, 0))));
37667fa27ce4SDimitry Andric addToFunctionSummaryMap("__range_minf_1",
37677fa27ce4SDimitry Andric Signature(ArgTypes{IntTy}, RetType{IntTy}),
37687fa27ce4SDimitry Andric Summary(EvalCallAsPure)
37697fa27ce4SDimitry Andric .ArgConstraint(ArgumentCondition(
37707fa27ce4SDimitry Andric 0U, WithinRange, Range(IntMin, 1))));
37717fa27ce4SDimitry Andric addToFunctionSummaryMap("__range_1_2__4_6",
37727fa27ce4SDimitry Andric Signature(ArgTypes{IntTy}, RetType{IntTy}),
37737fa27ce4SDimitry Andric Summary(EvalCallAsPure)
37747fa27ce4SDimitry Andric .ArgConstraint(ArgumentCondition(
37757fa27ce4SDimitry Andric 0U, WithinRange, Range({1, 2}, {4, 6}))));
37767fa27ce4SDimitry Andric addToFunctionSummaryMap(
37777fa27ce4SDimitry Andric "__range_1_2__4_inf", Signature(ArgTypes{IntTy}, RetType{IntTy}),
37787fa27ce4SDimitry Andric Summary(EvalCallAsPure)
37797fa27ce4SDimitry Andric .ArgConstraint(ArgumentCondition(0U, WithinRange,
37807fa27ce4SDimitry Andric Range({1, 2}, {4, IntMax}))));
37817fa27ce4SDimitry Andric
37827fa27ce4SDimitry Andric // Test out of range constraints.
37837fa27ce4SDimitry Andric addToFunctionSummaryMap(
37847fa27ce4SDimitry Andric "__single_val_out_0", Signature(ArgTypes{IntTy}, RetType{IntTy}),
37857fa27ce4SDimitry Andric Summary(EvalCallAsPure)
37867fa27ce4SDimitry Andric .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(0))));
37877fa27ce4SDimitry Andric addToFunctionSummaryMap(
37887fa27ce4SDimitry Andric "__single_val_out_1", Signature(ArgTypes{IntTy}, RetType{IntTy}),
37897fa27ce4SDimitry Andric Summary(EvalCallAsPure)
37907fa27ce4SDimitry Andric .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(1))));
37917fa27ce4SDimitry Andric addToFunctionSummaryMap(
37927fa27ce4SDimitry Andric "__range_out_1_2", Signature(ArgTypes{IntTy}, RetType{IntTy}),
37937fa27ce4SDimitry Andric Summary(EvalCallAsPure)
37947fa27ce4SDimitry Andric .ArgConstraint(ArgumentCondition(0U, OutOfRange, Range(1, 2))));
37957fa27ce4SDimitry Andric addToFunctionSummaryMap(
37967fa27ce4SDimitry Andric "__range_out_m1_1", Signature(ArgTypes{IntTy}, RetType{IntTy}),
37977fa27ce4SDimitry Andric Summary(EvalCallAsPure)
37987fa27ce4SDimitry Andric .ArgConstraint(ArgumentCondition(0U, OutOfRange, Range(-1, 1))));
37997fa27ce4SDimitry Andric addToFunctionSummaryMap(
38007fa27ce4SDimitry Andric "__range_out_m2_m1", Signature(ArgTypes{IntTy}, RetType{IntTy}),
38017fa27ce4SDimitry Andric Summary(EvalCallAsPure)
38027fa27ce4SDimitry Andric .ArgConstraint(ArgumentCondition(0U, OutOfRange, Range(-2, -1))));
38037fa27ce4SDimitry Andric addToFunctionSummaryMap(
38047fa27ce4SDimitry Andric "__range_out_m10_10", Signature(ArgTypes{IntTy}, RetType{IntTy}),
38057fa27ce4SDimitry Andric Summary(EvalCallAsPure)
38067fa27ce4SDimitry Andric .ArgConstraint(ArgumentCondition(0U, OutOfRange, Range(-10, 10))));
38077fa27ce4SDimitry Andric addToFunctionSummaryMap("__range_out_m1_inf",
38087fa27ce4SDimitry Andric Signature(ArgTypes{IntTy}, RetType{IntTy}),
38097fa27ce4SDimitry Andric Summary(EvalCallAsPure)
38107fa27ce4SDimitry Andric .ArgConstraint(ArgumentCondition(
38117fa27ce4SDimitry Andric 0U, OutOfRange, Range(-1, IntMax))));
38127fa27ce4SDimitry Andric addToFunctionSummaryMap("__range_out_0_inf",
38137fa27ce4SDimitry Andric Signature(ArgTypes{IntTy}, RetType{IntTy}),
38147fa27ce4SDimitry Andric Summary(EvalCallAsPure)
38157fa27ce4SDimitry Andric .ArgConstraint(ArgumentCondition(
38167fa27ce4SDimitry Andric 0U, OutOfRange, Range(0, IntMax))));
38177fa27ce4SDimitry Andric addToFunctionSummaryMap("__range_out_1_inf",
38187fa27ce4SDimitry Andric Signature(ArgTypes{IntTy}, RetType{IntTy}),
38197fa27ce4SDimitry Andric Summary(EvalCallAsPure)
38207fa27ce4SDimitry Andric .ArgConstraint(ArgumentCondition(
38217fa27ce4SDimitry Andric 0U, OutOfRange, Range(1, IntMax))));
38227fa27ce4SDimitry Andric addToFunctionSummaryMap("__range_out_minf_m1",
38237fa27ce4SDimitry Andric Signature(ArgTypes{IntTy}, RetType{IntTy}),
38247fa27ce4SDimitry Andric Summary(EvalCallAsPure)
38257fa27ce4SDimitry Andric .ArgConstraint(ArgumentCondition(
38267fa27ce4SDimitry Andric 0U, OutOfRange, Range(IntMin, -1))));
38277fa27ce4SDimitry Andric addToFunctionSummaryMap("__range_out_minf_0",
38287fa27ce4SDimitry Andric Signature(ArgTypes{IntTy}, RetType{IntTy}),
38297fa27ce4SDimitry Andric Summary(EvalCallAsPure)
38307fa27ce4SDimitry Andric .ArgConstraint(ArgumentCondition(
38317fa27ce4SDimitry Andric 0U, OutOfRange, Range(IntMin, 0))));
38327fa27ce4SDimitry Andric addToFunctionSummaryMap("__range_out_minf_1",
38337fa27ce4SDimitry Andric Signature(ArgTypes{IntTy}, RetType{IntTy}),
38347fa27ce4SDimitry Andric Summary(EvalCallAsPure)
38357fa27ce4SDimitry Andric .ArgConstraint(ArgumentCondition(
38367fa27ce4SDimitry Andric 0U, OutOfRange, Range(IntMin, 1))));
38377fa27ce4SDimitry Andric addToFunctionSummaryMap("__range_out_1_2__4_6",
38387fa27ce4SDimitry Andric Signature(ArgTypes{IntTy}, RetType{IntTy}),
38397fa27ce4SDimitry Andric Summary(EvalCallAsPure)
38407fa27ce4SDimitry Andric .ArgConstraint(ArgumentCondition(
38417fa27ce4SDimitry Andric 0U, OutOfRange, Range({1, 2}, {4, 6}))));
38427fa27ce4SDimitry Andric addToFunctionSummaryMap(
38437fa27ce4SDimitry Andric "__range_out_1_2__4_inf", Signature(ArgTypes{IntTy}, RetType{IntTy}),
38447fa27ce4SDimitry Andric Summary(EvalCallAsPure)
38457fa27ce4SDimitry Andric .ArgConstraint(
38467fa27ce4SDimitry Andric ArgumentCondition(0U, OutOfRange, Range({1, 2}, {4, IntMax}))));
3847344a3780SDimitry Andric
3848344a3780SDimitry Andric // Test range kind.
3849344a3780SDimitry Andric addToFunctionSummaryMap(
3850344a3780SDimitry Andric "__within", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3851344a3780SDimitry Andric Summary(EvalCallAsPure)
3852344a3780SDimitry Andric .ArgConstraint(ArgumentCondition(0U, WithinRange, SingleValue(1))));
3853344a3780SDimitry Andric addToFunctionSummaryMap(
3854344a3780SDimitry Andric "__out_of", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3855344a3780SDimitry Andric Summary(EvalCallAsPure)
3856344a3780SDimitry Andric .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(1))));
3857344a3780SDimitry Andric
3858344a3780SDimitry Andric addToFunctionSummaryMap(
3859cfca06d7SDimitry Andric "__two_constrained_args",
3860b60736ecSDimitry Andric Signature(ArgTypes{IntTy, IntTy}, RetType{IntTy}),
3861b60736ecSDimitry Andric Summary(EvalCallAsPure)
3862cfca06d7SDimitry Andric .ArgConstraint(ArgumentCondition(0U, WithinRange, SingleValue(1)))
3863cfca06d7SDimitry Andric .ArgConstraint(ArgumentCondition(1U, WithinRange, SingleValue(1))));
3864cfca06d7SDimitry Andric addToFunctionSummaryMap(
3865b60736ecSDimitry Andric "__arg_constrained_twice", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3866b60736ecSDimitry Andric Summary(EvalCallAsPure)
3867cfca06d7SDimitry Andric .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(1)))
3868cfca06d7SDimitry Andric .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(2))));
3869cfca06d7SDimitry Andric addToFunctionSummaryMap(
3870cfca06d7SDimitry Andric "__defaultparam",
3871b60736ecSDimitry Andric Signature(ArgTypes{Irrelevant, IntTy}, RetType{IntTy}),
3872b60736ecSDimitry Andric Summary(EvalCallAsPure).ArgConstraint(NotNull(ArgNo(0))));
3873b60736ecSDimitry Andric addToFunctionSummaryMap(
3874b60736ecSDimitry Andric "__variadic",
3875b60736ecSDimitry Andric Signature(ArgTypes{VoidPtrTy, ConstCharPtrTy}, RetType{IntTy}),
3876b60736ecSDimitry Andric Summary(EvalCallAsPure)
3877cfca06d7SDimitry Andric .ArgConstraint(NotNull(ArgNo(0)))
3878cfca06d7SDimitry Andric .ArgConstraint(NotNull(ArgNo(1))));
3879cfca06d7SDimitry Andric addToFunctionSummaryMap(
3880cfca06d7SDimitry Andric "__buf_size_arg_constraint",
3881b60736ecSDimitry Andric Signature(ArgTypes{ConstVoidPtrTy, SizeTy}, RetType{IntTy}),
3882b60736ecSDimitry Andric Summary(EvalCallAsPure)
3883cfca06d7SDimitry Andric .ArgConstraint(
3884cfca06d7SDimitry Andric BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1))));
3885cfca06d7SDimitry Andric addToFunctionSummaryMap(
3886cfca06d7SDimitry Andric "__buf_size_arg_constraint_mul",
3887b60736ecSDimitry Andric Signature(ArgTypes{ConstVoidPtrTy, SizeTy, SizeTy}, RetType{IntTy}),
3888b60736ecSDimitry Andric Summary(EvalCallAsPure)
3889cfca06d7SDimitry Andric .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1),
3890cfca06d7SDimitry Andric /*BufSizeMultiplier=*/ArgNo(2))));
3891b60736ecSDimitry Andric addToFunctionSummaryMap(
3892b60736ecSDimitry Andric "__buf_size_arg_constraint_concrete",
3893b60736ecSDimitry Andric Signature(ArgTypes{ConstVoidPtrTy}, RetType{IntTy}),
3894b60736ecSDimitry Andric Summary(EvalCallAsPure)
3895b60736ecSDimitry Andric .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(0),
3896b60736ecSDimitry Andric /*BufSize=*/BVF.getValue(10, IntTy))));
3897b60736ecSDimitry Andric addToFunctionSummaryMap(
3898b60736ecSDimitry Andric {"__test_restrict_param_0", "__test_restrict_param_1",
3899b60736ecSDimitry Andric "__test_restrict_param_2"},
3900b60736ecSDimitry Andric Signature(ArgTypes{VoidPtrRestrictTy}, RetType{VoidTy}),
3901b60736ecSDimitry Andric Summary(EvalCallAsPure));
3902e3b55780SDimitry Andric
3903e3b55780SDimitry Andric // Test the application of cases.
3904e3b55780SDimitry Andric addToFunctionSummaryMap(
3905e3b55780SDimitry Andric "__test_case_note", Signature(ArgTypes{}, RetType{IntTy}),
3906e3b55780SDimitry Andric Summary(EvalCallAsPure)
3907e3b55780SDimitry Andric .Case({ReturnValueCondition(WithinRange, SingleValue(0))},
3908e3b55780SDimitry Andric ErrnoIrrelevant, "Function returns 0")
3909e3b55780SDimitry Andric .Case({ReturnValueCondition(WithinRange, SingleValue(1))},
3910e3b55780SDimitry Andric ErrnoIrrelevant, "Function returns 1"));
39117fa27ce4SDimitry Andric addToFunctionSummaryMap(
39127fa27ce4SDimitry Andric "__test_case_range_1_2__4_6",
39137fa27ce4SDimitry Andric Signature(ArgTypes{IntTy}, RetType{IntTy}),
39147fa27ce4SDimitry Andric Summary(EvalCallAsPure)
39157fa27ce4SDimitry Andric .Case({ArgumentCondition(0U, WithinRange,
39167fa27ce4SDimitry Andric IntRangeVector{{IntMin, 0}, {3, 3}}),
39177fa27ce4SDimitry Andric ReturnValueCondition(WithinRange, SingleValue(1))},
39187fa27ce4SDimitry Andric ErrnoIrrelevant)
39197fa27ce4SDimitry Andric .Case({ArgumentCondition(0U, WithinRange,
39207fa27ce4SDimitry Andric IntRangeVector{{3, 3}, {7, IntMax}}),
39217fa27ce4SDimitry Andric ReturnValueCondition(WithinRange, SingleValue(2))},
39227fa27ce4SDimitry Andric ErrnoIrrelevant)
39237fa27ce4SDimitry Andric .Case({ArgumentCondition(0U, WithinRange,
39247fa27ce4SDimitry Andric IntRangeVector{{IntMin, 0}, {7, IntMax}}),
39257fa27ce4SDimitry Andric ReturnValueCondition(WithinRange, SingleValue(3))},
39267fa27ce4SDimitry Andric ErrnoIrrelevant)
39277fa27ce4SDimitry Andric .Case({ArgumentCondition(
39287fa27ce4SDimitry Andric 0U, WithinRange,
39297fa27ce4SDimitry Andric IntRangeVector{{IntMin, 0}, {3, 3}, {7, IntMax}}),
39307fa27ce4SDimitry Andric ReturnValueCondition(WithinRange, SingleValue(4))},
39317fa27ce4SDimitry Andric ErrnoIrrelevant));
3932cfca06d7SDimitry Andric }
3933bab175ecSDimitry Andric }
3934bab175ecSDimitry Andric
registerStdCLibraryFunctionsChecker(CheckerManager & mgr)3935bab175ecSDimitry Andric void ento::registerStdCLibraryFunctionsChecker(CheckerManager &mgr) {
3936cfca06d7SDimitry Andric auto *Checker = mgr.registerChecker<StdLibraryFunctionsChecker>();
39377fa27ce4SDimitry Andric Checker->CheckName = mgr.getCurrentCheckerName();
3938c0981da4SDimitry Andric const AnalyzerOptions &Opts = mgr.getAnalyzerOptions();
3939cfca06d7SDimitry Andric Checker->DisplayLoadedSummaries =
3940c0981da4SDimitry Andric Opts.getCheckerBooleanOption(Checker, "DisplayLoadedSummaries");
3941c0981da4SDimitry Andric Checker->ModelPOSIX = Opts.getCheckerBooleanOption(Checker, "ModelPOSIX");
3942c0981da4SDimitry Andric Checker->ShouldAssumeControlledEnvironment =
3943c0981da4SDimitry Andric Opts.ShouldAssumeControlledEnvironment;
3944bab175ecSDimitry Andric }
394522989816SDimitry Andric
shouldRegisterStdCLibraryFunctionsChecker(const CheckerManager & mgr)3946b60736ecSDimitry Andric bool ento::shouldRegisterStdCLibraryFunctionsChecker(
3947b60736ecSDimitry Andric const CheckerManager &mgr) {
394822989816SDimitry Andric return true;
394922989816SDimitry Andric }
3950cfca06d7SDimitry Andric
registerStdCLibraryFunctionsTesterChecker(CheckerManager & mgr)39517fa27ce4SDimitry Andric void ento::registerStdCLibraryFunctionsTesterChecker(CheckerManager &mgr) {
39527fa27ce4SDimitry Andric auto *Checker = mgr.getChecker<StdLibraryFunctionsChecker>();
39537fa27ce4SDimitry Andric Checker->AddTestFunctions = true;
39547fa27ce4SDimitry Andric }
3955cfca06d7SDimitry Andric
shouldRegisterStdCLibraryFunctionsTesterChecker(const CheckerManager & mgr)39567fa27ce4SDimitry Andric bool ento::shouldRegisterStdCLibraryFunctionsTesterChecker(
39577fa27ce4SDimitry Andric const CheckerManager &mgr) {
39587fa27ce4SDimitry Andric return true;
39597fa27ce4SDimitry Andric }
3960