1bba497fbSArtem Dergachev //=== StdLibraryFunctionsChecker.cpp - Model standard functions -*- C++ -*-===//
2bba497fbSArtem Dergachev //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6bba497fbSArtem Dergachev //
7bba497fbSArtem Dergachev //===----------------------------------------------------------------------===//
8bba497fbSArtem Dergachev //
9bba497fbSArtem Dergachev // This checker improves modeling of a few simple library functions.
10bba497fbSArtem Dergachev //
11f5086b38SGabor Marton // This checker provides a specification format - `Summary' - and
12bba497fbSArtem Dergachev // contains descriptions of some library functions in this format. Each
13bba497fbSArtem Dergachev // specification contains a list of branches for splitting the program state
14bba497fbSArtem Dergachev // upon call, and range constraints on argument and return-value symbols that
15bba497fbSArtem Dergachev // are satisfied on each branch. This spec can be expanded to include more
16bba497fbSArtem Dergachev // items, like external effects of the function.
17bba497fbSArtem Dergachev //
18bba497fbSArtem Dergachev // The main difference between this approach and the body farms technique is
19bba497fbSArtem Dergachev // in more explicit control over how many branches are produced. For example,
20bba497fbSArtem Dergachev // consider standard C function `ispunct(int x)', which returns a non-zero value
21bba497fbSArtem Dergachev // iff `x' is a punctuation character, that is, when `x' is in range
22bba497fbSArtem Dergachev // ['!', '/'] [':', '@'] U ['[', '\`'] U ['{', '~'].
23f5086b38SGabor Marton // `Summary' provides only two branches for this function. However,
24bba497fbSArtem Dergachev // any attempt to describe this range with if-statements in the body farm
25bba497fbSArtem Dergachev // would result in many more branches. Because each branch needs to be analyzed
26bba497fbSArtem Dergachev // independently, this significantly reduces performance. Additionally,
27bba497fbSArtem Dergachev // once we consider a branch on which `x' is in range, say, ['!', '/'],
28bba497fbSArtem Dergachev // we assume that such branch is an important separate path through the program,
29bba497fbSArtem Dergachev // which may lead to false positives because considering this particular path
30bba497fbSArtem Dergachev // was not consciously intended, and therefore it might have been unreachable.
31bba497fbSArtem Dergachev //
32f5086b38SGabor Marton // This checker uses eval::Call for modeling pure functions (functions without
33f5086b38SGabor Marton // side effets), for which their `Summary' is a precise model. This avoids
34f5086b38SGabor Marton // unnecessary invalidation passes. Conflicts with other checkers are unlikely
35f5086b38SGabor Marton // because if the function has no other effects, other checkers would probably
36f5086b38SGabor Marton // never want to improve upon the modeling done by this checker.
37bba497fbSArtem Dergachev //
38f5086b38SGabor Marton // Non-pure functions, for which only partial improvement over the default
39bba497fbSArtem Dergachev // behavior is expected, are modeled via check::PostCall, non-intrusively.
40bba497fbSArtem Dergachev //
41bba497fbSArtem Dergachev //===----------------------------------------------------------------------===//
42bba497fbSArtem Dergachev
43957014daSBalázs Kéri #include "ErrnoModeling.h"
4476a21502SKristof Umann #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
4594061df6SGabor Marton #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
46bba497fbSArtem Dergachev #include "clang/StaticAnalyzer/Core/Checker.h"
47bba497fbSArtem Dergachev #include "clang/StaticAnalyzer/Core/CheckerManager.h"
48bba497fbSArtem Dergachev #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
49bba497fbSArtem Dergachev #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
50536456a7SGabor Marton #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h"
519b3df78bSCharusso #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicExtent.h"
52a7cb951fSGabor Marton #include "llvm/ADT/SmallString.h"
53a7cb951fSGabor Marton #include "llvm/ADT/StringExtras.h"
54a7cb951fSGabor Marton
55a7cb951fSGabor Marton #include <string>
56bba497fbSArtem Dergachev
57bba497fbSArtem Dergachev using namespace clang;
58bba497fbSArtem Dergachev using namespace clang::ento;
59bba497fbSArtem Dergachev
60957014daSBalázs Kéri /// Produce a textual description of the state of \c errno (this describes the
61957014daSBalázs Kéri /// way how it is allowed to be used).
62957014daSBalázs Kéri /// The returned string is insertable into a longer warning message (in the form
63957014daSBalázs Kéri /// "the value 'errno' <...>").
64957014daSBalázs Kéri /// Currently only the \c errno_modeling::MustNotBeChecked state is supported.
65957014daSBalázs Kéri /// But later other kind of errno state may be needed if functions with special
66957014daSBalázs Kéri /// handling of \c errno are added.
describeErrnoCheckState(errno_modeling::ErrnoCheckState CS)67957014daSBalázs Kéri static const char *describeErrnoCheckState(errno_modeling::ErrnoCheckState CS) {
68957014daSBalázs Kéri assert(CS == errno_modeling::MustNotBeChecked &&
69957014daSBalázs Kéri "Errno description not applicable.");
70957014daSBalázs Kéri return "may be undefined after the call and should not be used";
71957014daSBalázs Kéri }
72957014daSBalázs Kéri
73bba497fbSArtem Dergachev namespace {
7494061df6SGabor Marton class StdLibraryFunctionsChecker
7594061df6SGabor Marton : public Checker<check::PreCall, check::PostCall, eval::Call> {
7616506d78SGabor Marton
7716506d78SGabor Marton class Summary;
78bba497fbSArtem Dergachev
79bba497fbSArtem Dergachev /// Specify how much the analyzer engine should entrust modeling this function
80bba497fbSArtem Dergachev /// to us. If he doesn't, he performs additional invalidations.
81f5086b38SGabor Marton enum InvalidationKind { NoEvalCall, EvalCallAsPure };
82bba497fbSArtem Dergachev
8347fec16cSArtem Dergachev // The universal integral type to use in value range descriptions.
8447fec16cSArtem Dergachev // Unsigned to make sure overflows are well-defined.
85f5086b38SGabor Marton typedef uint64_t RangeInt;
8647fec16cSArtem Dergachev
87bba497fbSArtem Dergachev /// Normally, describes a single range constraint, eg. {{0, 1}, {3, 4}} is
88bba497fbSArtem Dergachev /// a non-negative integer, which less than 5 and not equal to 2. For
89bba497fbSArtem Dergachev /// `ComparesToArgument', holds information about how exactly to compare to
90bba497fbSArtem Dergachev /// the argument.
91f5086b38SGabor Marton typedef std::vector<std::pair<RangeInt, RangeInt>> IntRangeVector;
92bba497fbSArtem Dergachev
93bba497fbSArtem Dergachev /// A reference to an argument or return value by its number.
94bba497fbSArtem Dergachev /// ArgNo in CallExpr and CallEvent is defined as Unsigned, but
95bba497fbSArtem Dergachev /// obviously uint32_t should be enough for all practical purposes.
96f5086b38SGabor Marton typedef uint32_t ArgNo;
97c6b8484eSGabor Marton static const ArgNo Ret;
98bba497fbSArtem Dergachev
99a7cb951fSGabor Marton /// Returns the string representation of an argument index.
100a7cb951fSGabor Marton /// E.g.: (1) -> '1st arg', (2) - > '2nd arg'
101a7cb951fSGabor Marton static SmallString<8> getArgDesc(ArgNo);
102a7cb951fSGabor Marton
10394061df6SGabor Marton class ValueConstraint;
10494061df6SGabor Marton
10594061df6SGabor Marton // Pointer to the ValueConstraint. We need a copyable, polymorphic and
10694061df6SGabor Marton // default initialize able type (vector needs that). A raw pointer was good,
10794061df6SGabor Marton // however, we cannot default initialize that. unique_ptr makes the Summary
10894061df6SGabor Marton // class non-copyable, therefore not an option. Releasing the copyability
10994061df6SGabor Marton // requirement would render the initialization of the Summary map infeasible.
11094061df6SGabor Marton using ValueConstraintPtr = std::shared_ptr<ValueConstraint>;
11194061df6SGabor Marton
112c6b8484eSGabor Marton /// Polymorphic base class that represents a constraint on a given argument
113c6b8484eSGabor Marton /// (or return value) of a function. Derived classes implement different kind
114c6b8484eSGabor Marton /// of constraints, e.g range constraints or correlation between two
115c6b8484eSGabor Marton /// arguments.
116c6b8484eSGabor Marton class ValueConstraint {
117c6b8484eSGabor Marton public:
ValueConstraint(ArgNo ArgN)118c6b8484eSGabor Marton ValueConstraint(ArgNo ArgN) : ArgN(ArgN) {}
~ValueConstraint()119c6b8484eSGabor Marton virtual ~ValueConstraint() {}
120c6b8484eSGabor Marton /// Apply the effects of the constraint on the given program state. If null
121c6b8484eSGabor Marton /// is returned then the constraint is not feasible.
122c6b8484eSGabor Marton virtual ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
123bd03ef19SGabor Marton const Summary &Summary,
124bd03ef19SGabor Marton CheckerContext &C) const = 0;
negate() const12594061df6SGabor Marton virtual ValueConstraintPtr negate() const {
12694061df6SGabor Marton llvm_unreachable("Not implemented");
12794061df6SGabor Marton };
12816506d78SGabor Marton
12916506d78SGabor Marton // Check whether the constraint is malformed or not. It is malformed if the
13016506d78SGabor Marton // specified argument has a mismatch with the given FunctionDecl (e.g. the
13116506d78SGabor Marton // arg number is out-of-range of the function's argument list).
checkValidity(const FunctionDecl * FD) const13216506d78SGabor Marton bool checkValidity(const FunctionDecl *FD) const {
13316506d78SGabor Marton const bool ValidArg = ArgN == Ret || ArgN < FD->getNumParams();
13416506d78SGabor Marton assert(ValidArg && "Arg out of range!");
13516506d78SGabor Marton if (!ValidArg)
13616506d78SGabor Marton return false;
13716506d78SGabor Marton // Subclasses may further refine the validation.
13816506d78SGabor Marton return checkSpecificValidity(FD);
13916506d78SGabor Marton }
getArgNo() const140c6b8484eSGabor Marton ArgNo getArgNo() const { return ArgN; }
141c6b8484eSGabor Marton
1424b99f9c7SGabor Marton // Return those arguments that should be tracked when we report a bug. By
1434b99f9c7SGabor Marton // default it is the argument that is constrained, however, in some special
1444b99f9c7SGabor Marton // cases we need to track other arguments as well. E.g. a buffer size might
1454b99f9c7SGabor Marton // be encoded in another argument.
getArgsToTrack() const1464b99f9c7SGabor Marton virtual std::vector<ArgNo> getArgsToTrack() const { return {ArgN}; }
1474b99f9c7SGabor Marton
148a97648b9SGabor Marton virtual StringRef getName() const = 0;
149a97648b9SGabor Marton
150a7cb951fSGabor Marton // Give a description that explains the constraint to the user. Used when
151a7cb951fSGabor Marton // the bug is reported.
describe(ProgramStateRef State,const Summary & Summary) const152a7cb951fSGabor Marton virtual std::string describe(ProgramStateRef State,
153a7cb951fSGabor Marton const Summary &Summary) const {
154a7cb951fSGabor Marton // There are some descendant classes that are not used as argument
155a7cb951fSGabor Marton // constraints, e.g. ComparisonConstraint. In that case we can safely
156a7cb951fSGabor Marton // ignore the implementation of this function.
157a7cb951fSGabor Marton llvm_unreachable("Not implemented");
158a7cb951fSGabor Marton }
159a7cb951fSGabor Marton
160c6b8484eSGabor Marton protected:
161c6b8484eSGabor Marton ArgNo ArgN; // Argument to which we apply the constraint.
16216506d78SGabor Marton
163d8e5a0c4SZarko Todorovski /// Do polymorphic validation check on the constraint.
checkSpecificValidity(const FunctionDecl * FD) const16416506d78SGabor Marton virtual bool checkSpecificValidity(const FunctionDecl *FD) const {
16516506d78SGabor Marton return true;
16616506d78SGabor Marton }
167c6b8484eSGabor Marton };
168c6b8484eSGabor Marton
169c6b8484eSGabor Marton /// Given a range, should the argument stay inside or outside this range?
170c6b8484eSGabor Marton enum RangeKind { OutOfRange, WithinRange };
171c6b8484eSGabor Marton
172a787a4edSGabor Marton /// Encapsulates a range on a single symbol.
173c6b8484eSGabor Marton class RangeConstraint : public ValueConstraint {
174a787a4edSGabor Marton RangeKind Kind;
175a787a4edSGabor Marton // A range is formed as a set of intervals (sub-ranges).
176a787a4edSGabor Marton // E.g. {['A', 'Z'], ['a', 'z']}
177a787a4edSGabor Marton //
178a787a4edSGabor Marton // The default constructed RangeConstraint has an empty range set, applying
179a787a4edSGabor Marton // such constraint does not involve any assumptions, thus the State remains
180a787a4edSGabor Marton // unchanged. This is meaningful, if the range is dependent on a looked up
181a787a4edSGabor Marton // type (e.g. [0, Socklen_tMax]). If the type is not found, then the range
182a787a4edSGabor Marton // is default initialized to be empty.
183a787a4edSGabor Marton IntRangeVector Ranges;
184bba497fbSArtem Dergachev
185bba497fbSArtem Dergachev public:
getName() const186a97648b9SGabor Marton StringRef getName() const override { return "Range"; }
RangeConstraint(ArgNo ArgN,RangeKind Kind,const IntRangeVector & Ranges)187a787a4edSGabor Marton RangeConstraint(ArgNo ArgN, RangeKind Kind, const IntRangeVector &Ranges)
188a787a4edSGabor Marton : ValueConstraint(ArgN), Kind(Kind), Ranges(Ranges) {}
189bba497fbSArtem Dergachev
190a7cb951fSGabor Marton std::string describe(ProgramStateRef State,
191a7cb951fSGabor Marton const Summary &Summary) const override;
192a7cb951fSGabor Marton
getRanges() const193a787a4edSGabor Marton const IntRangeVector &getRanges() const { return Ranges; }
194bba497fbSArtem Dergachev
195bba497fbSArtem Dergachev private:
196f5086b38SGabor Marton ProgramStateRef applyAsOutOfRange(ProgramStateRef State,
197f5086b38SGabor Marton const CallEvent &Call,
198f5086b38SGabor Marton const Summary &Summary) const;
199f5086b38SGabor Marton ProgramStateRef applyAsWithinRange(ProgramStateRef State,
200f5086b38SGabor Marton const CallEvent &Call,
201f5086b38SGabor Marton const Summary &Summary) const;
20225bbe234SZurab Tsinadze
203bba497fbSArtem Dergachev public:
apply(ProgramStateRef State,const CallEvent & Call,const Summary & Summary,CheckerContext & C) const204bba497fbSArtem Dergachev ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
205bd03ef19SGabor Marton const Summary &Summary,
206bd03ef19SGabor Marton CheckerContext &C) const override {
207bba497fbSArtem Dergachev switch (Kind) {
208bba497fbSArtem Dergachev case OutOfRange:
209bba497fbSArtem Dergachev return applyAsOutOfRange(State, Call, Summary);
210bba497fbSArtem Dergachev case WithinRange:
211bba497fbSArtem Dergachev return applyAsWithinRange(State, Call, Summary);
212bba497fbSArtem Dergachev }
213c6b8484eSGabor Marton llvm_unreachable("Unknown range kind!");
214bba497fbSArtem Dergachev }
21594061df6SGabor Marton
negate() const21694061df6SGabor Marton ValueConstraintPtr negate() const override {
21794061df6SGabor Marton RangeConstraint Tmp(*this);
21894061df6SGabor Marton switch (Kind) {
21994061df6SGabor Marton case OutOfRange:
22094061df6SGabor Marton Tmp.Kind = WithinRange;
22194061df6SGabor Marton break;
22294061df6SGabor Marton case WithinRange:
22394061df6SGabor Marton Tmp.Kind = OutOfRange;
22494061df6SGabor Marton break;
22594061df6SGabor Marton }
22694061df6SGabor Marton return std::make_shared<RangeConstraint>(Tmp);
22794061df6SGabor Marton }
22816506d78SGabor Marton
checkSpecificValidity(const FunctionDecl * FD) const22916506d78SGabor Marton bool checkSpecificValidity(const FunctionDecl *FD) const override {
23016506d78SGabor Marton const bool ValidArg =
23116506d78SGabor Marton getArgType(FD, ArgN)->isIntegralType(FD->getASTContext());
23216506d78SGabor Marton assert(ValidArg &&
23316506d78SGabor Marton "This constraint should be applied on an integral type");
23416506d78SGabor Marton return ValidArg;
23516506d78SGabor Marton }
236bba497fbSArtem Dergachev };
237bba497fbSArtem Dergachev
238c6b8484eSGabor Marton class ComparisonConstraint : public ValueConstraint {
239c6b8484eSGabor Marton BinaryOperator::Opcode Opcode;
240c6b8484eSGabor Marton ArgNo OtherArgN;
241c6b8484eSGabor Marton
242c6b8484eSGabor Marton public:
getName() const243*a210f404SKazu Hirata StringRef getName() const override { return "Comparison"; };
ComparisonConstraint(ArgNo ArgN,BinaryOperator::Opcode Opcode,ArgNo OtherArgN)244c6b8484eSGabor Marton ComparisonConstraint(ArgNo ArgN, BinaryOperator::Opcode Opcode,
245c6b8484eSGabor Marton ArgNo OtherArgN)
246c6b8484eSGabor Marton : ValueConstraint(ArgN), Opcode(Opcode), OtherArgN(OtherArgN) {}
getOtherArgNo() const247c6b8484eSGabor Marton ArgNo getOtherArgNo() const { return OtherArgN; }
getOpcode() const248c6b8484eSGabor Marton BinaryOperator::Opcode getOpcode() const { return Opcode; }
249c6b8484eSGabor Marton ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
250bd03ef19SGabor Marton const Summary &Summary,
251bd03ef19SGabor Marton CheckerContext &C) const override;
252c6b8484eSGabor Marton };
253c6b8484eSGabor Marton
254ededa65dSGabor Marton class NotNullConstraint : public ValueConstraint {
255ededa65dSGabor Marton using ValueConstraint::ValueConstraint;
256ededa65dSGabor Marton // This variable has a role when we negate the constraint.
257ededa65dSGabor Marton bool CannotBeNull = true;
258ededa65dSGabor Marton
259ededa65dSGabor Marton public:
260a7cb951fSGabor Marton std::string describe(ProgramStateRef State,
261a7cb951fSGabor Marton const Summary &Summary) const override;
getName() const262a97648b9SGabor Marton StringRef getName() const override { return "NonNull"; }
apply(ProgramStateRef State,const CallEvent & Call,const Summary & Summary,CheckerContext & C) const263ededa65dSGabor Marton ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
264bd03ef19SGabor Marton const Summary &Summary,
265bd03ef19SGabor Marton CheckerContext &C) const override {
266ededa65dSGabor Marton SVal V = getArgSVal(Call, getArgNo());
267defd95efSVince Bridgers if (V.isUndef())
268defd95efSVince Bridgers return State;
269defd95efSVince Bridgers
270ededa65dSGabor Marton DefinedOrUnknownSVal L = V.castAs<DefinedOrUnknownSVal>();
27196ccb690SBalazs Benics if (!isa<Loc>(L))
272ededa65dSGabor Marton return State;
273ededa65dSGabor Marton
274ededa65dSGabor Marton return State->assume(L, CannotBeNull);
275ededa65dSGabor Marton }
276ededa65dSGabor Marton
negate() const277ededa65dSGabor Marton ValueConstraintPtr negate() const override {
278ededa65dSGabor Marton NotNullConstraint Tmp(*this);
279ededa65dSGabor Marton Tmp.CannotBeNull = !this->CannotBeNull;
280ededa65dSGabor Marton return std::make_shared<NotNullConstraint>(Tmp);
281ededa65dSGabor Marton }
28216506d78SGabor Marton
checkSpecificValidity(const FunctionDecl * FD) const28316506d78SGabor Marton bool checkSpecificValidity(const FunctionDecl *FD) const override {
28416506d78SGabor Marton const bool ValidArg = getArgType(FD, ArgN)->isPointerType();
28516506d78SGabor Marton assert(ValidArg &&
28616506d78SGabor Marton "This constraint should be applied only on a pointer type");
28716506d78SGabor Marton return ValidArg;
28816506d78SGabor Marton }
289ededa65dSGabor Marton };
290ededa65dSGabor Marton
291f0b9dbcfSGabor Marton // Represents a buffer argument with an additional size constraint. The
292f0b9dbcfSGabor Marton // constraint may be a concrete value, or a symbolic value in an argument.
293f0b9dbcfSGabor Marton // Example 1. Concrete value as the minimum buffer size.
294f0b9dbcfSGabor Marton // char *asctime_r(const struct tm *restrict tm, char *restrict buf);
295f0b9dbcfSGabor Marton // // `buf` size must be at least 26 bytes according the POSIX standard.
296f0b9dbcfSGabor Marton // Example 2. Argument as a buffer size.
297bd03ef19SGabor Marton // ctime_s(char *buffer, rsize_t bufsz, const time_t *time);
298f0b9dbcfSGabor Marton // Example 3. The size is computed as a multiplication of other args.
29941928c97SGabor Marton // size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
30041928c97SGabor Marton // // Here, ptr is the buffer, and its minimum size is `size * nmemb`.
301bd03ef19SGabor Marton class BufferSizeConstraint : public ValueConstraint {
302f0b9dbcfSGabor Marton // The concrete value which is the minimum size for the buffer.
303f0b9dbcfSGabor Marton llvm::Optional<llvm::APSInt> ConcreteSize;
304bd03ef19SGabor Marton // The argument which holds the size of the buffer.
305f0b9dbcfSGabor Marton llvm::Optional<ArgNo> SizeArgN;
30641928c97SGabor Marton // The argument which is a multiplier to size. This is set in case of
30741928c97SGabor Marton // `fread` like functions where the size is computed as a multiplication of
30841928c97SGabor Marton // two arguments.
30941928c97SGabor Marton llvm::Optional<ArgNo> SizeMultiplierArgN;
310bd03ef19SGabor Marton // The operator we use in apply. This is negated in negate().
311bd03ef19SGabor Marton BinaryOperator::Opcode Op = BO_LE;
312bd03ef19SGabor Marton
313bd03ef19SGabor Marton public:
getName() const314a97648b9SGabor Marton StringRef getName() const override { return "BufferSize"; }
BufferSizeConstraint(ArgNo Buffer,llvm::APSInt BufMinSize)315f0b9dbcfSGabor Marton BufferSizeConstraint(ArgNo Buffer, llvm::APSInt BufMinSize)
316f0b9dbcfSGabor Marton : ValueConstraint(Buffer), ConcreteSize(BufMinSize) {}
BufferSizeConstraint(ArgNo Buffer,ArgNo BufSize)317bd03ef19SGabor Marton BufferSizeConstraint(ArgNo Buffer, ArgNo BufSize)
318bd03ef19SGabor Marton : ValueConstraint(Buffer), SizeArgN(BufSize) {}
BufferSizeConstraint(ArgNo Buffer,ArgNo BufSize,ArgNo BufSizeMultiplier)31941928c97SGabor Marton BufferSizeConstraint(ArgNo Buffer, ArgNo BufSize, ArgNo BufSizeMultiplier)
32041928c97SGabor Marton : ValueConstraint(Buffer), SizeArgN(BufSize),
32141928c97SGabor Marton SizeMultiplierArgN(BufSizeMultiplier) {}
32241928c97SGabor Marton
getArgsToTrack() const3234b99f9c7SGabor Marton std::vector<ArgNo> getArgsToTrack() const override {
3244b99f9c7SGabor Marton std::vector<ArgNo> Result{ArgN};
3254b99f9c7SGabor Marton if (SizeArgN)
3264b99f9c7SGabor Marton Result.push_back(*SizeArgN);
3274b99f9c7SGabor Marton if (SizeMultiplierArgN)
3284b99f9c7SGabor Marton Result.push_back(*SizeMultiplierArgN);
3294b99f9c7SGabor Marton return Result;
3304b99f9c7SGabor Marton }
3314b99f9c7SGabor Marton
332a7cb951fSGabor Marton std::string describe(ProgramStateRef State,
333a7cb951fSGabor Marton const Summary &Summary) const override;
334a7cb951fSGabor Marton
apply(ProgramStateRef State,const CallEvent & Call,const Summary & Summary,CheckerContext & C) const335bd03ef19SGabor Marton ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
336bd03ef19SGabor Marton const Summary &Summary,
337bd03ef19SGabor Marton CheckerContext &C) const override {
33841928c97SGabor Marton SValBuilder &SvalBuilder = C.getSValBuilder();
339bd03ef19SGabor Marton // The buffer argument.
340bd03ef19SGabor Marton SVal BufV = getArgSVal(Call, getArgNo());
341f0b9dbcfSGabor Marton
342f0b9dbcfSGabor Marton // Get the size constraint.
343f0b9dbcfSGabor Marton const SVal SizeV = [this, &State, &Call, &Summary, &SvalBuilder]() {
344f0b9dbcfSGabor Marton if (ConcreteSize) {
345f0b9dbcfSGabor Marton return SVal(SvalBuilder.makeIntVal(*ConcreteSize));
346a7cb951fSGabor Marton }
347a7cb951fSGabor Marton assert(SizeArgN && "The constraint must be either a concrete value or "
348a7cb951fSGabor Marton "encoded in an argument.");
349bd03ef19SGabor Marton // The size argument.
350f0b9dbcfSGabor Marton SVal SizeV = getArgSVal(Call, *SizeArgN);
35141928c97SGabor Marton // Multiply with another argument if given.
35241928c97SGabor Marton if (SizeMultiplierArgN) {
35341928c97SGabor Marton SVal SizeMulV = getArgSVal(Call, *SizeMultiplierArgN);
35441928c97SGabor Marton SizeV = SvalBuilder.evalBinOp(State, BO_Mul, SizeV, SizeMulV,
355f0b9dbcfSGabor Marton Summary.getArgType(*SizeArgN));
35641928c97SGabor Marton }
357f0b9dbcfSGabor Marton return SizeV;
358f0b9dbcfSGabor Marton }();
359f0b9dbcfSGabor Marton
360bd03ef19SGabor Marton // The dynamic size of the buffer argument, got from the analyzer engine.
3619b3df78bSCharusso SVal BufDynSize = getDynamicExtentWithOffset(State, BufV);
362bd03ef19SGabor Marton
363bd03ef19SGabor Marton SVal Feasible = SvalBuilder.evalBinOp(State, Op, SizeV, BufDynSize,
364bd03ef19SGabor Marton SvalBuilder.getContext().BoolTy);
365bd03ef19SGabor Marton if (auto F = Feasible.getAs<DefinedOrUnknownSVal>())
366bd03ef19SGabor Marton return State->assume(*F, true);
367bd03ef19SGabor Marton
368bd03ef19SGabor Marton // We can get here only if the size argument or the dynamic size is
369bd03ef19SGabor Marton // undefined. But the dynamic size should never be undefined, only
370bd03ef19SGabor Marton // unknown. So, here, the size of the argument is undefined, i.e. we
371bd03ef19SGabor Marton // cannot apply the constraint. Actually, other checkers like
372bd03ef19SGabor Marton // CallAndMessage should catch this situation earlier, because we call a
373bd03ef19SGabor Marton // function with an uninitialized argument.
374bd03ef19SGabor Marton llvm_unreachable("Size argument or the dynamic size is Undefined");
375bd03ef19SGabor Marton }
376bd03ef19SGabor Marton
negate() const377bd03ef19SGabor Marton ValueConstraintPtr negate() const override {
378bd03ef19SGabor Marton BufferSizeConstraint Tmp(*this);
379bd03ef19SGabor Marton Tmp.Op = BinaryOperator::negateComparisonOp(Op);
380bd03ef19SGabor Marton return std::make_shared<BufferSizeConstraint>(Tmp);
381bd03ef19SGabor Marton }
3823ff220deSGabor Marton
checkSpecificValidity(const FunctionDecl * FD) const3833ff220deSGabor Marton bool checkSpecificValidity(const FunctionDecl *FD) const override {
3843ff220deSGabor Marton const bool ValidArg = getArgType(FD, ArgN)->isPointerType();
3853ff220deSGabor Marton assert(ValidArg &&
3863ff220deSGabor Marton "This constraint should be applied only on a pointer type");
3873ff220deSGabor Marton return ValidArg;
3883ff220deSGabor Marton }
389bd03ef19SGabor Marton };
390bd03ef19SGabor Marton
391c6b8484eSGabor Marton /// The complete list of constraints that defines a single branch.
392f68c0a2fSArtem Dergachev using ConstraintSet = std::vector<ValueConstraintPtr>;
393f68c0a2fSArtem Dergachev
394957014daSBalázs Kéri /// Define how a function affects the system variable 'errno'.
395957014daSBalázs Kéri /// This works together with the ErrnoModeling and ErrnoChecker classes.
396957014daSBalázs Kéri class ErrnoConstraintBase {
397957014daSBalázs Kéri public:
398957014daSBalázs Kéri /// Apply specific state changes related to the errno variable.
399957014daSBalázs Kéri virtual ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
400957014daSBalázs Kéri const Summary &Summary,
401957014daSBalázs Kéri CheckerContext &C) const = 0;
402957014daSBalázs Kéri /// Get a description about what is applied to 'errno' and how is it allowed
403957014daSBalázs Kéri /// to be used. If ErrnoChecker generates a bug then this message is
404957014daSBalázs Kéri /// displayed as a note at the function call.
405957014daSBalázs Kéri /// It may return empty string if no note tag is to be added.
describe(StringRef FunctionName) const406957014daSBalázs Kéri virtual std::string describe(StringRef FunctionName) const { return ""; }
407957014daSBalázs Kéri
~ErrnoConstraintBase()408957014daSBalázs Kéri virtual ~ErrnoConstraintBase() {}
409957014daSBalázs Kéri
410957014daSBalázs Kéri protected:
411957014daSBalázs Kéri /// Many of the descendant classes use this value.
412957014daSBalázs Kéri const errno_modeling::ErrnoCheckState CheckState;
413957014daSBalázs Kéri
ErrnoConstraintBase(errno_modeling::ErrnoCheckState CS)414957014daSBalázs Kéri ErrnoConstraintBase(errno_modeling::ErrnoCheckState CS) : CheckState(CS) {}
415957014daSBalázs Kéri
416957014daSBalázs Kéri /// This is used for conjure symbol for errno to differentiate from the
417957014daSBalázs Kéri /// original call expression (same expression is used for the errno symbol).
418957014daSBalázs Kéri static int Tag;
419957014daSBalázs Kéri };
420957014daSBalázs Kéri
421957014daSBalázs Kéri /// Set value of 'errno' to be related to 0 in a specified way, with a
422957014daSBalázs Kéri /// specified "errno check state". For example with \c BO_GT 'errno' is
423957014daSBalázs Kéri /// constrained to be greater than 0. Use this for failure cases of functions.
424957014daSBalázs Kéri class ZeroRelatedErrnoConstraint : public ErrnoConstraintBase {
425957014daSBalázs Kéri BinaryOperatorKind Op;
426957014daSBalázs Kéri
427957014daSBalázs Kéri public:
ZeroRelatedErrnoConstraint(clang::BinaryOperatorKind OpK,errno_modeling::ErrnoCheckState CS)428957014daSBalázs Kéri ZeroRelatedErrnoConstraint(clang::BinaryOperatorKind OpK,
429957014daSBalázs Kéri errno_modeling::ErrnoCheckState CS)
430957014daSBalázs Kéri : ErrnoConstraintBase(CS), Op(OpK) {
431957014daSBalázs Kéri assert(BinaryOperator::isComparisonOp(OpK));
432957014daSBalázs Kéri }
433957014daSBalázs Kéri
apply(ProgramStateRef State,const CallEvent & Call,const Summary & Summary,CheckerContext & C) const434957014daSBalázs Kéri ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
435957014daSBalázs Kéri const Summary &Summary,
436957014daSBalázs Kéri CheckerContext &C) const override {
437957014daSBalázs Kéri SValBuilder &SVB = C.getSValBuilder();
438957014daSBalázs Kéri NonLoc ErrnoSVal =
439957014daSBalázs Kéri SVB.conjureSymbolVal(&Tag, Call.getOriginExpr(),
440957014daSBalázs Kéri C.getLocationContext(), C.getASTContext().IntTy,
441957014daSBalázs Kéri C.blockCount())
442957014daSBalázs Kéri .castAs<NonLoc>();
443957014daSBalázs Kéri NonLoc ZeroVal =
444957014daSBalázs Kéri SVB.makeZeroVal(C.getASTContext().IntTy).castAs<NonLoc>();
445957014daSBalázs Kéri DefinedOrUnknownSVal Cond =
446957014daSBalázs Kéri SVB.evalBinOp(State, Op, ErrnoSVal, ZeroVal, SVB.getConditionType())
447957014daSBalázs Kéri .castAs<DefinedOrUnknownSVal>();
448957014daSBalázs Kéri State = State->assume(Cond, true);
449957014daSBalázs Kéri if (!State)
450957014daSBalázs Kéri return State;
451957014daSBalázs Kéri return errno_modeling::setErrnoValue(State, C.getLocationContext(),
452957014daSBalázs Kéri ErrnoSVal, CheckState);
453957014daSBalázs Kéri }
454957014daSBalázs Kéri
describe(StringRef FunctionName) const455957014daSBalázs Kéri std::string describe(StringRef FunctionName) const override {
456957014daSBalázs Kéri if (CheckState == errno_modeling::Irrelevant)
457957014daSBalázs Kéri return "";
458957014daSBalázs Kéri return (Twine("Assuming that function '") + FunctionName.str() +
459957014daSBalázs Kéri "' fails, in this case the value 'errno' becomes " +
460957014daSBalázs Kéri BinaryOperator::getOpcodeStr(Op).str() + " 0 and " +
461957014daSBalázs Kéri describeErrnoCheckState(CheckState))
462957014daSBalázs Kéri .str();
463957014daSBalázs Kéri }
464957014daSBalázs Kéri };
465957014daSBalázs Kéri
466957014daSBalázs Kéri /// Applies the constraints to 'errno' for a common case when a standard
467957014daSBalázs Kéri /// function is successful. The value of 'errno' after the call is not
468957014daSBalázs Kéri /// specified by the standard (it may change or not). The \c ErrnoChecker can
469957014daSBalázs Kéri /// generate a bug if 'errno' is read afterwards.
470957014daSBalázs Kéri class SuccessErrnoConstraint : public ErrnoConstraintBase {
471957014daSBalázs Kéri public:
SuccessErrnoConstraint()472957014daSBalázs Kéri SuccessErrnoConstraint()
473957014daSBalázs Kéri : ErrnoConstraintBase(errno_modeling::MustNotBeChecked) {}
474957014daSBalázs Kéri
apply(ProgramStateRef State,const CallEvent & Call,const Summary & Summary,CheckerContext & C) const475957014daSBalázs Kéri ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
476957014daSBalázs Kéri const Summary &Summary,
477957014daSBalázs Kéri CheckerContext &C) const override {
478957014daSBalázs Kéri return errno_modeling::setErrnoState(State, CheckState);
479957014daSBalázs Kéri }
480957014daSBalázs Kéri
describe(StringRef FunctionName) const481957014daSBalázs Kéri std::string describe(StringRef FunctionName) const override {
482957014daSBalázs Kéri return (Twine("Assuming that function '") + FunctionName.str() +
483957014daSBalázs Kéri "' is successful, in this case the value 'errno' " +
484957014daSBalázs Kéri describeErrnoCheckState(CheckState))
485957014daSBalázs Kéri .str();
486957014daSBalázs Kéri }
487957014daSBalázs Kéri };
488957014daSBalázs Kéri
489957014daSBalázs Kéri /// Set errno constraints if use of 'errno' is completely irrelevant to the
490957014daSBalázs Kéri /// modeled function or modeling is not possible.
491957014daSBalázs Kéri class NoErrnoConstraint : public ErrnoConstraintBase {
492957014daSBalázs Kéri public:
NoErrnoConstraint()493957014daSBalázs Kéri NoErrnoConstraint() : ErrnoConstraintBase(errno_modeling::Irrelevant) {}
494957014daSBalázs Kéri
apply(ProgramStateRef State,const CallEvent & Call,const Summary & Summary,CheckerContext & C) const495957014daSBalázs Kéri ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
496957014daSBalázs Kéri const Summary &Summary,
497957014daSBalázs Kéri CheckerContext &C) const override {
498957014daSBalázs Kéri return errno_modeling::setErrnoState(State, CheckState);
499957014daSBalázs Kéri }
500957014daSBalázs Kéri };
501957014daSBalázs Kéri
502f68c0a2fSArtem Dergachev /// A single branch of a function summary.
503f68c0a2fSArtem Dergachev ///
504f68c0a2fSArtem Dergachev /// A branch is defined by a series of constraints - "assumptions" -
505f68c0a2fSArtem Dergachev /// that together form a single possible outcome of invoking the function.
506f68c0a2fSArtem Dergachev /// When static analyzer considers a branch, it tries to introduce
507f68c0a2fSArtem Dergachev /// a child node in the Exploded Graph. The child node has to include
508f68c0a2fSArtem Dergachev /// constraints that define the branch. If the constraints contradict
509f68c0a2fSArtem Dergachev /// existing constraints in the state, the node is not created and the branch
510f68c0a2fSArtem Dergachev /// is dropped; otherwise it's queued for future exploration.
511f68c0a2fSArtem Dergachev /// The branch is accompanied by a note text that may be displayed
512f68c0a2fSArtem Dergachev /// to the user when a bug is found on a path that takes this branch.
513f68c0a2fSArtem Dergachev ///
514f68c0a2fSArtem Dergachev /// For example, consider the branches in `isalpha(x)`:
515f68c0a2fSArtem Dergachev /// Branch 1)
516f68c0a2fSArtem Dergachev /// x is in range ['A', 'Z'] or in ['a', 'z']
517f68c0a2fSArtem Dergachev /// then the return value is not 0. (I.e. out-of-range [0, 0])
518f68c0a2fSArtem Dergachev /// and the note may say "Assuming the character is alphabetical"
519f68c0a2fSArtem Dergachev /// Branch 2)
520f68c0a2fSArtem Dergachev /// x is out-of-range ['A', 'Z'] and out-of-range ['a', 'z']
521f68c0a2fSArtem Dergachev /// then the return value is 0
522f68c0a2fSArtem Dergachev /// and the note may say "Assuming the character is non-alphabetical".
523f68c0a2fSArtem Dergachev class SummaryCase {
524f68c0a2fSArtem Dergachev ConstraintSet Constraints;
525957014daSBalázs Kéri const ErrnoConstraintBase &ErrnoConstraint;
526f68c0a2fSArtem Dergachev StringRef Note;
527f68c0a2fSArtem Dergachev
528f68c0a2fSArtem Dergachev public:
SummaryCase(ConstraintSet && Constraints,const ErrnoConstraintBase & ErrnoC,StringRef Note)529957014daSBalázs Kéri SummaryCase(ConstraintSet &&Constraints, const ErrnoConstraintBase &ErrnoC,
530957014daSBalázs Kéri StringRef Note)
531957014daSBalázs Kéri : Constraints(std::move(Constraints)), ErrnoConstraint(ErrnoC),
532957014daSBalázs Kéri Note(Note) {}
533f68c0a2fSArtem Dergachev
SummaryCase(const ConstraintSet & Constraints,const ErrnoConstraintBase & ErrnoC,StringRef Note)534957014daSBalázs Kéri SummaryCase(const ConstraintSet &Constraints,
535957014daSBalázs Kéri const ErrnoConstraintBase &ErrnoC, StringRef Note)
536957014daSBalázs Kéri : Constraints(Constraints), ErrnoConstraint(ErrnoC), Note(Note) {}
537f68c0a2fSArtem Dergachev
getConstraints() const538f68c0a2fSArtem Dergachev const ConstraintSet &getConstraints() const { return Constraints; }
getErrnoConstraint() const539957014daSBalázs Kéri const ErrnoConstraintBase &getErrnoConstraint() const {
540957014daSBalázs Kéri return ErrnoConstraint;
541957014daSBalázs Kéri }
getNote() const542f68c0a2fSArtem Dergachev StringRef getNote() const { return Note; }
543f68c0a2fSArtem Dergachev };
544bba497fbSArtem Dergachev
545a787a4edSGabor Marton using ArgTypes = std::vector<Optional<QualType>>;
546a787a4edSGabor Marton using RetType = Optional<QualType>;
54716506d78SGabor Marton
54816506d78SGabor Marton // A placeholder type, we use it whenever we do not care about the concrete
54916506d78SGabor Marton // type in a Signature.
55016506d78SGabor Marton const QualType Irrelevant{};
isIrrelevant(QualType T)55116506d78SGabor Marton bool static isIrrelevant(QualType T) { return T.isNull(); }
55216506d78SGabor Marton
55316506d78SGabor Marton // The signature of a function we want to describe with a summary. This is a
55416506d78SGabor Marton // concessive signature, meaning there may be irrelevant types in the
55516506d78SGabor Marton // signature which we do not check against a function with concrete types.
556a787a4edSGabor Marton // All types in the spec need to be canonical.
557a787a4edSGabor Marton class Signature {
558a787a4edSGabor Marton using ArgQualTypes = std::vector<QualType>;
559a787a4edSGabor Marton ArgQualTypes ArgTys;
5603ff220deSGabor Marton QualType RetTy;
561a787a4edSGabor Marton // True if any component type is not found by lookup.
562a787a4edSGabor Marton bool Invalid = false;
563a787a4edSGabor Marton
564a787a4edSGabor Marton public:
565a787a4edSGabor Marton // Construct a signature from optional types. If any of the optional types
566a787a4edSGabor Marton // are not set then the signature will be invalid.
Signature(ArgTypes ArgTys,RetType RetTy)567a787a4edSGabor Marton Signature(ArgTypes ArgTys, RetType RetTy) {
568a787a4edSGabor Marton for (Optional<QualType> Arg : ArgTys) {
569a787a4edSGabor Marton if (!Arg) {
570a787a4edSGabor Marton Invalid = true;
571a787a4edSGabor Marton return;
572a787a4edSGabor Marton } else {
573a787a4edSGabor Marton assertArgTypeSuitableForSignature(*Arg);
574a787a4edSGabor Marton this->ArgTys.push_back(*Arg);
575a787a4edSGabor Marton }
576a787a4edSGabor Marton }
577a787a4edSGabor Marton if (!RetTy) {
578a787a4edSGabor Marton Invalid = true;
579a787a4edSGabor Marton return;
580a787a4edSGabor Marton } else {
581a787a4edSGabor Marton assertRetTypeSuitableForSignature(*RetTy);
582a787a4edSGabor Marton this->RetTy = *RetTy;
58316506d78SGabor Marton }
58416506d78SGabor Marton }
5853ff220deSGabor Marton
isInvalid() const586a787a4edSGabor Marton bool isInvalid() const { return Invalid; }
58716506d78SGabor Marton bool matches(const FunctionDecl *FD) const;
58816506d78SGabor Marton
58916506d78SGabor Marton private:
assertArgTypeSuitableForSignature(QualType T)59016506d78SGabor Marton static void assertArgTypeSuitableForSignature(QualType T) {
59116506d78SGabor Marton assert((T.isNull() || !T->isVoidType()) &&
59216506d78SGabor Marton "We should have no void types in the spec");
59316506d78SGabor Marton assert((T.isNull() || T.isCanonical()) &&
59416506d78SGabor Marton "We should only have canonical types in the spec");
59516506d78SGabor Marton }
assertRetTypeSuitableForSignature(QualType T)59616506d78SGabor Marton static void assertRetTypeSuitableForSignature(QualType T) {
59716506d78SGabor Marton assert((T.isNull() || T.isCanonical()) &&
59816506d78SGabor Marton "We should only have canonical types in the spec");
59916506d78SGabor Marton }
60016506d78SGabor Marton };
60116506d78SGabor Marton
getArgType(const FunctionDecl * FD,ArgNo ArgN)60216506d78SGabor Marton static QualType getArgType(const FunctionDecl *FD, ArgNo ArgN) {
60316506d78SGabor Marton assert(FD && "Function must be set");
60416506d78SGabor Marton QualType T = (ArgN == Ret)
60516506d78SGabor Marton ? FD->getReturnType().getCanonicalType()
60616506d78SGabor Marton : FD->getParamDecl(ArgN)->getType().getCanonicalType();
60716506d78SGabor Marton return T;
60816506d78SGabor Marton }
60916506d78SGabor Marton
610f68c0a2fSArtem Dergachev using SummaryCases = std::vector<SummaryCase>;
611f5086b38SGabor Marton
61216506d78SGabor Marton /// A summary includes information about
61316506d78SGabor Marton /// * function prototype (signature)
61494061df6SGabor Marton /// * approach to invalidation,
615f68c0a2fSArtem Dergachev /// * a list of branches - so, a list of list of ranges,
61694061df6SGabor Marton /// * a list of argument constraints, that must be true on every branch.
61794061df6SGabor Marton /// If these constraints are not satisfied that means a fatal error
61894061df6SGabor Marton /// usually resulting in undefined behaviour.
61916506d78SGabor Marton ///
62016506d78SGabor Marton /// Application of a summary:
62116506d78SGabor Marton /// The signature and argument constraints together contain information
62216506d78SGabor Marton /// about which functions are handled by the summary. The signature can use
62316506d78SGabor Marton /// "wildcards", i.e. Irrelevant types. Irrelevant type of a parameter in
62416506d78SGabor Marton /// a signature means that type is not compared to the type of the parameter
62516506d78SGabor Marton /// in the found FunctionDecl. Argument constraints may specify additional
62616506d78SGabor Marton /// rules for the given parameter's type, those rules are checked once the
62716506d78SGabor Marton /// signature is matched.
62816506d78SGabor Marton class Summary {
629f5086b38SGabor Marton const InvalidationKind InvalidationKd;
630f68c0a2fSArtem Dergachev SummaryCases Cases;
631c6b8484eSGabor Marton ConstraintSet ArgConstraints;
632f5086b38SGabor Marton
63316506d78SGabor Marton // The function to which the summary applies. This is set after lookup and
63416506d78SGabor Marton // match to the signature.
63516506d78SGabor Marton const FunctionDecl *FD = nullptr;
63616506d78SGabor Marton
63716506d78SGabor Marton public:
Summary(InvalidationKind InvalidationKd)6383ff220deSGabor Marton Summary(InvalidationKind InvalidationKd) : InvalidationKd(InvalidationKd) {}
6393ff220deSGabor Marton
Case(ConstraintSet && CS,const ErrnoConstraintBase & ErrnoC,StringRef Note="")640957014daSBalázs Kéri Summary &Case(ConstraintSet &&CS, const ErrnoConstraintBase &ErrnoC,
641957014daSBalázs Kéri StringRef Note = "") {
642957014daSBalázs Kéri Cases.push_back(SummaryCase(std::move(CS), ErrnoC, Note));
643f5086b38SGabor Marton return *this;
644f5086b38SGabor Marton }
Case(const ConstraintSet & CS,const ErrnoConstraintBase & ErrnoC,StringRef Note="")645957014daSBalázs Kéri Summary &Case(const ConstraintSet &CS, const ErrnoConstraintBase &ErrnoC,
646957014daSBalázs Kéri StringRef Note = "") {
647957014daSBalázs Kéri Cases.push_back(SummaryCase(CS, ErrnoC, Note));
648b40b3196SGabor Marton return *this;
649b40b3196SGabor Marton }
ArgConstraint(ValueConstraintPtr VC)65094061df6SGabor Marton Summary &ArgConstraint(ValueConstraintPtr VC) {
651a97648b9SGabor Marton assert(VC->getArgNo() != Ret &&
652a97648b9SGabor Marton "Arg constraint should not refer to the return value");
65394061df6SGabor Marton ArgConstraints.push_back(VC);
65494061df6SGabor Marton return *this;
65594061df6SGabor Marton }
656bba497fbSArtem Dergachev
getInvalidationKd() const65716506d78SGabor Marton InvalidationKind getInvalidationKd() const { return InvalidationKd; }
getCases() const658f68c0a2fSArtem Dergachev const SummaryCases &getCases() const { return Cases; }
getArgConstraints() const65916506d78SGabor Marton const ConstraintSet &getArgConstraints() const { return ArgConstraints; }
660bba497fbSArtem Dergachev
getArgType(ArgNo ArgN) const661f5086b38SGabor Marton QualType getArgType(ArgNo ArgN) const {
66216506d78SGabor Marton return StdLibraryFunctionsChecker::getArgType(FD, ArgN);
663bba497fbSArtem Dergachev }
664bba497fbSArtem Dergachev
66516506d78SGabor Marton // Returns true if the summary should be applied to the given function.
66616506d78SGabor Marton // And if yes then store the function declaration.
matchesAndSet(const Signature & Sign,const FunctionDecl * FD)66711d2e63aSGabor Marton bool matchesAndSet(const Signature &Sign, const FunctionDecl *FD) {
66811d2e63aSGabor Marton bool Result = Sign.matches(FD) && validateByConstraints(FD);
66916506d78SGabor Marton if (Result) {
67016506d78SGabor Marton assert(!this->FD && "FD must not be set more than once");
67116506d78SGabor Marton this->FD = FD;
67216506d78SGabor Marton }
67316506d78SGabor Marton return Result;
67416506d78SGabor Marton }
67516506d78SGabor Marton
67616506d78SGabor Marton private:
677d8e5a0c4SZarko Todorovski // Once we know the exact type of the function then do validation check on
678d8e5a0c4SZarko Todorovski // all the given constraints.
validateByConstraints(const FunctionDecl * FD) const67916506d78SGabor Marton bool validateByConstraints(const FunctionDecl *FD) const {
680f68c0a2fSArtem Dergachev for (const SummaryCase &Case : Cases)
681f68c0a2fSArtem Dergachev for (const ValueConstraintPtr &Constraint : Case.getConstraints())
68216506d78SGabor Marton if (!Constraint->checkValidity(FD))
68316506d78SGabor Marton return false;
68416506d78SGabor Marton for (const ValueConstraintPtr &Constraint : ArgConstraints)
68516506d78SGabor Marton if (!Constraint->checkValidity(FD))
68616506d78SGabor Marton return false;
68716506d78SGabor Marton return true;
68816506d78SGabor Marton }
689bba497fbSArtem Dergachev };
690bba497fbSArtem Dergachev
691bba497fbSArtem Dergachev // The map of all functions supported by the checker. It is initialized
692bba497fbSArtem Dergachev // lazily, and it doesn't change after initialization.
69362e747f6SGabor Marton using FunctionSummaryMapType = llvm::DenseMap<const FunctionDecl *, Summary>;
69462e747f6SGabor Marton mutable FunctionSummaryMapType FunctionSummaryMap;
695bba497fbSArtem Dergachev
69694061df6SGabor Marton mutable std::unique_ptr<BugType> BT_InvalidArg;
697c7635040SValeriy Savchenko mutable bool SummariesInitialized = false;
69894061df6SGabor Marton
getArgSVal(const CallEvent & Call,ArgNo ArgN)699f5086b38SGabor Marton static SVal getArgSVal(const CallEvent &Call, ArgNo ArgN) {
700f5086b38SGabor Marton return ArgN == Ret ? Call.getReturnValue() : Call.getArgSVal(ArgN);
701bba497fbSArtem Dergachev }
702bba497fbSArtem Dergachev
703bba497fbSArtem Dergachev public:
70494061df6SGabor Marton void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
705bba497fbSArtem Dergachev void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
70644820630SArtem Dergachev bool evalCall(const CallEvent &Call, CheckerContext &C) const;
707bba497fbSArtem Dergachev
7081525232eSGabor Marton enum CheckKind {
7091525232eSGabor Marton CK_StdCLibraryFunctionArgsChecker,
7101525232eSGabor Marton CK_StdCLibraryFunctionsTesterChecker,
7111525232eSGabor Marton CK_NumCheckKinds
7121525232eSGabor Marton };
7135114db93SVince Bridgers bool ChecksEnabled[CK_NumCheckKinds] = {false};
71494061df6SGabor Marton CheckerNameRef CheckNames[CK_NumCheckKinds];
71594061df6SGabor Marton
716ff4492c8SGabor Marton bool DisplayLoadedSummaries = false;
717db4d5f70SGabor Marton bool ModelPOSIX = false;
718edde4efcSBalazs Benics bool ShouldAssumeControlledEnvironment = false;
719ff4492c8SGabor Marton
720bba497fbSArtem Dergachev private:
721f5086b38SGabor Marton Optional<Summary> findFunctionSummary(const FunctionDecl *FD,
722bba497fbSArtem Dergachev CheckerContext &C) const;
72394061df6SGabor Marton Optional<Summary> findFunctionSummary(const CallEvent &Call,
72494061df6SGabor Marton CheckerContext &C) const;
725bba497fbSArtem Dergachev
726536456a7SGabor Marton void initFunctionSummaries(CheckerContext &C) const;
72794061df6SGabor Marton
reportBug(const CallEvent & Call,ExplodedNode * N,const ValueConstraint * VC,const Summary & Summary,CheckerContext & C) const72894061df6SGabor Marton void reportBug(const CallEvent &Call, ExplodedNode *N,
729a7cb951fSGabor Marton const ValueConstraint *VC, const Summary &Summary,
730a7cb951fSGabor Marton CheckerContext &C) const {
73194061df6SGabor Marton if (!ChecksEnabled[CK_StdCLibraryFunctionArgsChecker])
73294061df6SGabor Marton return;
733a97648b9SGabor Marton std::string Msg =
734a97648b9SGabor Marton (Twine("Function argument constraint is not satisfied, constraint: ") +
735a7cb951fSGabor Marton VC->getName().data())
736a97648b9SGabor Marton .str();
73794061df6SGabor Marton if (!BT_InvalidArg)
73894061df6SGabor Marton BT_InvalidArg = std::make_unique<BugType>(
73994061df6SGabor Marton CheckNames[CK_StdCLibraryFunctionArgsChecker],
74094061df6SGabor Marton "Unsatisfied argument constraints", categories::LogicError);
74194061df6SGabor Marton auto R = std::make_unique<PathSensitiveBugReport>(*BT_InvalidArg, Msg, N);
7424b99f9c7SGabor Marton
7434b99f9c7SGabor Marton for (ArgNo ArgN : VC->getArgsToTrack())
7444b99f9c7SGabor Marton bugreporter::trackExpressionValue(N, Call.getArgExpr(ArgN), *R);
745a97648b9SGabor Marton
746a97648b9SGabor Marton // Highlight the range of the argument that was violated.
747a97648b9SGabor Marton R->addRange(Call.getArgSourceRange(VC->getArgNo()));
748a97648b9SGabor Marton
749a7cb951fSGabor Marton // Describe the argument constraint in a note.
750a7cb951fSGabor Marton R->addNote(VC->describe(C.getState(), Summary), R->getLocation(),
751a7cb951fSGabor Marton Call.getArgSourceRange(VC->getArgNo()));
752a7cb951fSGabor Marton
75394061df6SGabor Marton C.emitReport(std::move(R));
75494061df6SGabor Marton }
755957014daSBalázs Kéri
756957014daSBalázs Kéri /// These are the errno constraints that can be passed to summary cases.
757957014daSBalázs Kéri /// One of these should fit for a single summary case.
758957014daSBalázs Kéri /// Usually if a failure return value exists for function, that function
759957014daSBalázs Kéri /// needs different cases for success and failure with different errno
760957014daSBalázs Kéri /// constraints (and different return value constraints).
761957014daSBalázs Kéri const NoErrnoConstraint ErrnoIrrelevant;
762957014daSBalázs Kéri const SuccessErrnoConstraint ErrnoMustNotBeChecked;
763957014daSBalázs Kéri const ZeroRelatedErrnoConstraint ErrnoNEZeroIrrelevant{
764957014daSBalázs Kéri clang::BinaryOperatorKind::BO_NE, errno_modeling::Irrelevant};
765bba497fbSArtem Dergachev };
766c6b8484eSGabor Marton
767957014daSBalázs Kéri int StdLibraryFunctionsChecker::ErrnoConstraintBase::Tag = 0;
768957014daSBalázs Kéri
769c6b8484eSGabor Marton const StdLibraryFunctionsChecker::ArgNo StdLibraryFunctionsChecker::Ret =
770c6b8484eSGabor Marton std::numeric_limits<ArgNo>::max();
771c6b8484eSGabor Marton
772bba497fbSArtem Dergachev } // end of anonymous namespace
773bba497fbSArtem Dergachev
getBVF(ProgramStateRef State)774a7cb951fSGabor Marton static BasicValueFactory &getBVF(ProgramStateRef State) {
775a7cb951fSGabor Marton ProgramStateManager &Mgr = State->getStateManager();
776a7cb951fSGabor Marton SValBuilder &SVB = Mgr.getSValBuilder();
777a7cb951fSGabor Marton return SVB.getBasicValueFactory();
778a7cb951fSGabor Marton }
779a7cb951fSGabor Marton
describe(ProgramStateRef State,const Summary & Summary) const780a7cb951fSGabor Marton std::string StdLibraryFunctionsChecker::NotNullConstraint::describe(
781a7cb951fSGabor Marton ProgramStateRef State, const Summary &Summary) const {
782a7cb951fSGabor Marton SmallString<48> Result;
783a7cb951fSGabor Marton Result += "The ";
784a7cb951fSGabor Marton Result += getArgDesc(ArgN);
785a7cb951fSGabor Marton Result += " should not be NULL";
786a7cb951fSGabor Marton return Result.c_str();
787a7cb951fSGabor Marton }
788a7cb951fSGabor Marton
describe(ProgramStateRef State,const Summary & Summary) const789a7cb951fSGabor Marton std::string StdLibraryFunctionsChecker::RangeConstraint::describe(
790a7cb951fSGabor Marton ProgramStateRef State, const Summary &Summary) const {
791a7cb951fSGabor Marton
792a7cb951fSGabor Marton BasicValueFactory &BVF = getBVF(State);
793a7cb951fSGabor Marton
794a7cb951fSGabor Marton QualType T = Summary.getArgType(getArgNo());
795a7cb951fSGabor Marton SmallString<48> Result;
796a7cb951fSGabor Marton Result += "The ";
797a7cb951fSGabor Marton Result += getArgDesc(ArgN);
798a7cb951fSGabor Marton Result += " should be ";
799a7cb951fSGabor Marton
800a7cb951fSGabor Marton // Range kind as a string.
801a7cb951fSGabor Marton Kind == OutOfRange ? Result += "out of" : Result += "within";
802a7cb951fSGabor Marton
803a7cb951fSGabor Marton // Get the range values as a string.
804a7cb951fSGabor Marton Result += " the range ";
805a7cb951fSGabor Marton if (Ranges.size() > 1)
806a7cb951fSGabor Marton Result += "[";
807a7cb951fSGabor Marton unsigned I = Ranges.size();
808a7cb951fSGabor Marton for (const std::pair<RangeInt, RangeInt> &R : Ranges) {
809a7cb951fSGabor Marton Result += "[";
810a7cb951fSGabor Marton const llvm::APSInt &Min = BVF.getValue(R.first, T);
811a7cb951fSGabor Marton const llvm::APSInt &Max = BVF.getValue(R.second, T);
812a7cb951fSGabor Marton Min.toString(Result);
813a7cb951fSGabor Marton Result += ", ";
814a7cb951fSGabor Marton Max.toString(Result);
815a7cb951fSGabor Marton Result += "]";
816a7cb951fSGabor Marton if (--I > 0)
817a7cb951fSGabor Marton Result += ", ";
818a7cb951fSGabor Marton }
819a7cb951fSGabor Marton if (Ranges.size() > 1)
820a7cb951fSGabor Marton Result += "]";
821a7cb951fSGabor Marton
822a7cb951fSGabor Marton return Result.c_str();
823a7cb951fSGabor Marton }
824a7cb951fSGabor Marton
825a7cb951fSGabor Marton SmallString<8>
getArgDesc(StdLibraryFunctionsChecker::ArgNo ArgN)826a7cb951fSGabor Marton StdLibraryFunctionsChecker::getArgDesc(StdLibraryFunctionsChecker::ArgNo ArgN) {
827a7cb951fSGabor Marton SmallString<8> Result;
828a7cb951fSGabor Marton Result += std::to_string(ArgN + 1);
829a7cb951fSGabor Marton Result += llvm::getOrdinalSuffix(ArgN + 1);
830a7cb951fSGabor Marton Result += " arg";
831a7cb951fSGabor Marton return Result;
832a7cb951fSGabor Marton }
833a7cb951fSGabor Marton
describe(ProgramStateRef State,const Summary & Summary) const834a7cb951fSGabor Marton std::string StdLibraryFunctionsChecker::BufferSizeConstraint::describe(
835a7cb951fSGabor Marton ProgramStateRef State, const Summary &Summary) const {
836a7cb951fSGabor Marton SmallString<96> Result;
837a7cb951fSGabor Marton Result += "The size of the ";
838a7cb951fSGabor Marton Result += getArgDesc(ArgN);
839a7cb951fSGabor Marton Result += " should be equal to or less than the value of ";
840a7cb951fSGabor Marton if (ConcreteSize) {
841a7cb951fSGabor Marton ConcreteSize->toString(Result);
842a7cb951fSGabor Marton } else if (SizeArgN) {
843a7cb951fSGabor Marton Result += "the ";
844a7cb951fSGabor Marton Result += getArgDesc(*SizeArgN);
845a7cb951fSGabor Marton if (SizeMultiplierArgN) {
846a7cb951fSGabor Marton Result += " times the ";
847a7cb951fSGabor Marton Result += getArgDesc(*SizeMultiplierArgN);
848a7cb951fSGabor Marton }
849a7cb951fSGabor Marton }
850a7cb951fSGabor Marton return Result.c_str();
851a7cb951fSGabor Marton }
852a7cb951fSGabor Marton
applyAsOutOfRange(ProgramStateRef State,const CallEvent & Call,const Summary & Summary) const853c6b8484eSGabor Marton ProgramStateRef StdLibraryFunctionsChecker::RangeConstraint::applyAsOutOfRange(
854bba497fbSArtem Dergachev ProgramStateRef State, const CallEvent &Call,
855f5086b38SGabor Marton const Summary &Summary) const {
856a787a4edSGabor Marton if (Ranges.empty())
857a787a4edSGabor Marton return State;
858bba497fbSArtem Dergachev
859bba497fbSArtem Dergachev ProgramStateManager &Mgr = State->getStateManager();
860bba497fbSArtem Dergachev SValBuilder &SVB = Mgr.getSValBuilder();
861bba497fbSArtem Dergachev BasicValueFactory &BVF = SVB.getBasicValueFactory();
862bba497fbSArtem Dergachev ConstraintManager &CM = Mgr.getConstraintManager();
86316506d78SGabor Marton QualType T = Summary.getArgType(getArgNo());
864bba497fbSArtem Dergachev SVal V = getArgSVal(Call, getArgNo());
865bba497fbSArtem Dergachev
866bba497fbSArtem Dergachev if (auto N = V.getAs<NonLoc>()) {
867f5086b38SGabor Marton const IntRangeVector &R = getRanges();
868bba497fbSArtem Dergachev size_t E = R.size();
869bba497fbSArtem Dergachev for (size_t I = 0; I != E; ++I) {
870bba497fbSArtem Dergachev const llvm::APSInt &Min = BVF.getValue(R[I].first, T);
871bba497fbSArtem Dergachev const llvm::APSInt &Max = BVF.getValue(R[I].second, T);
872bba497fbSArtem Dergachev assert(Min <= Max);
8733f8c3fa7SDominic Chen State = CM.assumeInclusiveRange(State, *N, Min, Max, false);
874bba497fbSArtem Dergachev if (!State)
875bba497fbSArtem Dergachev break;
876bba497fbSArtem Dergachev }
877bba497fbSArtem Dergachev }
878bba497fbSArtem Dergachev
879bba497fbSArtem Dergachev return State;
880bba497fbSArtem Dergachev }
881bba497fbSArtem Dergachev
applyAsWithinRange(ProgramStateRef State,const CallEvent & Call,const Summary & Summary) const882c6b8484eSGabor Marton ProgramStateRef StdLibraryFunctionsChecker::RangeConstraint::applyAsWithinRange(
883bba497fbSArtem Dergachev ProgramStateRef State, const CallEvent &Call,
884f5086b38SGabor Marton const Summary &Summary) const {
885a787a4edSGabor Marton if (Ranges.empty())
886a787a4edSGabor Marton return State;
887bba497fbSArtem Dergachev
888bba497fbSArtem Dergachev ProgramStateManager &Mgr = State->getStateManager();
889bba497fbSArtem Dergachev SValBuilder &SVB = Mgr.getSValBuilder();
890bba497fbSArtem Dergachev BasicValueFactory &BVF = SVB.getBasicValueFactory();
891bba497fbSArtem Dergachev ConstraintManager &CM = Mgr.getConstraintManager();
89216506d78SGabor Marton QualType T = Summary.getArgType(getArgNo());
893bba497fbSArtem Dergachev SVal V = getArgSVal(Call, getArgNo());
894bba497fbSArtem Dergachev
895bba497fbSArtem Dergachev // "WithinRange R" is treated as "outside [T_MIN, T_MAX] \ R".
896bba497fbSArtem Dergachev // We cut off [T_MIN, min(R) - 1] and [max(R) + 1, T_MAX] if necessary,
897bba497fbSArtem Dergachev // and then cut away all holes in R one by one.
898536456a7SGabor Marton //
899536456a7SGabor Marton // E.g. consider a range list R as [A, B] and [C, D]
900536456a7SGabor Marton // -------+--------+------------------+------------+----------->
901536456a7SGabor Marton // A B C D
902536456a7SGabor Marton // Then we assume that the value is not in [-inf, A - 1],
903536456a7SGabor Marton // then not in [D + 1, +inf], then not in [B + 1, C - 1]
904bba497fbSArtem Dergachev if (auto N = V.getAs<NonLoc>()) {
905f5086b38SGabor Marton const IntRangeVector &R = getRanges();
906bba497fbSArtem Dergachev size_t E = R.size();
907bba497fbSArtem Dergachev
908bba497fbSArtem Dergachev const llvm::APSInt &MinusInf = BVF.getMinValue(T);
909bba497fbSArtem Dergachev const llvm::APSInt &PlusInf = BVF.getMaxValue(T);
910bba497fbSArtem Dergachev
91126b0a9d8SArtem Dergachev const llvm::APSInt &Left = BVF.getValue(R[0].first - 1ULL, T);
912bba497fbSArtem Dergachev if (Left != PlusInf) {
913bba497fbSArtem Dergachev assert(MinusInf <= Left);
9143f8c3fa7SDominic Chen State = CM.assumeInclusiveRange(State, *N, MinusInf, Left, false);
915bba497fbSArtem Dergachev if (!State)
916bba497fbSArtem Dergachev return nullptr;
917bba497fbSArtem Dergachev }
918bba497fbSArtem Dergachev
91926b0a9d8SArtem Dergachev const llvm::APSInt &Right = BVF.getValue(R[E - 1].second + 1ULL, T);
920bba497fbSArtem Dergachev if (Right != MinusInf) {
921bba497fbSArtem Dergachev assert(Right <= PlusInf);
9223f8c3fa7SDominic Chen State = CM.assumeInclusiveRange(State, *N, Right, PlusInf, false);
923bba497fbSArtem Dergachev if (!State)
924bba497fbSArtem Dergachev return nullptr;
925bba497fbSArtem Dergachev }
926bba497fbSArtem Dergachev
927bba497fbSArtem Dergachev for (size_t I = 1; I != E; ++I) {
92826b0a9d8SArtem Dergachev const llvm::APSInt &Min = BVF.getValue(R[I - 1].second + 1ULL, T);
92926b0a9d8SArtem Dergachev const llvm::APSInt &Max = BVF.getValue(R[I].first - 1ULL, T);
930536456a7SGabor Marton if (Min <= Max) {
9313f8c3fa7SDominic Chen State = CM.assumeInclusiveRange(State, *N, Min, Max, false);
932bba497fbSArtem Dergachev if (!State)
933bba497fbSArtem Dergachev return nullptr;
934bba497fbSArtem Dergachev }
935bba497fbSArtem Dergachev }
936536456a7SGabor Marton }
937bba497fbSArtem Dergachev
938bba497fbSArtem Dergachev return State;
939bba497fbSArtem Dergachev }
940bba497fbSArtem Dergachev
apply(ProgramStateRef State,const CallEvent & Call,const Summary & Summary,CheckerContext & C) const941c6b8484eSGabor Marton ProgramStateRef StdLibraryFunctionsChecker::ComparisonConstraint::apply(
942bd03ef19SGabor Marton ProgramStateRef State, const CallEvent &Call, const Summary &Summary,
943bd03ef19SGabor Marton CheckerContext &C) const {
944bba497fbSArtem Dergachev
945bba497fbSArtem Dergachev ProgramStateManager &Mgr = State->getStateManager();
946bba497fbSArtem Dergachev SValBuilder &SVB = Mgr.getSValBuilder();
947bba497fbSArtem Dergachev QualType CondT = SVB.getConditionType();
94816506d78SGabor Marton QualType T = Summary.getArgType(getArgNo());
949bba497fbSArtem Dergachev SVal V = getArgSVal(Call, getArgNo());
950bba497fbSArtem Dergachev
951bba497fbSArtem Dergachev BinaryOperator::Opcode Op = getOpcode();
952f5086b38SGabor Marton ArgNo OtherArg = getOtherArgNo();
953bba497fbSArtem Dergachev SVal OtherV = getArgSVal(Call, OtherArg);
95416506d78SGabor Marton QualType OtherT = Summary.getArgType(OtherArg);
955bba497fbSArtem Dergachev // Note: we avoid integral promotion for comparison.
956bba497fbSArtem Dergachev OtherV = SVB.evalCast(OtherV, T, OtherT);
957bba497fbSArtem Dergachev if (auto CompV = SVB.evalBinOp(State, Op, V, OtherV, CondT)
958bba497fbSArtem Dergachev .getAs<DefinedOrUnknownSVal>())
959bba497fbSArtem Dergachev State = State->assume(*CompV, true);
960bba497fbSArtem Dergachev return State;
961bba497fbSArtem Dergachev }
962bba497fbSArtem Dergachev
checkPreCall(const CallEvent & Call,CheckerContext & C) const96394061df6SGabor Marton void StdLibraryFunctionsChecker::checkPreCall(const CallEvent &Call,
96494061df6SGabor Marton CheckerContext &C) const {
96594061df6SGabor Marton Optional<Summary> FoundSummary = findFunctionSummary(Call, C);
96694061df6SGabor Marton if (!FoundSummary)
96794061df6SGabor Marton return;
96894061df6SGabor Marton
96994061df6SGabor Marton const Summary &Summary = *FoundSummary;
97094061df6SGabor Marton ProgramStateRef State = C.getState();
97194061df6SGabor Marton
9721525232eSGabor Marton ProgramStateRef NewState = State;
97316506d78SGabor Marton for (const ValueConstraintPtr &Constraint : Summary.getArgConstraints()) {
97416506d78SGabor Marton ProgramStateRef SuccessSt = Constraint->apply(NewState, Call, Summary, C);
97516506d78SGabor Marton ProgramStateRef FailureSt =
97616506d78SGabor Marton Constraint->negate()->apply(NewState, Call, Summary, C);
97794061df6SGabor Marton // The argument constraint is not satisfied.
97894061df6SGabor Marton if (FailureSt && !SuccessSt) {
9791525232eSGabor Marton if (ExplodedNode *N = C.generateErrorNode(NewState))
980a7cb951fSGabor Marton reportBug(Call, N, Constraint.get(), Summary, C);
98194061df6SGabor Marton break;
98294061df6SGabor Marton } else {
9831525232eSGabor Marton // We will apply the constraint even if we cannot reason about the
9841525232eSGabor Marton // argument. This means both SuccessSt and FailureSt can be true. If we
9851525232eSGabor Marton // weren't applying the constraint that would mean that symbolic
9861525232eSGabor Marton // execution continues on a code whose behaviour is undefined.
98794061df6SGabor Marton assert(SuccessSt);
9881525232eSGabor Marton NewState = SuccessSt;
98994061df6SGabor Marton }
99094061df6SGabor Marton }
9911525232eSGabor Marton if (NewState && NewState != State)
9921525232eSGabor Marton C.addTransition(NewState);
99394061df6SGabor Marton }
99494061df6SGabor Marton
checkPostCall(const CallEvent & Call,CheckerContext & C) const995bba497fbSArtem Dergachev void StdLibraryFunctionsChecker::checkPostCall(const CallEvent &Call,
996bba497fbSArtem Dergachev CheckerContext &C) const {
99794061df6SGabor Marton Optional<Summary> FoundSummary = findFunctionSummary(Call, C);
998bba497fbSArtem Dergachev if (!FoundSummary)
999bba497fbSArtem Dergachev return;
1000bba497fbSArtem Dergachev
1001c6b8484eSGabor Marton // Now apply the constraints.
1002f5086b38SGabor Marton const Summary &Summary = *FoundSummary;
1003bba497fbSArtem Dergachev ProgramStateRef State = C.getState();
1004f68c0a2fSArtem Dergachev const ExplodedNode *Node = C.getPredecessor();
1005bba497fbSArtem Dergachev
1006f5086b38SGabor Marton // Apply case/branch specifications.
1007f68c0a2fSArtem Dergachev for (const SummaryCase &Case : Summary.getCases()) {
1008bba497fbSArtem Dergachev ProgramStateRef NewState = State;
1009f68c0a2fSArtem Dergachev for (const ValueConstraintPtr &Constraint : Case.getConstraints()) {
101016506d78SGabor Marton NewState = Constraint->apply(NewState, Call, Summary, C);
1011bba497fbSArtem Dergachev if (!NewState)
1012bba497fbSArtem Dergachev break;
1013bba497fbSArtem Dergachev }
1014bba497fbSArtem Dergachev
1015957014daSBalázs Kéri if (NewState)
1016957014daSBalázs Kéri NewState = Case.getErrnoConstraint().apply(NewState, Call, Summary, C);
1017957014daSBalázs Kéri
1018f68c0a2fSArtem Dergachev if (NewState && NewState != State) {
1019957014daSBalázs Kéri if (Case.getNote().empty()) {
1020957014daSBalázs Kéri std::string Note;
1021957014daSBalázs Kéri if (const auto *D = dyn_cast_or_null<FunctionDecl>(Call.getDecl()))
1022957014daSBalázs Kéri Note = Case.getErrnoConstraint().describe(D->getNameAsString());
1023957014daSBalázs Kéri if (Note.empty())
1024957014daSBalázs Kéri C.addTransition(NewState);
1025957014daSBalázs Kéri else
1026957014daSBalázs Kéri C.addTransition(NewState, errno_modeling::getErrnoNoteTag(C, Note));
1027957014daSBalázs Kéri } else {
1028f68c0a2fSArtem Dergachev StringRef Note = Case.getNote();
1029f68c0a2fSArtem Dergachev const NoteTag *Tag = C.getNoteTag(
1030f68c0a2fSArtem Dergachev // Sorry couldn't help myself.
1031957014daSBalázs Kéri [Node, Note]() -> std::string {
1032f68c0a2fSArtem Dergachev // Don't emit "Assuming..." note when we ended up
1033f68c0a2fSArtem Dergachev // knowing in advance which branch is taken.
1034f68c0a2fSArtem Dergachev return (Node->succ_size() > 1) ? Note.str() : "";
1035f68c0a2fSArtem Dergachev },
1036f68c0a2fSArtem Dergachev /*IsPrunable=*/true);
1037f68c0a2fSArtem Dergachev C.addTransition(NewState, Tag);
1038f68c0a2fSArtem Dergachev }
1039bba497fbSArtem Dergachev }
1040bba497fbSArtem Dergachev }
1041957014daSBalázs Kéri }
1042bba497fbSArtem Dergachev
evalCall(const CallEvent & Call,CheckerContext & C) const104344820630SArtem Dergachev bool StdLibraryFunctionsChecker::evalCall(const CallEvent &Call,
1044bba497fbSArtem Dergachev CheckerContext &C) const {
104594061df6SGabor Marton Optional<Summary> FoundSummary = findFunctionSummary(Call, C);
1046bba497fbSArtem Dergachev if (!FoundSummary)
1047bba497fbSArtem Dergachev return false;
1048bba497fbSArtem Dergachev
1049f5086b38SGabor Marton const Summary &Summary = *FoundSummary;
105016506d78SGabor Marton switch (Summary.getInvalidationKd()) {
1051bba497fbSArtem Dergachev case EvalCallAsPure: {
1052bba497fbSArtem Dergachev ProgramStateRef State = C.getState();
1053bba497fbSArtem Dergachev const LocationContext *LC = C.getLocationContext();
1054879c12d9SSimon Pilgrim const auto *CE = cast<CallExpr>(Call.getOriginExpr());
1055bba497fbSArtem Dergachev SVal V = C.getSValBuilder().conjureSymbolVal(
1056bba497fbSArtem Dergachev CE, LC, CE->getType().getCanonicalType(), C.blockCount());
1057bba497fbSArtem Dergachev State = State->BindExpr(CE, LC, V);
1058957014daSBalázs Kéri
1059bba497fbSArtem Dergachev C.addTransition(State);
1060957014daSBalázs Kéri
1061bba497fbSArtem Dergachev return true;
1062bba497fbSArtem Dergachev }
1063bba497fbSArtem Dergachev case NoEvalCall:
1064bba497fbSArtem Dergachev // Summary tells us to avoid performing eval::Call. The function is possibly
1065bba497fbSArtem Dergachev // evaluated by another checker, or evaluated conservatively.
1066bba497fbSArtem Dergachev return false;
1067bba497fbSArtem Dergachev }
1068bba497fbSArtem Dergachev llvm_unreachable("Unknown invalidation kind!");
1069bba497fbSArtem Dergachev }
1070bba497fbSArtem Dergachev
matches(const FunctionDecl * FD) const107116506d78SGabor Marton bool StdLibraryFunctionsChecker::Signature::matches(
10728f961399SGabor Marton const FunctionDecl *FD) const {
1073a787a4edSGabor Marton assert(!isInvalid());
1074fe0972d3SGabor Marton // Check the number of arguments.
10758f961399SGabor Marton if (FD->param_size() != ArgTys.size())
1076bba497fbSArtem Dergachev return false;
1077bba497fbSArtem Dergachev
1078fe0972d3SGabor Marton // The "restrict" keyword is illegal in C++, however, many libc
1079fe0972d3SGabor Marton // implementations use the "__restrict" compiler intrinsic in functions
1080fe0972d3SGabor Marton // prototypes. The "__restrict" keyword qualifies a type as a restricted type
1081fe0972d3SGabor Marton // even in C++.
1082fe0972d3SGabor Marton // In case of any non-C99 languages, we don't want to match based on the
1083fe0972d3SGabor Marton // restrict qualifier because we cannot know if the given libc implementation
1084fe0972d3SGabor Marton // qualifies the paramter type or not.
1085fe0972d3SGabor Marton auto RemoveRestrict = [&FD](QualType T) {
1086fe0972d3SGabor Marton if (!FD->getASTContext().getLangOpts().C99)
1087fe0972d3SGabor Marton T.removeLocalRestrict();
1088fe0972d3SGabor Marton return T;
1089fe0972d3SGabor Marton };
1090bba497fbSArtem Dergachev
1091fe0972d3SGabor Marton // Check the return type.
1092fe0972d3SGabor Marton if (!isIrrelevant(RetTy)) {
1093fe0972d3SGabor Marton QualType FDRetTy = RemoveRestrict(FD->getReturnType().getCanonicalType());
1094fe0972d3SGabor Marton if (RetTy != FDRetTy)
1095fe0972d3SGabor Marton return false;
1096fe0972d3SGabor Marton }
1097fe0972d3SGabor Marton
1098fe0972d3SGabor Marton // Check the argument types.
1099f5086b38SGabor Marton for (size_t I = 0, E = ArgTys.size(); I != E; ++I) {
110016506d78SGabor Marton QualType ArgTy = ArgTys[I];
110116506d78SGabor Marton if (isIrrelevant(ArgTy))
1102bba497fbSArtem Dergachev continue;
1103fe0972d3SGabor Marton QualType FDArgTy =
1104fe0972d3SGabor Marton RemoveRestrict(FD->getParamDecl(I)->getType().getCanonicalType());
1105fe0972d3SGabor Marton if (ArgTy != FDArgTy)
1106bba497fbSArtem Dergachev return false;
1107bba497fbSArtem Dergachev }
1108bba497fbSArtem Dergachev
1109bba497fbSArtem Dergachev return true;
1110bba497fbSArtem Dergachev }
1111bba497fbSArtem Dergachev
1112f5086b38SGabor Marton Optional<StdLibraryFunctionsChecker::Summary>
findFunctionSummary(const FunctionDecl * FD,CheckerContext & C) const1113bba497fbSArtem Dergachev StdLibraryFunctionsChecker::findFunctionSummary(const FunctionDecl *FD,
1114bba497fbSArtem Dergachev CheckerContext &C) const {
1115bba497fbSArtem Dergachev if (!FD)
1116bba497fbSArtem Dergachev return None;
1117bba497fbSArtem Dergachev
1118536456a7SGabor Marton initFunctionSummaries(C);
1119bba497fbSArtem Dergachev
112062e747f6SGabor Marton auto FSMI = FunctionSummaryMap.find(FD->getCanonicalDecl());
1121bba497fbSArtem Dergachev if (FSMI == FunctionSummaryMap.end())
1122bba497fbSArtem Dergachev return None;
112362e747f6SGabor Marton return FSMI->second;
1124bba497fbSArtem Dergachev }
1125bba497fbSArtem Dergachev
112694061df6SGabor Marton Optional<StdLibraryFunctionsChecker::Summary>
findFunctionSummary(const CallEvent & Call,CheckerContext & C) const112794061df6SGabor Marton StdLibraryFunctionsChecker::findFunctionSummary(const CallEvent &Call,
112894061df6SGabor Marton CheckerContext &C) const {
112994061df6SGabor Marton const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
113094061df6SGabor Marton if (!FD)
113194061df6SGabor Marton return None;
11328f961399SGabor Marton return findFunctionSummary(FD, C);
113394061df6SGabor Marton }
113494061df6SGabor Marton
initFunctionSummaries(CheckerContext & C) const1135a787a4edSGabor Marton void StdLibraryFunctionsChecker::initFunctionSummaries(
1136a787a4edSGabor Marton CheckerContext &C) const {
1137c7635040SValeriy Savchenko if (SummariesInitialized)
1138a787a4edSGabor Marton return;
1139a787a4edSGabor Marton
1140a787a4edSGabor Marton SValBuilder &SVB = C.getSValBuilder();
1141a787a4edSGabor Marton BasicValueFactory &BVF = SVB.getBasicValueFactory();
1142a787a4edSGabor Marton const ASTContext &ACtx = BVF.getContext();
1143a787a4edSGabor Marton
1144a787a4edSGabor Marton // Helper class to lookup a type by its name.
1145a787a4edSGabor Marton class LookupType {
1146a787a4edSGabor Marton const ASTContext &ACtx;
1147a787a4edSGabor Marton
1148a787a4edSGabor Marton public:
1149a787a4edSGabor Marton LookupType(const ASTContext &ACtx) : ACtx(ACtx) {}
1150a787a4edSGabor Marton
1151a787a4edSGabor Marton // Find the type. If not found then the optional is not set.
1152a787a4edSGabor Marton llvm::Optional<QualType> operator()(StringRef Name) {
1153634258b8SGabor Marton IdentifierInfo &II = ACtx.Idents.get(Name);
1154634258b8SGabor Marton auto LookupRes = ACtx.getTranslationUnitDecl()->lookup(&II);
11550cb7e7caSVassil Vassilev if (LookupRes.empty())
1156634258b8SGabor Marton return None;
1157634258b8SGabor Marton
1158634258b8SGabor Marton // Prioritze typedef declarations.
1159634258b8SGabor Marton // This is needed in case of C struct typedefs. E.g.:
1160634258b8SGabor Marton // typedef struct FILE FILE;
1161a787a4edSGabor Marton // In this case, we have a RecordDecl 'struct FILE' with the name 'FILE'
1162a787a4edSGabor Marton // and we have a TypedefDecl with the name 'FILE'.
1163db4d5f70SGabor Marton for (Decl *D : LookupRes)
1164634258b8SGabor Marton if (auto *TD = dyn_cast<TypedefNameDecl>(D))
1165634258b8SGabor Marton return ACtx.getTypeDeclType(TD).getCanonicalType();
1166db4d5f70SGabor Marton
1167db4d5f70SGabor Marton // Find the first TypeDecl.
1168db4d5f70SGabor Marton // There maybe cases when a function has the same name as a struct.
1169db4d5f70SGabor Marton // E.g. in POSIX: `struct stat` and the function `stat()`:
1170db4d5f70SGabor Marton // int stat(const char *restrict path, struct stat *restrict buf);
1171db4d5f70SGabor Marton for (Decl *D : LookupRes)
1172db4d5f70SGabor Marton if (auto *TD = dyn_cast<TypeDecl>(D))
1173db4d5f70SGabor Marton return ACtx.getTypeDeclType(TD).getCanonicalType();
1174db4d5f70SGabor Marton return None;
1175634258b8SGabor Marton }
1176a787a4edSGabor Marton } lookupTy(ACtx);
1177634258b8SGabor Marton
1178a787a4edSGabor Marton // Below are auxiliary classes to handle optional types that we get as a
1179a787a4edSGabor Marton // result of the lookup.
1180a787a4edSGabor Marton class GetRestrictTy {
1181a787a4edSGabor Marton const ASTContext &ACtx;
1182bba497fbSArtem Dergachev
1183a787a4edSGabor Marton public:
1184a787a4edSGabor Marton GetRestrictTy(const ASTContext &ACtx) : ACtx(ACtx) {}
1185a787a4edSGabor Marton QualType operator()(QualType Ty) {
11863ff220deSGabor Marton return ACtx.getLangOpts().C99 ? ACtx.getRestrictType(Ty) : Ty;
1187a787a4edSGabor Marton }
1188a787a4edSGabor Marton Optional<QualType> operator()(Optional<QualType> Ty) {
1189a787a4edSGabor Marton if (Ty)
1190a787a4edSGabor Marton return operator()(*Ty);
1191a787a4edSGabor Marton return None;
1192a787a4edSGabor Marton }
1193a787a4edSGabor Marton } getRestrictTy(ACtx);
1194a787a4edSGabor Marton class GetPointerTy {
1195a787a4edSGabor Marton const ASTContext &ACtx;
1196a787a4edSGabor Marton
1197a787a4edSGabor Marton public:
1198a787a4edSGabor Marton GetPointerTy(const ASTContext &ACtx) : ACtx(ACtx) {}
1199a787a4edSGabor Marton QualType operator()(QualType Ty) { return ACtx.getPointerType(Ty); }
1200a787a4edSGabor Marton Optional<QualType> operator()(Optional<QualType> Ty) {
1201a787a4edSGabor Marton if (Ty)
1202a787a4edSGabor Marton return operator()(*Ty);
1203a787a4edSGabor Marton return None;
1204a787a4edSGabor Marton }
1205a787a4edSGabor Marton } getPointerTy(ACtx);
1206a787a4edSGabor Marton class {
1207a787a4edSGabor Marton public:
1208a787a4edSGabor Marton Optional<QualType> operator()(Optional<QualType> Ty) {
1209a787a4edSGabor Marton return Ty ? Optional<QualType>(Ty->withConst()) : None;
1210a787a4edSGabor Marton }
1211a787a4edSGabor Marton QualType operator()(QualType Ty) { return Ty.withConst(); }
1212a787a4edSGabor Marton } getConstTy;
1213a787a4edSGabor Marton class GetMaxValue {
1214a787a4edSGabor Marton BasicValueFactory &BVF;
1215a787a4edSGabor Marton
1216a787a4edSGabor Marton public:
1217a787a4edSGabor Marton GetMaxValue(BasicValueFactory &BVF) : BVF(BVF) {}
1218a787a4edSGabor Marton Optional<RangeInt> operator()(QualType Ty) {
1219a787a4edSGabor Marton return BVF.getMaxValue(Ty).getLimitedValue();
1220a787a4edSGabor Marton }
1221a787a4edSGabor Marton Optional<RangeInt> operator()(Optional<QualType> Ty) {
1222a787a4edSGabor Marton if (Ty) {
1223a787a4edSGabor Marton return operator()(*Ty);
1224a787a4edSGabor Marton }
1225a787a4edSGabor Marton return None;
1226a787a4edSGabor Marton }
1227a787a4edSGabor Marton } getMaxValue(BVF);
12283ff220deSGabor Marton
1229bba497fbSArtem Dergachev // These types are useful for writing specifications quickly,
1230bba497fbSArtem Dergachev // New specifications should probably introduce more types.
123147fec16cSArtem Dergachev // Some types are hard to obtain from the AST, eg. "ssize_t".
123247fec16cSArtem Dergachev // In such cases it should be possible to provide multiple variants
123347fec16cSArtem Dergachev // of function summary for common cases (eg. ssize_t could be int or long
123447fec16cSArtem Dergachev // or long long, so three summary variants would be enough).
123547fec16cSArtem Dergachev // Of course, function variants are also useful for C++ overloads.
1236db4d5f70SGabor Marton const QualType VoidTy = ACtx.VoidTy;
1237a787a4edSGabor Marton const QualType CharTy = ACtx.CharTy;
1238a787a4edSGabor Marton const QualType WCharTy = ACtx.WCharTy;
1239536456a7SGabor Marton const QualType IntTy = ACtx.IntTy;
1240db4d5f70SGabor Marton const QualType UnsignedIntTy = ACtx.UnsignedIntTy;
1241536456a7SGabor Marton const QualType LongTy = ACtx.LongTy;
1242536456a7SGabor Marton const QualType SizeTy = ACtx.getSizeType();
1243db4d5f70SGabor Marton
1244a787a4edSGabor Marton const QualType VoidPtrTy = getPointerTy(VoidTy); // void *
1245a787a4edSGabor Marton const QualType IntPtrTy = getPointerTy(IntTy); // int *
1246db4d5f70SGabor Marton const QualType UnsignedIntPtrTy =
1247a787a4edSGabor Marton getPointerTy(UnsignedIntTy); // unsigned int *
12483ff220deSGabor Marton const QualType VoidPtrRestrictTy = getRestrictTy(VoidPtrTy);
1249ededa65dSGabor Marton const QualType ConstVoidPtrTy =
1250a787a4edSGabor Marton getPointerTy(getConstTy(VoidTy)); // const void *
1251a787a4edSGabor Marton const QualType CharPtrTy = getPointerTy(CharTy); // char *
12523ff220deSGabor Marton const QualType CharPtrRestrictTy = getRestrictTy(CharPtrTy);
12538f961399SGabor Marton const QualType ConstCharPtrTy =
1254a787a4edSGabor Marton getPointerTy(getConstTy(CharTy)); // const char *
12553ff220deSGabor Marton const QualType ConstCharPtrRestrictTy = getRestrictTy(ConstCharPtrTy);
1256a787a4edSGabor Marton const QualType Wchar_tPtrTy = getPointerTy(WCharTy); // wchar_t *
1257db4d5f70SGabor Marton const QualType ConstWchar_tPtrTy =
1258a787a4edSGabor Marton getPointerTy(getConstTy(WCharTy)); // const wchar_t *
12593ff220deSGabor Marton const QualType ConstVoidPtrRestrictTy = getRestrictTy(ConstVoidPtrTy);
1260d0128058SGabor Marton const QualType SizePtrTy = getPointerTy(SizeTy);
1261d0128058SGabor Marton const QualType SizePtrRestrictTy = getRestrictTy(SizePtrTy);
1262bba497fbSArtem Dergachev
1263536456a7SGabor Marton const RangeInt IntMax = BVF.getMaxValue(IntTy).getLimitedValue();
1264db4d5f70SGabor Marton const RangeInt UnsignedIntMax =
1265db4d5f70SGabor Marton BVF.getMaxValue(UnsignedIntTy).getLimitedValue();
1266536456a7SGabor Marton const RangeInt LongMax = BVF.getMaxValue(LongTy).getLimitedValue();
1267db4d5f70SGabor Marton const RangeInt SizeMax = BVF.getMaxValue(SizeTy).getLimitedValue();
1268536456a7SGabor Marton
12690eba5dc8SArtem Dergachev // Set UCharRangeMax to min of int or uchar maximum value.
12700eba5dc8SArtem Dergachev // The C standard states that the arguments of functions like isalpha must
12710eba5dc8SArtem Dergachev // be representable as an unsigned char. Their type is 'int', so the max
12720eba5dc8SArtem Dergachev // value of the argument should be min(UCharMax, IntMax). This just happen
12730eba5dc8SArtem Dergachev // to be true for commonly used and well tested instruction set
12740eba5dc8SArtem Dergachev // architectures, but not for others.
12750eba5dc8SArtem Dergachev const RangeInt UCharRangeMax =
12760eba5dc8SArtem Dergachev std::min(BVF.getMaxValue(ACtx.UnsignedCharTy).getLimitedValue(), IntMax);
1277536456a7SGabor Marton
1278536456a7SGabor Marton // The platform dependent value of EOF.
1279536456a7SGabor Marton // Try our best to parse this from the Preprocessor, otherwise fallback to -1.
1280536456a7SGabor Marton const auto EOFv = [&C]() -> RangeInt {
1281536456a7SGabor Marton if (const llvm::Optional<int> OptInt =
1282536456a7SGabor Marton tryExpandAsInteger("EOF", C.getPreprocessor()))
1283536456a7SGabor Marton return *OptInt;
1284536456a7SGabor Marton return -1;
1285536456a7SGabor Marton }();
1286bba497fbSArtem Dergachev
128762e747f6SGabor Marton // Auxiliary class to aid adding summaries to the summary map.
128862e747f6SGabor Marton struct AddToFunctionSummaryMap {
128962e747f6SGabor Marton const ASTContext &ACtx;
129062e747f6SGabor Marton FunctionSummaryMapType ⤅
1291ff4492c8SGabor Marton bool DisplayLoadedSummaries;
1292ff4492c8SGabor Marton AddToFunctionSummaryMap(const ASTContext &ACtx, FunctionSummaryMapType &FSM,
1293ff4492c8SGabor Marton bool DisplayLoadedSummaries)
1294ff4492c8SGabor Marton : ACtx(ACtx), Map(FSM), DisplayLoadedSummaries(DisplayLoadedSummaries) {
1295ff4492c8SGabor Marton }
1296ff4492c8SGabor Marton
129762e747f6SGabor Marton // Add a summary to a FunctionDecl found by lookup. The lookup is performed
129862e747f6SGabor Marton // by the given Name, and in the global scope. The summary will be attached
129962e747f6SGabor Marton // to the found FunctionDecl only if the signatures match.
13003ff220deSGabor Marton //
13013ff220deSGabor Marton // Returns true if the summary has been added, false otherwise.
130211d2e63aSGabor Marton bool operator()(StringRef Name, Signature Sign, Summary Sum) {
130311d2e63aSGabor Marton if (Sign.isInvalid())
1304a787a4edSGabor Marton return false;
130562e747f6SGabor Marton IdentifierInfo &II = ACtx.Idents.get(Name);
130662e747f6SGabor Marton auto LookupRes = ACtx.getTranslationUnitDecl()->lookup(&II);
13070cb7e7caSVassil Vassilev if (LookupRes.empty())
13083ff220deSGabor Marton return false;
130962e747f6SGabor Marton for (Decl *D : LookupRes) {
131062e747f6SGabor Marton if (auto *FD = dyn_cast<FunctionDecl>(D)) {
131111d2e63aSGabor Marton if (Sum.matchesAndSet(Sign, FD)) {
131211d2e63aSGabor Marton auto Res = Map.insert({FD->getCanonicalDecl(), Sum});
131362e747f6SGabor Marton assert(Res.second && "Function already has a summary set!");
131462e747f6SGabor Marton (void)Res;
1315ff4492c8SGabor Marton if (DisplayLoadedSummaries) {
1316ff4492c8SGabor Marton llvm::errs() << "Loaded summary for: ";
1317ff4492c8SGabor Marton FD->print(llvm::errs());
1318ff4492c8SGabor Marton llvm::errs() << "\n";
1319ff4492c8SGabor Marton }
13203ff220deSGabor Marton return true;
132162e747f6SGabor Marton }
132262e747f6SGabor Marton }
132362e747f6SGabor Marton }
13243ff220deSGabor Marton return false;
13253ff220deSGabor Marton }
1326fe0972d3SGabor Marton // Add the same summary for different names with the Signature explicitly
1327fe0972d3SGabor Marton // given.
1328fe0972d3SGabor Marton void operator()(std::vector<StringRef> Names, Signature Sign, Summary Sum) {
1329fe0972d3SGabor Marton for (StringRef Name : Names)
1330fe0972d3SGabor Marton operator()(Name, Sign, Sum);
1331fe0972d3SGabor Marton }
1332ff4492c8SGabor Marton } addToFunctionSummaryMap(ACtx, FunctionSummaryMap, DisplayLoadedSummaries);
133362e747f6SGabor Marton
1334c6b8484eSGabor Marton // Below are helpers functions to create the summaries.
1335c6b8484eSGabor Marton auto ArgumentCondition = [](ArgNo ArgN, RangeKind Kind,
1336c6b8484eSGabor Marton IntRangeVector Ranges) {
1337c6b8484eSGabor Marton return std::make_shared<RangeConstraint>(ArgN, Kind, Ranges);
1338f5086b38SGabor Marton };
133941928c97SGabor Marton auto BufferSize = [](auto... Args) {
134041928c97SGabor Marton return std::make_shared<BufferSizeConstraint>(Args...);
1341bd03ef19SGabor Marton };
1342c6b8484eSGabor Marton struct {
1343c6b8484eSGabor Marton auto operator()(RangeKind Kind, IntRangeVector Ranges) {
1344c6b8484eSGabor Marton return std::make_shared<RangeConstraint>(Ret, Kind, Ranges);
1345c6b8484eSGabor Marton }
1346c6b8484eSGabor Marton auto operator()(BinaryOperator::Opcode Op, ArgNo OtherArgN) {
1347c6b8484eSGabor Marton return std::make_shared<ComparisonConstraint>(Ret, Op, OtherArgN);
1348c6b8484eSGabor Marton }
1349c6b8484eSGabor Marton } ReturnValueCondition;
1350a787a4edSGabor Marton struct {
1351a787a4edSGabor Marton auto operator()(RangeInt b, RangeInt e) {
1352f5086b38SGabor Marton return IntRangeVector{std::pair<RangeInt, RangeInt>{b, e}};
1353a787a4edSGabor Marton }
1354a787a4edSGabor Marton auto operator()(RangeInt b, Optional<RangeInt> e) {
1355a787a4edSGabor Marton if (e)
1356a787a4edSGabor Marton return IntRangeVector{std::pair<RangeInt, RangeInt>{b, *e}};
1357a787a4edSGabor Marton return IntRangeVector{};
1358a787a4edSGabor Marton }
1359d63a945aSGabor Marton auto operator()(std::pair<RangeInt, RangeInt> i0,
1360d63a945aSGabor Marton std::pair<RangeInt, Optional<RangeInt>> i1) {
1361d63a945aSGabor Marton if (i1.second)
1362d63a945aSGabor Marton return IntRangeVector{i0, {i1.first, *(i1.second)}};
1363d63a945aSGabor Marton return IntRangeVector{i0};
1364d63a945aSGabor Marton }
1365a787a4edSGabor Marton } Range;
1366f5086b38SGabor Marton auto SingleValue = [](RangeInt v) {
1367f5086b38SGabor Marton return IntRangeVector{std::pair<RangeInt, RangeInt>{v, v}};
1368f5086b38SGabor Marton };
1369c6b8484eSGabor Marton auto LessThanOrEq = BO_LE;
1370ededa65dSGabor Marton auto NotNull = [&](ArgNo ArgN) {
1371ededa65dSGabor Marton return std::make_shared<NotNullConstraint>(ArgN);
1372ededa65dSGabor Marton };
1373f5086b38SGabor Marton
1374a787a4edSGabor Marton Optional<QualType> FileTy = lookupTy("FILE");
1375a787a4edSGabor Marton Optional<QualType> FilePtrTy = getPointerTy(FileTy);
1376a787a4edSGabor Marton Optional<QualType> FilePtrRestrictTy = getRestrictTy(FilePtrTy);
1377634258b8SGabor Marton
1378a787a4edSGabor Marton // We are finally ready to define specifications for all supported functions.
1379a787a4edSGabor Marton //
1380a787a4edSGabor Marton // Argument ranges should always cover all variants. If return value
1381a787a4edSGabor Marton // is completely unknown, omit it from the respective range set.
1382a787a4edSGabor Marton //
1383a787a4edSGabor Marton // Every item in the list of range sets represents a particular
1384a787a4edSGabor Marton // execution path the analyzer would need to explore once
1385a787a4edSGabor Marton // the call is modeled - a new program state is constructed
1386a787a4edSGabor Marton // for every range set, and each range line in the range set
1387a787a4edSGabor Marton // corresponds to a specific constraint within this state.
1388a787a4edSGabor Marton
1389bba497fbSArtem Dergachev // The isascii() family of functions.
139094061df6SGabor Marton // The behavior is undefined if the value of the argument is not
139194061df6SGabor Marton // representable as unsigned char or is not equal to EOF. See e.g. C99
139294061df6SGabor Marton // 7.4.1.2 The isalpha function (p: 181-182).
139362e747f6SGabor Marton addToFunctionSummaryMap(
139411d2e63aSGabor Marton "isalnum", Signature(ArgTypes{IntTy}, RetType{IntTy}),
139511d2e63aSGabor Marton Summary(EvalCallAsPure)
1396f5086b38SGabor Marton // Boils down to isupper() or islower() or isdigit().
139762e747f6SGabor Marton .Case({ArgumentCondition(0U, WithinRange,
1398f5086b38SGabor Marton {{'0', '9'}, {'A', 'Z'}, {'a', 'z'}}),
1399f68c0a2fSArtem Dergachev ReturnValueCondition(OutOfRange, SingleValue(0))},
1400957014daSBalázs Kéri ErrnoIrrelevant, "Assuming the character is alphanumeric")
1401f5086b38SGabor Marton // The locale-specific range.
1402bba497fbSArtem Dergachev // No post-condition. We are completely unaware of
1403bba497fbSArtem Dergachev // locale-specific return values.
1404957014daSBalázs Kéri .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})},
1405957014daSBalázs Kéri ErrnoIrrelevant)
140662e747f6SGabor Marton .Case(
140762e747f6SGabor Marton {ArgumentCondition(
140862e747f6SGabor Marton 0U, OutOfRange,
140962e747f6SGabor Marton {{'0', '9'}, {'A', 'Z'}, {'a', 'z'}, {128, UCharRangeMax}}),
1410f68c0a2fSArtem Dergachev ReturnValueCondition(WithinRange, SingleValue(0))},
1411957014daSBalázs Kéri ErrnoIrrelevant, "Assuming the character is non-alphanumeric")
141294061df6SGabor Marton .ArgConstraint(ArgumentCondition(
141362e747f6SGabor Marton 0U, WithinRange, {{EOFv, EOFv}, {0, UCharRangeMax}})));
141462e747f6SGabor Marton addToFunctionSummaryMap(
141511d2e63aSGabor Marton "isalpha", Signature(ArgTypes{IntTy}, RetType{IntTy}),
141611d2e63aSGabor Marton Summary(EvalCallAsPure)
141762e747f6SGabor Marton .Case({ArgumentCondition(0U, WithinRange, {{'A', 'Z'}, {'a', 'z'}}),
1418f68c0a2fSArtem Dergachev ReturnValueCondition(OutOfRange, SingleValue(0))},
1419957014daSBalázs Kéri ErrnoIrrelevant, "Assuming the character is alphabetical")
1420f5086b38SGabor Marton // The locale-specific range.
1421957014daSBalázs Kéri .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})},
1422957014daSBalázs Kéri ErrnoIrrelevant)
1423536456a7SGabor Marton .Case({ArgumentCondition(
1424536456a7SGabor Marton 0U, OutOfRange,
14250eba5dc8SArtem Dergachev {{'A', 'Z'}, {'a', 'z'}, {128, UCharRangeMax}}),
1426f68c0a2fSArtem Dergachev ReturnValueCondition(WithinRange, SingleValue(0))},
1427957014daSBalázs Kéri ErrnoIrrelevant, "Assuming the character is non-alphabetical"));
142862e747f6SGabor Marton addToFunctionSummaryMap(
142911d2e63aSGabor Marton "isascii", Signature(ArgTypes{IntTy}, RetType{IntTy}),
143011d2e63aSGabor Marton Summary(EvalCallAsPure)
1431f5086b38SGabor Marton .Case({ArgumentCondition(0U, WithinRange, Range(0, 127)),
1432f68c0a2fSArtem Dergachev ReturnValueCondition(OutOfRange, SingleValue(0))},
1433957014daSBalázs Kéri ErrnoIrrelevant, "Assuming the character is an ASCII character")
1434f5086b38SGabor Marton .Case({ArgumentCondition(0U, OutOfRange, Range(0, 127)),
1435f68c0a2fSArtem Dergachev ReturnValueCondition(WithinRange, SingleValue(0))},
1436957014daSBalázs Kéri ErrnoIrrelevant,
1437f68c0a2fSArtem Dergachev "Assuming the character is not an ASCII character"));
143862e747f6SGabor Marton addToFunctionSummaryMap(
143911d2e63aSGabor Marton "isblank", Signature(ArgTypes{IntTy}, RetType{IntTy}),
144011d2e63aSGabor Marton Summary(EvalCallAsPure)
144162e747f6SGabor Marton .Case({ArgumentCondition(0U, WithinRange, {{'\t', '\t'}, {' ', ' '}}),
1442f68c0a2fSArtem Dergachev ReturnValueCondition(OutOfRange, SingleValue(0))},
1443957014daSBalázs Kéri ErrnoIrrelevant, "Assuming the character is a blank character")
144462e747f6SGabor Marton .Case({ArgumentCondition(0U, OutOfRange, {{'\t', '\t'}, {' ', ' '}}),
1445f68c0a2fSArtem Dergachev ReturnValueCondition(WithinRange, SingleValue(0))},
1446957014daSBalázs Kéri ErrnoIrrelevant,
1447f68c0a2fSArtem Dergachev "Assuming the character is not a blank character"));
144862e747f6SGabor Marton addToFunctionSummaryMap(
144911d2e63aSGabor Marton "iscntrl", Signature(ArgTypes{IntTy}, RetType{IntTy}),
145011d2e63aSGabor Marton Summary(EvalCallAsPure)
145162e747f6SGabor Marton .Case({ArgumentCondition(0U, WithinRange, {{0, 32}, {127, 127}}),
1452f68c0a2fSArtem Dergachev ReturnValueCondition(OutOfRange, SingleValue(0))},
1453957014daSBalázs Kéri ErrnoIrrelevant,
1454f68c0a2fSArtem Dergachev "Assuming the character is a control character")
145562e747f6SGabor Marton .Case({ArgumentCondition(0U, OutOfRange, {{0, 32}, {127, 127}}),
1456f68c0a2fSArtem Dergachev ReturnValueCondition(WithinRange, SingleValue(0))},
1457957014daSBalázs Kéri ErrnoIrrelevant,
1458f68c0a2fSArtem Dergachev "Assuming the character is not a control character"));
145962e747f6SGabor Marton addToFunctionSummaryMap(
146011d2e63aSGabor Marton "isdigit", Signature(ArgTypes{IntTy}, RetType{IntTy}),
146111d2e63aSGabor Marton Summary(EvalCallAsPure)
1462f5086b38SGabor Marton .Case({ArgumentCondition(0U, WithinRange, Range('0', '9')),
1463f68c0a2fSArtem Dergachev ReturnValueCondition(OutOfRange, SingleValue(0))},
1464957014daSBalázs Kéri ErrnoIrrelevant, "Assuming the character is a digit")
1465f5086b38SGabor Marton .Case({ArgumentCondition(0U, OutOfRange, Range('0', '9')),
1466f68c0a2fSArtem Dergachev ReturnValueCondition(WithinRange, SingleValue(0))},
1467957014daSBalázs Kéri ErrnoIrrelevant, "Assuming the character is not a digit"));
146862e747f6SGabor Marton addToFunctionSummaryMap(
146911d2e63aSGabor Marton "isgraph", Signature(ArgTypes{IntTy}, RetType{IntTy}),
147011d2e63aSGabor Marton Summary(EvalCallAsPure)
1471f5086b38SGabor Marton .Case({ArgumentCondition(0U, WithinRange, Range(33, 126)),
1472f68c0a2fSArtem Dergachev ReturnValueCondition(OutOfRange, SingleValue(0))},
1473957014daSBalázs Kéri ErrnoIrrelevant,
1474f68c0a2fSArtem Dergachev "Assuming the character has graphical representation")
1475f68c0a2fSArtem Dergachev .Case(
1476f68c0a2fSArtem Dergachev {ArgumentCondition(0U, OutOfRange, Range(33, 126)),
1477f68c0a2fSArtem Dergachev ReturnValueCondition(WithinRange, SingleValue(0))},
1478957014daSBalázs Kéri ErrnoIrrelevant,
1479f68c0a2fSArtem Dergachev "Assuming the character does not have graphical representation"));
148062e747f6SGabor Marton addToFunctionSummaryMap(
148111d2e63aSGabor Marton "islower", Signature(ArgTypes{IntTy}, RetType{IntTy}),
148211d2e63aSGabor Marton Summary(EvalCallAsPure)
1483f5086b38SGabor Marton // Is certainly lowercase.
1484f5086b38SGabor Marton .Case({ArgumentCondition(0U, WithinRange, Range('a', 'z')),
1485f68c0a2fSArtem Dergachev ReturnValueCondition(OutOfRange, SingleValue(0))},
1486957014daSBalázs Kéri ErrnoIrrelevant, "Assuming the character is a lowercase letter")
1487f5086b38SGabor Marton // Is ascii but not lowercase.
1488f5086b38SGabor Marton .Case({ArgumentCondition(0U, WithinRange, Range(0, 127)),
1489f5086b38SGabor Marton ArgumentCondition(0U, OutOfRange, Range('a', 'z')),
1490f68c0a2fSArtem Dergachev ReturnValueCondition(WithinRange, SingleValue(0))},
1491957014daSBalázs Kéri ErrnoIrrelevant,
1492f68c0a2fSArtem Dergachev "Assuming the character is not a lowercase letter")
1493f5086b38SGabor Marton // The locale-specific range.
1494957014daSBalázs Kéri .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})},
1495957014daSBalázs Kéri ErrnoIrrelevant)
1496f5086b38SGabor Marton // Is not an unsigned char.
149762e747f6SGabor Marton .Case({ArgumentCondition(0U, OutOfRange, Range(0, UCharRangeMax)),
1498957014daSBalázs Kéri ReturnValueCondition(WithinRange, SingleValue(0))},
1499957014daSBalázs Kéri ErrnoIrrelevant));
150062e747f6SGabor Marton addToFunctionSummaryMap(
150111d2e63aSGabor Marton "isprint", Signature(ArgTypes{IntTy}, RetType{IntTy}),
150211d2e63aSGabor Marton Summary(EvalCallAsPure)
1503f5086b38SGabor Marton .Case({ArgumentCondition(0U, WithinRange, Range(32, 126)),
1504f68c0a2fSArtem Dergachev ReturnValueCondition(OutOfRange, SingleValue(0))},
1505957014daSBalázs Kéri ErrnoIrrelevant, "Assuming the character is printable")
1506f5086b38SGabor Marton .Case({ArgumentCondition(0U, OutOfRange, Range(32, 126)),
1507f68c0a2fSArtem Dergachev ReturnValueCondition(WithinRange, SingleValue(0))},
1508957014daSBalázs Kéri ErrnoIrrelevant, "Assuming the character is non-printable"));
150962e747f6SGabor Marton addToFunctionSummaryMap(
151011d2e63aSGabor Marton "ispunct", Signature(ArgTypes{IntTy}, RetType{IntTy}),
151111d2e63aSGabor Marton Summary(EvalCallAsPure)
1512f5086b38SGabor Marton .Case({ArgumentCondition(
1513f5086b38SGabor Marton 0U, WithinRange,
1514f5086b38SGabor Marton {{'!', '/'}, {':', '@'}, {'[', '`'}, {'{', '~'}}),
1515f68c0a2fSArtem Dergachev ReturnValueCondition(OutOfRange, SingleValue(0))},
1516957014daSBalázs Kéri ErrnoIrrelevant, "Assuming the character is a punctuation mark")
1517f5086b38SGabor Marton .Case({ArgumentCondition(
1518f5086b38SGabor Marton 0U, OutOfRange,
1519f5086b38SGabor Marton {{'!', '/'}, {':', '@'}, {'[', '`'}, {'{', '~'}}),
1520f68c0a2fSArtem Dergachev ReturnValueCondition(WithinRange, SingleValue(0))},
1521957014daSBalázs Kéri ErrnoIrrelevant,
1522f68c0a2fSArtem Dergachev "Assuming the character is not a punctuation mark"));
152362e747f6SGabor Marton addToFunctionSummaryMap(
152411d2e63aSGabor Marton "isspace", Signature(ArgTypes{IntTy}, RetType{IntTy}),
152511d2e63aSGabor Marton Summary(EvalCallAsPure)
1526f5086b38SGabor Marton // Space, '\f', '\n', '\r', '\t', '\v'.
152762e747f6SGabor Marton .Case({ArgumentCondition(0U, WithinRange, {{9, 13}, {' ', ' '}}),
1528f68c0a2fSArtem Dergachev ReturnValueCondition(OutOfRange, SingleValue(0))},
1529957014daSBalázs Kéri ErrnoIrrelevant,
1530f68c0a2fSArtem Dergachev "Assuming the character is a whitespace character")
1531f5086b38SGabor Marton // The locale-specific range.
1532957014daSBalázs Kéri .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})},
1533957014daSBalázs Kéri ErrnoIrrelevant)
153462e747f6SGabor Marton .Case({ArgumentCondition(0U, OutOfRange,
15350eba5dc8SArtem Dergachev {{9, 13}, {' ', ' '}, {128, UCharRangeMax}}),
1536f68c0a2fSArtem Dergachev ReturnValueCondition(WithinRange, SingleValue(0))},
1537957014daSBalázs Kéri ErrnoIrrelevant,
1538f68c0a2fSArtem Dergachev "Assuming the character is not a whitespace character"));
153962e747f6SGabor Marton addToFunctionSummaryMap(
154011d2e63aSGabor Marton "isupper", Signature(ArgTypes{IntTy}, RetType{IntTy}),
154111d2e63aSGabor Marton Summary(EvalCallAsPure)
1542f5086b38SGabor Marton // Is certainly uppercase.
1543f5086b38SGabor Marton .Case({ArgumentCondition(0U, WithinRange, Range('A', 'Z')),
1544f68c0a2fSArtem Dergachev ReturnValueCondition(OutOfRange, SingleValue(0))},
1545957014daSBalázs Kéri ErrnoIrrelevant,
1546f68c0a2fSArtem Dergachev "Assuming the character is an uppercase letter")
1547f5086b38SGabor Marton // The locale-specific range.
1548957014daSBalázs Kéri .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})},
1549957014daSBalázs Kéri ErrnoIrrelevant)
1550f5086b38SGabor Marton // Other.
1551f5086b38SGabor Marton .Case({ArgumentCondition(0U, OutOfRange,
15520eba5dc8SArtem Dergachev {{'A', 'Z'}, {128, UCharRangeMax}}),
1553f68c0a2fSArtem Dergachev ReturnValueCondition(WithinRange, SingleValue(0))},
1554957014daSBalázs Kéri ErrnoIrrelevant,
1555f68c0a2fSArtem Dergachev "Assuming the character is not an uppercase letter"));
155662e747f6SGabor Marton addToFunctionSummaryMap(
155711d2e63aSGabor Marton "isxdigit", Signature(ArgTypes{IntTy}, RetType{IntTy}),
155811d2e63aSGabor Marton Summary(EvalCallAsPure)
155962e747f6SGabor Marton .Case({ArgumentCondition(0U, WithinRange,
1560f5086b38SGabor Marton {{'0', '9'}, {'A', 'F'}, {'a', 'f'}}),
1561f68c0a2fSArtem Dergachev ReturnValueCondition(OutOfRange, SingleValue(0))},
1562957014daSBalázs Kéri ErrnoIrrelevant,
1563f68c0a2fSArtem Dergachev "Assuming the character is a hexadecimal digit")
156462e747f6SGabor Marton .Case({ArgumentCondition(0U, OutOfRange,
1565f5086b38SGabor Marton {{'0', '9'}, {'A', 'F'}, {'a', 'f'}}),
1566f68c0a2fSArtem Dergachev ReturnValueCondition(WithinRange, SingleValue(0))},
1567957014daSBalázs Kéri ErrnoIrrelevant,
1568f68c0a2fSArtem Dergachev "Assuming the character is not a hexadecimal digit"));
156925bbe234SZurab Tsinadze addToFunctionSummaryMap(
157011d2e63aSGabor Marton "toupper", Signature(ArgTypes{IntTy}, RetType{IntTy}),
157111d2e63aSGabor Marton Summary(EvalCallAsPure)
157225bbe234SZurab Tsinadze .ArgConstraint(ArgumentCondition(
157325bbe234SZurab Tsinadze 0U, WithinRange, {{EOFv, EOFv}, {0, UCharRangeMax}})));
157425bbe234SZurab Tsinadze addToFunctionSummaryMap(
157511d2e63aSGabor Marton "tolower", Signature(ArgTypes{IntTy}, RetType{IntTy}),
157611d2e63aSGabor Marton Summary(EvalCallAsPure)
157725bbe234SZurab Tsinadze .ArgConstraint(ArgumentCondition(
157825bbe234SZurab Tsinadze 0U, WithinRange, {{EOFv, EOFv}, {0, UCharRangeMax}})));
157925bbe234SZurab Tsinadze addToFunctionSummaryMap(
158011d2e63aSGabor Marton "toascii", Signature(ArgTypes{IntTy}, RetType{IntTy}),
158111d2e63aSGabor Marton Summary(EvalCallAsPure)
158225bbe234SZurab Tsinadze .ArgConstraint(ArgumentCondition(
158325bbe234SZurab Tsinadze 0U, WithinRange, {{EOFv, EOFv}, {0, UCharRangeMax}})));
1584bba497fbSArtem Dergachev
1585bba497fbSArtem Dergachev // The getc() family of functions that returns either a char or an EOF.
1586a012bc4cSGabor Marton addToFunctionSummaryMap(
1587a012bc4cSGabor Marton {"getc", "fgetc"}, Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
1588a012bc4cSGabor Marton Summary(NoEvalCall)
1589a012bc4cSGabor Marton .Case({ReturnValueCondition(WithinRange,
1590957014daSBalázs Kéri {{EOFv, EOFv}, {0, UCharRangeMax}})},
1591957014daSBalázs Kéri ErrnoIrrelevant));
159262e747f6SGabor Marton addToFunctionSummaryMap(
159311d2e63aSGabor Marton "getchar", Signature(ArgTypes{}, RetType{IntTy}),
159411d2e63aSGabor Marton Summary(NoEvalCall)
159511d2e63aSGabor Marton .Case({ReturnValueCondition(WithinRange,
1596957014daSBalázs Kéri {{EOFv, EOFv}, {0, UCharRangeMax}})},
1597957014daSBalázs Kéri ErrnoIrrelevant));
1598bba497fbSArtem Dergachev
1599bba497fbSArtem Dergachev // read()-like functions that never return more than buffer size.
1600a012bc4cSGabor Marton auto FreadSummary =
1601a012bc4cSGabor Marton Summary(NoEvalCall)
1602b40b3196SGabor Marton .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)),
1603957014daSBalázs Kéri ReturnValueCondition(WithinRange, Range(0, SizeMax))},
1604957014daSBalázs Kéri ErrnoIrrelevant)
1605a012bc4cSGabor Marton .ArgConstraint(NotNull(ArgNo(0)))
1606a012bc4cSGabor Marton .ArgConstraint(NotNull(ArgNo(3)))
1607a012bc4cSGabor Marton .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1),
1608a012bc4cSGabor Marton /*BufSizeMultiplier=*/ArgNo(2)));
1609a012bc4cSGabor Marton
1610a012bc4cSGabor Marton // size_t fread(void *restrict ptr, size_t size, size_t nitems,
1611a012bc4cSGabor Marton // FILE *restrict stream);
1612a012bc4cSGabor Marton addToFunctionSummaryMap(
1613a012bc4cSGabor Marton "fread",
1614a012bc4cSGabor Marton Signature(ArgTypes{VoidPtrRestrictTy, SizeTy, SizeTy, FilePtrRestrictTy},
1615a012bc4cSGabor Marton RetType{SizeTy}),
1616a012bc4cSGabor Marton FreadSummary);
1617a012bc4cSGabor Marton // size_t fwrite(const void *restrict ptr, size_t size, size_t nitems,
1618a012bc4cSGabor Marton // FILE *restrict stream);
1619a012bc4cSGabor Marton addToFunctionSummaryMap("fwrite",
1620a012bc4cSGabor Marton Signature(ArgTypes{ConstVoidPtrRestrictTy, SizeTy,
1621a012bc4cSGabor Marton SizeTy, FilePtrRestrictTy},
1622a012bc4cSGabor Marton RetType{SizeTy}),
1623a012bc4cSGabor Marton FreadSummary);
1624634258b8SGabor Marton
1625d63a945aSGabor Marton Optional<QualType> Ssize_tTy = lookupTy("ssize_t");
1626d63a945aSGabor Marton Optional<RangeInt> Ssize_tMax = getMaxValue(Ssize_tTy);
1627d63a945aSGabor Marton
1628d63a945aSGabor Marton auto ReadSummary =
1629d63a945aSGabor Marton Summary(NoEvalCall)
1630d63a945aSGabor Marton .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)),
1631957014daSBalázs Kéri ReturnValueCondition(WithinRange, Range(-1, Ssize_tMax))},
1632957014daSBalázs Kéri ErrnoIrrelevant);
1633d63a945aSGabor Marton
1634634258b8SGabor Marton // FIXME these are actually defined by POSIX and not by the C standard, we
1635634258b8SGabor Marton // should handle them together with the rest of the POSIX functions.
1636d63a945aSGabor Marton // ssize_t read(int fildes, void *buf, size_t nbyte);
1637d63a945aSGabor Marton addToFunctionSummaryMap(
1638d63a945aSGabor Marton "read", Signature(ArgTypes{IntTy, VoidPtrTy, SizeTy}, RetType{Ssize_tTy}),
1639d63a945aSGabor Marton ReadSummary);
1640d63a945aSGabor Marton // ssize_t write(int fildes, const void *buf, size_t nbyte);
1641d63a945aSGabor Marton addToFunctionSummaryMap(
1642d63a945aSGabor Marton "write",
1643d63a945aSGabor Marton Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTy}, RetType{Ssize_tTy}),
1644d63a945aSGabor Marton ReadSummary);
1645d63a945aSGabor Marton
1646d63a945aSGabor Marton auto GetLineSummary =
1647d63a945aSGabor Marton Summary(NoEvalCall)
1648d63a945aSGabor Marton .Case({ReturnValueCondition(WithinRange,
1649957014daSBalázs Kéri Range({-1, -1}, {1, Ssize_tMax}))},
1650957014daSBalázs Kéri ErrnoIrrelevant);
1651d63a945aSGabor Marton
1652d63a945aSGabor Marton QualType CharPtrPtrRestrictTy = getRestrictTy(getPointerTy(CharPtrTy));
1653634258b8SGabor Marton
1654bba497fbSArtem Dergachev // getline()-like functions either fail or read at least the delimiter.
1655634258b8SGabor Marton // FIXME these are actually defined by POSIX and not by the C standard, we
1656634258b8SGabor Marton // should handle them together with the rest of the POSIX functions.
1657d63a945aSGabor Marton // ssize_t getline(char **restrict lineptr, size_t *restrict n,
1658d63a945aSGabor Marton // FILE *restrict stream);
1659d63a945aSGabor Marton addToFunctionSummaryMap(
1660d63a945aSGabor Marton "getline",
1661d63a945aSGabor Marton Signature(
1662d63a945aSGabor Marton ArgTypes{CharPtrPtrRestrictTy, SizePtrRestrictTy, FilePtrRestrictTy},
1663d63a945aSGabor Marton RetType{Ssize_tTy}),
1664d63a945aSGabor Marton GetLineSummary);
1665d63a945aSGabor Marton // ssize_t getdelim(char **restrict lineptr, size_t *restrict n,
1666d63a945aSGabor Marton // int delimiter, FILE *restrict stream);
1667d63a945aSGabor Marton addToFunctionSummaryMap(
1668d63a945aSGabor Marton "getdelim",
1669d63a945aSGabor Marton Signature(ArgTypes{CharPtrPtrRestrictTy, SizePtrRestrictTy, IntTy,
1670d63a945aSGabor Marton FilePtrRestrictTy},
1671d63a945aSGabor Marton RetType{Ssize_tTy}),
1672d63a945aSGabor Marton GetLineSummary);
16731525232eSGabor Marton
1674edde4efcSBalazs Benics {
1675f68c0a2fSArtem Dergachev Summary GetenvSummary =
1676f68c0a2fSArtem Dergachev Summary(NoEvalCall)
1677edde4efcSBalazs Benics .ArgConstraint(NotNull(ArgNo(0)))
1678957014daSBalázs Kéri .Case({NotNull(Ret)}, ErrnoIrrelevant,
1679957014daSBalázs Kéri "Assuming the environment variable exists");
1680edde4efcSBalazs Benics // In untrusted environments the envvar might not exist.
1681edde4efcSBalazs Benics if (!ShouldAssumeControlledEnvironment)
1682957014daSBalázs Kéri GetenvSummary.Case({NotNull(Ret)->negate()}, ErrnoIrrelevant,
1683f68c0a2fSArtem Dergachev "Assuming the environment variable does not exist");
1684edde4efcSBalazs Benics
16857fc15030SBalazs Benics // char *getenv(const char *name);
16867fc15030SBalazs Benics addToFunctionSummaryMap(
16877fc15030SBalazs Benics "getenv", Signature(ArgTypes{ConstCharPtrTy}, RetType{CharPtrTy}),
1688edde4efcSBalazs Benics std::move(GetenvSummary));
1689edde4efcSBalazs Benics }
16907fc15030SBalazs Benics
1691db4d5f70SGabor Marton if (ModelPOSIX) {
1692db4d5f70SGabor Marton
1693db4d5f70SGabor Marton // long a64l(const char *str64);
1694db4d5f70SGabor Marton addToFunctionSummaryMap(
169511d2e63aSGabor Marton "a64l", Signature(ArgTypes{ConstCharPtrTy}, RetType{LongTy}),
169611d2e63aSGabor Marton Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
1697db4d5f70SGabor Marton
1698db4d5f70SGabor Marton // char *l64a(long value);
169911d2e63aSGabor Marton addToFunctionSummaryMap("l64a",
170011d2e63aSGabor Marton Signature(ArgTypes{LongTy}, RetType{CharPtrTy}),
170111d2e63aSGabor Marton Summary(NoEvalCall)
170211d2e63aSGabor Marton .ArgConstraint(ArgumentCondition(
170311d2e63aSGabor Marton 0, WithinRange, Range(0, LongMax))));
1704db4d5f70SGabor Marton
1705febe7503SGabor Marton const auto ReturnsZeroOrMinusOne =
1706febe7503SGabor Marton ConstraintSet{ReturnValueCondition(WithinRange, Range(-1, 0))};
1707957014daSBalázs Kéri const auto ReturnsZero =
1708957014daSBalázs Kéri ConstraintSet{ReturnValueCondition(WithinRange, SingleValue(0))};
1709957014daSBalázs Kéri const auto ReturnsMinusOne =
1710957014daSBalázs Kéri ConstraintSet{ReturnValueCondition(WithinRange, SingleValue(-1))};
1711957014daSBalázs Kéri const auto ReturnsNonnegative =
1712957014daSBalázs Kéri ConstraintSet{ReturnValueCondition(WithinRange, Range(0, IntMax))};
1713febe7503SGabor Marton const auto ReturnsFileDescriptor =
1714febe7503SGabor Marton ConstraintSet{ReturnValueCondition(WithinRange, Range(-1, IntMax))};
1715957014daSBalázs Kéri const auto &ReturnsValidFileDescriptor = ReturnsNonnegative;
1716febe7503SGabor Marton
1717db4d5f70SGabor Marton // int access(const char *pathname, int amode);
171811d2e63aSGabor Marton addToFunctionSummaryMap(
171911d2e63aSGabor Marton "access", Signature(ArgTypes{ConstCharPtrTy, IntTy}, RetType{IntTy}),
1720febe7503SGabor Marton Summary(NoEvalCall)
1721957014daSBalázs Kéri .Case(ReturnsZero, ErrnoMustNotBeChecked)
1722957014daSBalázs Kéri .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
1723febe7503SGabor Marton .ArgConstraint(NotNull(ArgNo(0))));
1724db4d5f70SGabor Marton
1725db4d5f70SGabor Marton // int faccessat(int dirfd, const char *pathname, int mode, int flags);
1726db4d5f70SGabor Marton addToFunctionSummaryMap(
172711d2e63aSGabor Marton "faccessat",
172811d2e63aSGabor Marton Signature(ArgTypes{IntTy, ConstCharPtrTy, IntTy, IntTy},
172911d2e63aSGabor Marton RetType{IntTy}),
1730febe7503SGabor Marton Summary(NoEvalCall)
1731957014daSBalázs Kéri .Case(ReturnsZero, ErrnoMustNotBeChecked)
1732957014daSBalázs Kéri .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
1733febe7503SGabor Marton .ArgConstraint(NotNull(ArgNo(1))));
1734db4d5f70SGabor Marton
1735db4d5f70SGabor Marton // int dup(int fildes);
1736957014daSBalázs Kéri addToFunctionSummaryMap(
1737957014daSBalázs Kéri "dup", Signature(ArgTypes{IntTy}, RetType{IntTy}),
173811d2e63aSGabor Marton Summary(NoEvalCall)
1739957014daSBalázs Kéri .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked)
1740957014daSBalázs Kéri .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
1741957014daSBalázs Kéri .ArgConstraint(
1742957014daSBalázs Kéri ArgumentCondition(0, WithinRange, Range(0, IntMax))));
1743db4d5f70SGabor Marton
1744db4d5f70SGabor Marton // int dup2(int fildes1, int filedes2);
1745db4d5f70SGabor Marton addToFunctionSummaryMap(
174611d2e63aSGabor Marton "dup2", Signature(ArgTypes{IntTy, IntTy}, RetType{IntTy}),
174711d2e63aSGabor Marton Summary(NoEvalCall)
1748957014daSBalázs Kéri .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked)
1749957014daSBalázs Kéri .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
1750db4d5f70SGabor Marton .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
1751db4d5f70SGabor Marton .ArgConstraint(
1752db4d5f70SGabor Marton ArgumentCondition(1, WithinRange, Range(0, IntMax))));
1753db4d5f70SGabor Marton
1754db4d5f70SGabor Marton // int fdatasync(int fildes);
175511d2e63aSGabor Marton addToFunctionSummaryMap("fdatasync",
175611d2e63aSGabor Marton Signature(ArgTypes{IntTy}, RetType{IntTy}),
175711d2e63aSGabor Marton Summary(NoEvalCall)
1758957014daSBalázs Kéri .Case(ReturnsZero, ErrnoMustNotBeChecked)
1759957014daSBalázs Kéri .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
176011d2e63aSGabor Marton .ArgConstraint(ArgumentCondition(
176111d2e63aSGabor Marton 0, WithinRange, Range(0, IntMax))));
1762db4d5f70SGabor Marton
1763db4d5f70SGabor Marton // int fnmatch(const char *pattern, const char *string, int flags);
1764db4d5f70SGabor Marton addToFunctionSummaryMap(
176511d2e63aSGabor Marton "fnmatch",
176611d2e63aSGabor Marton Signature(ArgTypes{ConstCharPtrTy, ConstCharPtrTy, IntTy},
176711d2e63aSGabor Marton RetType{IntTy}),
1768957014daSBalázs Kéri Summary(NoEvalCall)
1769db4d5f70SGabor Marton .ArgConstraint(NotNull(ArgNo(0)))
1770db4d5f70SGabor Marton .ArgConstraint(NotNull(ArgNo(1))));
1771db4d5f70SGabor Marton
1772db4d5f70SGabor Marton // int fsync(int fildes);
177311d2e63aSGabor Marton addToFunctionSummaryMap("fsync", Signature(ArgTypes{IntTy}, RetType{IntTy}),
177411d2e63aSGabor Marton Summary(NoEvalCall)
1775957014daSBalázs Kéri .Case(ReturnsZero, ErrnoMustNotBeChecked)
1776957014daSBalázs Kéri .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
177711d2e63aSGabor Marton .ArgConstraint(ArgumentCondition(
177811d2e63aSGabor Marton 0, WithinRange, Range(0, IntMax))));
1779db4d5f70SGabor Marton
1780a787a4edSGabor Marton Optional<QualType> Off_tTy = lookupTy("off_t");
1781db4d5f70SGabor Marton
1782db4d5f70SGabor Marton // int truncate(const char *path, off_t length);
1783a787a4edSGabor Marton addToFunctionSummaryMap(
1784a787a4edSGabor Marton "truncate",
178511d2e63aSGabor Marton Signature(ArgTypes{ConstCharPtrTy, Off_tTy}, RetType{IntTy}),
1786febe7503SGabor Marton Summary(NoEvalCall)
1787957014daSBalázs Kéri .Case(ReturnsZero, ErrnoMustNotBeChecked)
1788957014daSBalázs Kéri .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
1789febe7503SGabor Marton .ArgConstraint(NotNull(ArgNo(0))));
1790db4d5f70SGabor Marton
1791db4d5f70SGabor Marton // int symlink(const char *oldpath, const char *newpath);
179211d2e63aSGabor Marton addToFunctionSummaryMap(
179311d2e63aSGabor Marton "symlink",
179411d2e63aSGabor Marton Signature(ArgTypes{ConstCharPtrTy, ConstCharPtrTy}, RetType{IntTy}),
179511d2e63aSGabor Marton Summary(NoEvalCall)
1796957014daSBalázs Kéri .Case(ReturnsZero, ErrnoMustNotBeChecked)
1797957014daSBalázs Kéri .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
1798db4d5f70SGabor Marton .ArgConstraint(NotNull(ArgNo(0)))
1799db4d5f70SGabor Marton .ArgConstraint(NotNull(ArgNo(1))));
1800db4d5f70SGabor Marton
1801db4d5f70SGabor Marton // int symlinkat(const char *oldpath, int newdirfd, const char *newpath);
1802db4d5f70SGabor Marton addToFunctionSummaryMap(
1803db4d5f70SGabor Marton "symlinkat",
180411d2e63aSGabor Marton Signature(ArgTypes{ConstCharPtrTy, IntTy, ConstCharPtrTy},
180511d2e63aSGabor Marton RetType{IntTy}),
180611d2e63aSGabor Marton Summary(NoEvalCall)
1807957014daSBalázs Kéri .Case(ReturnsZero, ErrnoMustNotBeChecked)
1808957014daSBalázs Kéri .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
1809db4d5f70SGabor Marton .ArgConstraint(NotNull(ArgNo(0)))
1810db4d5f70SGabor Marton .ArgConstraint(ArgumentCondition(1, WithinRange, Range(0, IntMax)))
1811db4d5f70SGabor Marton .ArgConstraint(NotNull(ArgNo(2))));
1812db4d5f70SGabor Marton
1813db4d5f70SGabor Marton // int lockf(int fd, int cmd, off_t len);
1814db4d5f70SGabor Marton addToFunctionSummaryMap(
181511d2e63aSGabor Marton "lockf", Signature(ArgTypes{IntTy, IntTy, Off_tTy}, RetType{IntTy}),
181611d2e63aSGabor Marton Summary(NoEvalCall)
1817957014daSBalázs Kéri .Case(ReturnsZero, ErrnoMustNotBeChecked)
1818957014daSBalázs Kéri .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
1819db4d5f70SGabor Marton .ArgConstraint(
1820db4d5f70SGabor Marton ArgumentCondition(0, WithinRange, Range(0, IntMax))));
1821db4d5f70SGabor Marton
1822a787a4edSGabor Marton Optional<QualType> Mode_tTy = lookupTy("mode_t");
1823db4d5f70SGabor Marton
1824db4d5f70SGabor Marton // int creat(const char *pathname, mode_t mode);
182511d2e63aSGabor Marton addToFunctionSummaryMap(
182611d2e63aSGabor Marton "creat", Signature(ArgTypes{ConstCharPtrTy, Mode_tTy}, RetType{IntTy}),
1827febe7503SGabor Marton Summary(NoEvalCall)
1828957014daSBalázs Kéri .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked)
1829957014daSBalázs Kéri .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
1830febe7503SGabor Marton .ArgConstraint(NotNull(ArgNo(0))));
1831db4d5f70SGabor Marton
1832db4d5f70SGabor Marton // unsigned int sleep(unsigned int seconds);
1833db4d5f70SGabor Marton addToFunctionSummaryMap(
183411d2e63aSGabor Marton "sleep", Signature(ArgTypes{UnsignedIntTy}, RetType{UnsignedIntTy}),
183511d2e63aSGabor Marton Summary(NoEvalCall)
1836db4d5f70SGabor Marton .ArgConstraint(
1837db4d5f70SGabor Marton ArgumentCondition(0, WithinRange, Range(0, UnsignedIntMax))));
1838db4d5f70SGabor Marton
1839a787a4edSGabor Marton Optional<QualType> DirTy = lookupTy("DIR");
1840a787a4edSGabor Marton Optional<QualType> DirPtrTy = getPointerTy(DirTy);
1841db4d5f70SGabor Marton
1842db4d5f70SGabor Marton // int dirfd(DIR *dirp);
1843957014daSBalázs Kéri addToFunctionSummaryMap(
1844957014daSBalázs Kéri "dirfd", Signature(ArgTypes{DirPtrTy}, RetType{IntTy}),
1845febe7503SGabor Marton Summary(NoEvalCall)
1846957014daSBalázs Kéri .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked)
1847957014daSBalázs Kéri .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
1848febe7503SGabor Marton .ArgConstraint(NotNull(ArgNo(0))));
1849db4d5f70SGabor Marton
1850db4d5f70SGabor Marton // unsigned int alarm(unsigned int seconds);
1851db4d5f70SGabor Marton addToFunctionSummaryMap(
185211d2e63aSGabor Marton "alarm", Signature(ArgTypes{UnsignedIntTy}, RetType{UnsignedIntTy}),
185311d2e63aSGabor Marton Summary(NoEvalCall)
1854db4d5f70SGabor Marton .ArgConstraint(
1855db4d5f70SGabor Marton ArgumentCondition(0, WithinRange, Range(0, UnsignedIntMax))));
1856db4d5f70SGabor Marton
1857db4d5f70SGabor Marton // int closedir(DIR *dir);
1858febe7503SGabor Marton addToFunctionSummaryMap("closedir",
1859febe7503SGabor Marton Signature(ArgTypes{DirPtrTy}, RetType{IntTy}),
1860febe7503SGabor Marton Summary(NoEvalCall)
1861957014daSBalázs Kéri .Case(ReturnsZero, ErrnoMustNotBeChecked)
1862957014daSBalázs Kéri .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
1863febe7503SGabor Marton .ArgConstraint(NotNull(ArgNo(0))));
1864db4d5f70SGabor Marton
1865db4d5f70SGabor Marton // char *strdup(const char *s);
186611d2e63aSGabor Marton addToFunctionSummaryMap(
186711d2e63aSGabor Marton "strdup", Signature(ArgTypes{ConstCharPtrTy}, RetType{CharPtrTy}),
186811d2e63aSGabor Marton Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
1869db4d5f70SGabor Marton
1870db4d5f70SGabor Marton // char *strndup(const char *s, size_t n);
1871db4d5f70SGabor Marton addToFunctionSummaryMap(
187211d2e63aSGabor Marton "strndup",
187311d2e63aSGabor Marton Signature(ArgTypes{ConstCharPtrTy, SizeTy}, RetType{CharPtrTy}),
187411d2e63aSGabor Marton Summary(NoEvalCall)
1875db4d5f70SGabor Marton .ArgConstraint(NotNull(ArgNo(0)))
187611d2e63aSGabor Marton .ArgConstraint(
187711d2e63aSGabor Marton ArgumentCondition(1, WithinRange, Range(0, SizeMax))));
1878db4d5f70SGabor Marton
1879db4d5f70SGabor Marton // wchar_t *wcsdup(const wchar_t *s);
188011d2e63aSGabor Marton addToFunctionSummaryMap(
188111d2e63aSGabor Marton "wcsdup", Signature(ArgTypes{ConstWchar_tPtrTy}, RetType{Wchar_tPtrTy}),
188211d2e63aSGabor Marton Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
1883db4d5f70SGabor Marton
1884db4d5f70SGabor Marton // int mkstemp(char *template);
1885957014daSBalázs Kéri addToFunctionSummaryMap(
1886957014daSBalázs Kéri "mkstemp", Signature(ArgTypes{CharPtrTy}, RetType{IntTy}),
1887febe7503SGabor Marton Summary(NoEvalCall)
1888957014daSBalázs Kéri .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked)
1889957014daSBalázs Kéri .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
1890febe7503SGabor Marton .ArgConstraint(NotNull(ArgNo(0))));
1891db4d5f70SGabor Marton
1892db4d5f70SGabor Marton // char *mkdtemp(char *template);
1893957014daSBalázs Kéri // FIXME: Improve for errno modeling.
1894db4d5f70SGabor Marton addToFunctionSummaryMap(
189511d2e63aSGabor Marton "mkdtemp", Signature(ArgTypes{CharPtrTy}, RetType{CharPtrTy}),
189611d2e63aSGabor Marton Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
1897db4d5f70SGabor Marton
1898db4d5f70SGabor Marton // char *getcwd(char *buf, size_t size);
1899957014daSBalázs Kéri // FIXME: Improve for errno modeling.
1900db4d5f70SGabor Marton addToFunctionSummaryMap(
190111d2e63aSGabor Marton "getcwd", Signature(ArgTypes{CharPtrTy, SizeTy}, RetType{CharPtrTy}),
190211d2e63aSGabor Marton Summary(NoEvalCall)
1903db4d5f70SGabor Marton .ArgConstraint(
1904db4d5f70SGabor Marton ArgumentCondition(1, WithinRange, Range(0, SizeMax))));
1905db4d5f70SGabor Marton
1906db4d5f70SGabor Marton // int mkdir(const char *pathname, mode_t mode);
190711d2e63aSGabor Marton addToFunctionSummaryMap(
190811d2e63aSGabor Marton "mkdir", Signature(ArgTypes{ConstCharPtrTy, Mode_tTy}, RetType{IntTy}),
1909febe7503SGabor Marton Summary(NoEvalCall)
19107dc81c62SBalázs Kéri .Case(ReturnsZero, ErrnoMustNotBeChecked)
1911957014daSBalázs Kéri .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
1912febe7503SGabor Marton .ArgConstraint(NotNull(ArgNo(0))));
1913db4d5f70SGabor Marton
1914db4d5f70SGabor Marton // int mkdirat(int dirfd, const char *pathname, mode_t mode);
191511d2e63aSGabor Marton addToFunctionSummaryMap(
191611d2e63aSGabor Marton "mkdirat",
191711d2e63aSGabor Marton Signature(ArgTypes{IntTy, ConstCharPtrTy, Mode_tTy}, RetType{IntTy}),
1918febe7503SGabor Marton Summary(NoEvalCall)
19197dc81c62SBalázs Kéri .Case(ReturnsZero, ErrnoMustNotBeChecked)
1920957014daSBalázs Kéri .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
1921febe7503SGabor Marton .ArgConstraint(NotNull(ArgNo(1))));
1922db4d5f70SGabor Marton
1923a787a4edSGabor Marton Optional<QualType> Dev_tTy = lookupTy("dev_t");
1924db4d5f70SGabor Marton
1925db4d5f70SGabor Marton // int mknod(const char *pathname, mode_t mode, dev_t dev);
192611d2e63aSGabor Marton addToFunctionSummaryMap(
192711d2e63aSGabor Marton "mknod",
192811d2e63aSGabor Marton Signature(ArgTypes{ConstCharPtrTy, Mode_tTy, Dev_tTy}, RetType{IntTy}),
1929febe7503SGabor Marton Summary(NoEvalCall)
19307dc81c62SBalázs Kéri .Case(ReturnsZero, ErrnoMustNotBeChecked)
1931957014daSBalázs Kéri .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
1932febe7503SGabor Marton .ArgConstraint(NotNull(ArgNo(0))));
1933db4d5f70SGabor Marton
1934db4d5f70SGabor Marton // int mknodat(int dirfd, const char *pathname, mode_t mode, dev_t dev);
1935a787a4edSGabor Marton addToFunctionSummaryMap(
193611d2e63aSGabor Marton "mknodat",
193711d2e63aSGabor Marton Signature(ArgTypes{IntTy, ConstCharPtrTy, Mode_tTy, Dev_tTy},
193811d2e63aSGabor Marton RetType{IntTy}),
1939febe7503SGabor Marton Summary(NoEvalCall)
19407dc81c62SBalázs Kéri .Case(ReturnsZero, ErrnoMustNotBeChecked)
1941957014daSBalázs Kéri .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
1942febe7503SGabor Marton .ArgConstraint(NotNull(ArgNo(1))));
1943db4d5f70SGabor Marton
1944db4d5f70SGabor Marton // int chmod(const char *path, mode_t mode);
194511d2e63aSGabor Marton addToFunctionSummaryMap(
194611d2e63aSGabor Marton "chmod", Signature(ArgTypes{ConstCharPtrTy, Mode_tTy}, RetType{IntTy}),
1947febe7503SGabor Marton Summary(NoEvalCall)
1948957014daSBalázs Kéri .Case(ReturnsZero, ErrnoMustNotBeChecked)
1949957014daSBalázs Kéri .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
1950febe7503SGabor Marton .ArgConstraint(NotNull(ArgNo(0))));
1951db4d5f70SGabor Marton
1952db4d5f70SGabor Marton // int fchmodat(int dirfd, const char *pathname, mode_t mode, int flags);
1953db4d5f70SGabor Marton addToFunctionSummaryMap(
1954a787a4edSGabor Marton "fchmodat",
195511d2e63aSGabor Marton Signature(ArgTypes{IntTy, ConstCharPtrTy, Mode_tTy, IntTy},
195611d2e63aSGabor Marton RetType{IntTy}),
195711d2e63aSGabor Marton Summary(NoEvalCall)
1958957014daSBalázs Kéri .Case(ReturnsZero, ErrnoMustNotBeChecked)
1959957014daSBalázs Kéri .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
1960a787a4edSGabor Marton .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
1961db4d5f70SGabor Marton .ArgConstraint(NotNull(ArgNo(1))));
1962db4d5f70SGabor Marton
1963db4d5f70SGabor Marton // int fchmod(int fildes, mode_t mode);
1964db4d5f70SGabor Marton addToFunctionSummaryMap(
196511d2e63aSGabor Marton "fchmod", Signature(ArgTypes{IntTy, Mode_tTy}, RetType{IntTy}),
196611d2e63aSGabor Marton Summary(NoEvalCall)
1967957014daSBalázs Kéri .Case(ReturnsZero, ErrnoMustNotBeChecked)
1968957014daSBalázs Kéri .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
1969db4d5f70SGabor Marton .ArgConstraint(
1970db4d5f70SGabor Marton ArgumentCondition(0, WithinRange, Range(0, IntMax))));
1971db4d5f70SGabor Marton
1972a787a4edSGabor Marton Optional<QualType> Uid_tTy = lookupTy("uid_t");
1973a787a4edSGabor Marton Optional<QualType> Gid_tTy = lookupTy("gid_t");
1974db4d5f70SGabor Marton
1975db4d5f70SGabor Marton // int fchownat(int dirfd, const char *pathname, uid_t owner, gid_t group,
1976db4d5f70SGabor Marton // int flags);
1977db4d5f70SGabor Marton addToFunctionSummaryMap(
1978db4d5f70SGabor Marton "fchownat",
197911d2e63aSGabor Marton Signature(ArgTypes{IntTy, ConstCharPtrTy, Uid_tTy, Gid_tTy, IntTy},
198011d2e63aSGabor Marton RetType{IntTy}),
198111d2e63aSGabor Marton Summary(NoEvalCall)
1982957014daSBalázs Kéri .Case(ReturnsZero, ErrnoMustNotBeChecked)
1983957014daSBalázs Kéri .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
1984a787a4edSGabor Marton .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
1985db4d5f70SGabor Marton .ArgConstraint(NotNull(ArgNo(1))));
1986db4d5f70SGabor Marton
1987db4d5f70SGabor Marton // int chown(const char *path, uid_t owner, gid_t group);
198811d2e63aSGabor Marton addToFunctionSummaryMap(
198911d2e63aSGabor Marton "chown",
199011d2e63aSGabor Marton Signature(ArgTypes{ConstCharPtrTy, Uid_tTy, Gid_tTy}, RetType{IntTy}),
1991febe7503SGabor Marton Summary(NoEvalCall)
1992957014daSBalázs Kéri .Case(ReturnsZero, ErrnoMustNotBeChecked)
1993957014daSBalázs Kéri .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
1994febe7503SGabor Marton .ArgConstraint(NotNull(ArgNo(0))));
1995db4d5f70SGabor Marton
1996db4d5f70SGabor Marton // int lchown(const char *path, uid_t owner, gid_t group);
199711d2e63aSGabor Marton addToFunctionSummaryMap(
199811d2e63aSGabor Marton "lchown",
199911d2e63aSGabor Marton Signature(ArgTypes{ConstCharPtrTy, Uid_tTy, Gid_tTy}, RetType{IntTy}),
2000febe7503SGabor Marton Summary(NoEvalCall)
2001957014daSBalázs Kéri .Case(ReturnsZero, ErrnoMustNotBeChecked)
2002957014daSBalázs Kéri .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2003febe7503SGabor Marton .ArgConstraint(NotNull(ArgNo(0))));
2004db4d5f70SGabor Marton
2005db4d5f70SGabor Marton // int fchown(int fildes, uid_t owner, gid_t group);
2006db4d5f70SGabor Marton addToFunctionSummaryMap(
200711d2e63aSGabor Marton "fchown", Signature(ArgTypes{IntTy, Uid_tTy, Gid_tTy}, RetType{IntTy}),
200811d2e63aSGabor Marton Summary(NoEvalCall)
2009957014daSBalázs Kéri .Case(ReturnsZero, ErrnoMustNotBeChecked)
2010957014daSBalázs Kéri .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2011a787a4edSGabor Marton .ArgConstraint(
2012a787a4edSGabor Marton ArgumentCondition(0, WithinRange, Range(0, IntMax))));
2013db4d5f70SGabor Marton
2014db4d5f70SGabor Marton // int rmdir(const char *pathname);
2015febe7503SGabor Marton addToFunctionSummaryMap("rmdir",
2016febe7503SGabor Marton Signature(ArgTypes{ConstCharPtrTy}, RetType{IntTy}),
2017febe7503SGabor Marton Summary(NoEvalCall)
2018957014daSBalázs Kéri .Case(ReturnsZero, ErrnoMustNotBeChecked)
2019957014daSBalázs Kéri .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2020febe7503SGabor Marton .ArgConstraint(NotNull(ArgNo(0))));
2021db4d5f70SGabor Marton
2022db4d5f70SGabor Marton // int chdir(const char *path);
2023febe7503SGabor Marton addToFunctionSummaryMap("chdir",
2024febe7503SGabor Marton Signature(ArgTypes{ConstCharPtrTy}, RetType{IntTy}),
2025febe7503SGabor Marton Summary(NoEvalCall)
2026957014daSBalázs Kéri .Case(ReturnsZero, ErrnoMustNotBeChecked)
2027957014daSBalázs Kéri .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2028febe7503SGabor Marton .ArgConstraint(NotNull(ArgNo(0))));
2029db4d5f70SGabor Marton
2030db4d5f70SGabor Marton // int link(const char *oldpath, const char *newpath);
203111d2e63aSGabor Marton addToFunctionSummaryMap(
203211d2e63aSGabor Marton "link",
203311d2e63aSGabor Marton Signature(ArgTypes{ConstCharPtrTy, ConstCharPtrTy}, RetType{IntTy}),
203411d2e63aSGabor Marton Summary(NoEvalCall)
2035957014daSBalázs Kéri .Case(ReturnsZero, ErrnoMustNotBeChecked)
2036957014daSBalázs Kéri .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2037db4d5f70SGabor Marton .ArgConstraint(NotNull(ArgNo(0)))
2038db4d5f70SGabor Marton .ArgConstraint(NotNull(ArgNo(1))));
2039db4d5f70SGabor Marton
2040db4d5f70SGabor Marton // int linkat(int fd1, const char *path1, int fd2, const char *path2,
2041db4d5f70SGabor Marton // int flag);
2042db4d5f70SGabor Marton addToFunctionSummaryMap(
2043db4d5f70SGabor Marton "linkat",
204411d2e63aSGabor Marton Signature(ArgTypes{IntTy, ConstCharPtrTy, IntTy, ConstCharPtrTy, IntTy},
204511d2e63aSGabor Marton RetType{IntTy}),
204611d2e63aSGabor Marton Summary(NoEvalCall)
2047957014daSBalázs Kéri .Case(ReturnsZero, ErrnoMustNotBeChecked)
2048957014daSBalázs Kéri .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2049db4d5f70SGabor Marton .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
2050db4d5f70SGabor Marton .ArgConstraint(NotNull(ArgNo(1)))
2051db4d5f70SGabor Marton .ArgConstraint(ArgumentCondition(2, WithinRange, Range(0, IntMax)))
2052db4d5f70SGabor Marton .ArgConstraint(NotNull(ArgNo(3))));
2053db4d5f70SGabor Marton
2054db4d5f70SGabor Marton // int unlink(const char *pathname);
2055febe7503SGabor Marton addToFunctionSummaryMap("unlink",
2056febe7503SGabor Marton Signature(ArgTypes{ConstCharPtrTy}, RetType{IntTy}),
2057febe7503SGabor Marton Summary(NoEvalCall)
2058957014daSBalázs Kéri .Case(ReturnsZero, ErrnoMustNotBeChecked)
2059957014daSBalázs Kéri .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2060febe7503SGabor Marton .ArgConstraint(NotNull(ArgNo(0))));
2061db4d5f70SGabor Marton
2062db4d5f70SGabor Marton // int unlinkat(int fd, const char *path, int flag);
2063db4d5f70SGabor Marton addToFunctionSummaryMap(
2064db4d5f70SGabor Marton "unlinkat",
206511d2e63aSGabor Marton Signature(ArgTypes{IntTy, ConstCharPtrTy, IntTy}, RetType{IntTy}),
206611d2e63aSGabor Marton Summary(NoEvalCall)
2067957014daSBalázs Kéri .Case(ReturnsZero, ErrnoMustNotBeChecked)
2068957014daSBalázs Kéri .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2069db4d5f70SGabor Marton .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
2070db4d5f70SGabor Marton .ArgConstraint(NotNull(ArgNo(1))));
2071db4d5f70SGabor Marton
2072a787a4edSGabor Marton Optional<QualType> StructStatTy = lookupTy("stat");
2073a787a4edSGabor Marton Optional<QualType> StructStatPtrTy = getPointerTy(StructStatTy);
2074a787a4edSGabor Marton Optional<QualType> StructStatPtrRestrictTy = getRestrictTy(StructStatPtrTy);
2075db4d5f70SGabor Marton
2076db4d5f70SGabor Marton // int fstat(int fd, struct stat *statbuf);
2077db4d5f70SGabor Marton addToFunctionSummaryMap(
207811d2e63aSGabor Marton "fstat", Signature(ArgTypes{IntTy, StructStatPtrTy}, RetType{IntTy}),
207911d2e63aSGabor Marton Summary(NoEvalCall)
2080957014daSBalázs Kéri .Case(ReturnsZero, ErrnoMustNotBeChecked)
2081957014daSBalázs Kéri .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2082a787a4edSGabor Marton .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
2083db4d5f70SGabor Marton .ArgConstraint(NotNull(ArgNo(1))));
2084db4d5f70SGabor Marton
2085db4d5f70SGabor Marton // int stat(const char *restrict path, struct stat *restrict buf);
208611d2e63aSGabor Marton addToFunctionSummaryMap(
208711d2e63aSGabor Marton "stat",
208811d2e63aSGabor Marton Signature(ArgTypes{ConstCharPtrRestrictTy, StructStatPtrRestrictTy},
208911d2e63aSGabor Marton RetType{IntTy}),
209011d2e63aSGabor Marton Summary(NoEvalCall)
2091957014daSBalázs Kéri .Case(ReturnsZero, ErrnoMustNotBeChecked)
2092957014daSBalázs Kéri .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2093db4d5f70SGabor Marton .ArgConstraint(NotNull(ArgNo(0)))
2094db4d5f70SGabor Marton .ArgConstraint(NotNull(ArgNo(1))));
2095db4d5f70SGabor Marton
2096db4d5f70SGabor Marton // int lstat(const char *restrict path, struct stat *restrict buf);
209711d2e63aSGabor Marton addToFunctionSummaryMap(
209811d2e63aSGabor Marton "lstat",
209911d2e63aSGabor Marton Signature(ArgTypes{ConstCharPtrRestrictTy, StructStatPtrRestrictTy},
210011d2e63aSGabor Marton RetType{IntTy}),
210111d2e63aSGabor Marton Summary(NoEvalCall)
2102957014daSBalázs Kéri .Case(ReturnsZero, ErrnoMustNotBeChecked)
2103957014daSBalázs Kéri .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2104db4d5f70SGabor Marton .ArgConstraint(NotNull(ArgNo(0)))
2105db4d5f70SGabor Marton .ArgConstraint(NotNull(ArgNo(1))));
2106db4d5f70SGabor Marton
2107db4d5f70SGabor Marton // int fstatat(int fd, const char *restrict path,
2108db4d5f70SGabor Marton // struct stat *restrict buf, int flag);
2109db4d5f70SGabor Marton addToFunctionSummaryMap(
2110a787a4edSGabor Marton "fstatat",
211111d2e63aSGabor Marton Signature(ArgTypes{IntTy, ConstCharPtrRestrictTy,
211211d2e63aSGabor Marton StructStatPtrRestrictTy, IntTy},
211311d2e63aSGabor Marton RetType{IntTy}),
211411d2e63aSGabor Marton Summary(NoEvalCall)
2115957014daSBalázs Kéri .Case(ReturnsZero, ErrnoMustNotBeChecked)
2116957014daSBalázs Kéri .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2117a787a4edSGabor Marton .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
2118db4d5f70SGabor Marton .ArgConstraint(NotNull(ArgNo(1)))
2119db4d5f70SGabor Marton .ArgConstraint(NotNull(ArgNo(2))));
2120db4d5f70SGabor Marton
2121db4d5f70SGabor Marton // DIR *opendir(const char *name);
2122957014daSBalázs Kéri // FIXME: Improve for errno modeling.
212311d2e63aSGabor Marton addToFunctionSummaryMap(
212411d2e63aSGabor Marton "opendir", Signature(ArgTypes{ConstCharPtrTy}, RetType{DirPtrTy}),
212511d2e63aSGabor Marton Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2126db4d5f70SGabor Marton
2127db4d5f70SGabor Marton // DIR *fdopendir(int fd);
2128957014daSBalázs Kéri // FIXME: Improve for errno modeling.
212911d2e63aSGabor Marton addToFunctionSummaryMap("fdopendir",
213011d2e63aSGabor Marton Signature(ArgTypes{IntTy}, RetType{DirPtrTy}),
213111d2e63aSGabor Marton Summary(NoEvalCall)
213211d2e63aSGabor Marton .ArgConstraint(ArgumentCondition(
213311d2e63aSGabor Marton 0, WithinRange, Range(0, IntMax))));
2134db4d5f70SGabor Marton
2135db4d5f70SGabor Marton // int isatty(int fildes);
2136febe7503SGabor Marton addToFunctionSummaryMap(
2137febe7503SGabor Marton "isatty", Signature(ArgTypes{IntTy}, RetType{IntTy}),
213811d2e63aSGabor Marton Summary(NoEvalCall)
2139957014daSBalázs Kéri .Case({ReturnValueCondition(WithinRange, Range(0, 1))},
2140957014daSBalázs Kéri ErrnoIrrelevant)
2141febe7503SGabor Marton .ArgConstraint(
2142febe7503SGabor Marton ArgumentCondition(0, WithinRange, Range(0, IntMax))));
2143db4d5f70SGabor Marton
2144db4d5f70SGabor Marton // FILE *popen(const char *command, const char *type);
2145957014daSBalázs Kéri // FIXME: Improve for errno modeling.
214611d2e63aSGabor Marton addToFunctionSummaryMap(
214711d2e63aSGabor Marton "popen",
214811d2e63aSGabor Marton Signature(ArgTypes{ConstCharPtrTy, ConstCharPtrTy}, RetType{FilePtrTy}),
214911d2e63aSGabor Marton Summary(NoEvalCall)
2150db4d5f70SGabor Marton .ArgConstraint(NotNull(ArgNo(0)))
2151db4d5f70SGabor Marton .ArgConstraint(NotNull(ArgNo(1))));
2152db4d5f70SGabor Marton
2153db4d5f70SGabor Marton // int pclose(FILE *stream);
2154957014daSBalázs Kéri // FIXME: Improve for errno modeling.
2155db4d5f70SGabor Marton addToFunctionSummaryMap(
215611d2e63aSGabor Marton "pclose", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
215711d2e63aSGabor Marton Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2158db4d5f70SGabor Marton
2159db4d5f70SGabor Marton // int close(int fildes);
216011d2e63aSGabor Marton addToFunctionSummaryMap("close", Signature(ArgTypes{IntTy}, RetType{IntTy}),
216111d2e63aSGabor Marton Summary(NoEvalCall)
2162957014daSBalázs Kéri .Case(ReturnsZero, ErrnoMustNotBeChecked)
2163957014daSBalázs Kéri .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
216411d2e63aSGabor Marton .ArgConstraint(ArgumentCondition(
2165d14c6316SGabor Marton 0, WithinRange, Range(-1, IntMax))));
2166db4d5f70SGabor Marton
2167db4d5f70SGabor Marton // long fpathconf(int fildes, int name);
216811d2e63aSGabor Marton addToFunctionSummaryMap("fpathconf",
216911d2e63aSGabor Marton Signature(ArgTypes{IntTy, IntTy}, RetType{LongTy}),
217011d2e63aSGabor Marton Summary(NoEvalCall)
217111d2e63aSGabor Marton .ArgConstraint(ArgumentCondition(
217211d2e63aSGabor Marton 0, WithinRange, Range(0, IntMax))));
2173db4d5f70SGabor Marton
2174db4d5f70SGabor Marton // long pathconf(const char *path, int name);
217511d2e63aSGabor Marton addToFunctionSummaryMap(
217611d2e63aSGabor Marton "pathconf", Signature(ArgTypes{ConstCharPtrTy, IntTy}, RetType{LongTy}),
217711d2e63aSGabor Marton Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2178db4d5f70SGabor Marton
2179db4d5f70SGabor Marton // FILE *fdopen(int fd, const char *mode);
2180957014daSBalázs Kéri // FIXME: Improve for errno modeling.
2181db4d5f70SGabor Marton addToFunctionSummaryMap(
2182a787a4edSGabor Marton "fdopen",
218311d2e63aSGabor Marton Signature(ArgTypes{IntTy, ConstCharPtrTy}, RetType{FilePtrTy}),
218411d2e63aSGabor Marton Summary(NoEvalCall)
2185a787a4edSGabor Marton .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
2186db4d5f70SGabor Marton .ArgConstraint(NotNull(ArgNo(1))));
2187db4d5f70SGabor Marton
2188db4d5f70SGabor Marton // void rewinddir(DIR *dir);
2189db4d5f70SGabor Marton addToFunctionSummaryMap(
219011d2e63aSGabor Marton "rewinddir", Signature(ArgTypes{DirPtrTy}, RetType{VoidTy}),
219111d2e63aSGabor Marton Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2192db4d5f70SGabor Marton
2193db4d5f70SGabor Marton // void seekdir(DIR *dirp, long loc);
219411d2e63aSGabor Marton addToFunctionSummaryMap(
219511d2e63aSGabor Marton "seekdir", Signature(ArgTypes{DirPtrTy, LongTy}, RetType{VoidTy}),
219611d2e63aSGabor Marton Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2197db4d5f70SGabor Marton
2198db4d5f70SGabor Marton // int rand_r(unsigned int *seedp);
219911d2e63aSGabor Marton addToFunctionSummaryMap(
220011d2e63aSGabor Marton "rand_r", Signature(ArgTypes{UnsignedIntPtrTy}, RetType{IntTy}),
220111d2e63aSGabor Marton Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2202db4d5f70SGabor Marton
2203db4d5f70SGabor Marton // int fileno(FILE *stream);
2204957014daSBalázs Kéri addToFunctionSummaryMap(
2205957014daSBalázs Kéri "fileno", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
2206febe7503SGabor Marton Summary(NoEvalCall)
2207957014daSBalázs Kéri .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked)
2208957014daSBalázs Kéri .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2209febe7503SGabor Marton .ArgConstraint(NotNull(ArgNo(0))));
2210db4d5f70SGabor Marton
2211db4d5f70SGabor Marton // int fseeko(FILE *stream, off_t offset, int whence);
2212a787a4edSGabor Marton addToFunctionSummaryMap(
2213a787a4edSGabor Marton "fseeko",
221411d2e63aSGabor Marton Signature(ArgTypes{FilePtrTy, Off_tTy, IntTy}, RetType{IntTy}),
2215febe7503SGabor Marton Summary(NoEvalCall)
2216957014daSBalázs Kéri .Case(ReturnsZeroOrMinusOne, ErrnoIrrelevant)
2217febe7503SGabor Marton .ArgConstraint(NotNull(ArgNo(0))));
2218db4d5f70SGabor Marton
2219db4d5f70SGabor Marton // off_t ftello(FILE *stream);
2220db4d5f70SGabor Marton addToFunctionSummaryMap(
222111d2e63aSGabor Marton "ftello", Signature(ArgTypes{FilePtrTy}, RetType{Off_tTy}),
222211d2e63aSGabor Marton Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2223db4d5f70SGabor Marton
2224db4d5f70SGabor Marton // void *mmap(void *addr, size_t length, int prot, int flags, int fd,
2225db4d5f70SGabor Marton // off_t offset);
2226957014daSBalázs Kéri // FIXME: Improve for errno modeling.
2227db4d5f70SGabor Marton addToFunctionSummaryMap(
2228db4d5f70SGabor Marton "mmap",
222911d2e63aSGabor Marton Signature(ArgTypes{VoidPtrTy, SizeTy, IntTy, IntTy, IntTy, Off_tTy},
223011d2e63aSGabor Marton RetType{VoidPtrTy}),
223111d2e63aSGabor Marton Summary(NoEvalCall)
2232a787a4edSGabor Marton .ArgConstraint(ArgumentCondition(1, WithinRange, Range(1, SizeMax)))
2233db4d5f70SGabor Marton .ArgConstraint(
2234d14c6316SGabor Marton ArgumentCondition(4, WithinRange, Range(-1, IntMax))));
2235db4d5f70SGabor Marton
2236a787a4edSGabor Marton Optional<QualType> Off64_tTy = lookupTy("off64_t");
2237db4d5f70SGabor Marton // void *mmap64(void *addr, size_t length, int prot, int flags, int fd,
2238db4d5f70SGabor Marton // off64_t offset);
2239957014daSBalázs Kéri // FIXME: Improve for errno modeling.
2240db4d5f70SGabor Marton addToFunctionSummaryMap(
2241db4d5f70SGabor Marton "mmap64",
224211d2e63aSGabor Marton Signature(ArgTypes{VoidPtrTy, SizeTy, IntTy, IntTy, IntTy, Off64_tTy},
224311d2e63aSGabor Marton RetType{VoidPtrTy}),
224411d2e63aSGabor Marton Summary(NoEvalCall)
2245a787a4edSGabor Marton .ArgConstraint(ArgumentCondition(1, WithinRange, Range(1, SizeMax)))
2246db4d5f70SGabor Marton .ArgConstraint(
2247d14c6316SGabor Marton ArgumentCondition(4, WithinRange, Range(-1, IntMax))));
2248db4d5f70SGabor Marton
2249db4d5f70SGabor Marton // int pipe(int fildes[2]);
2250febe7503SGabor Marton addToFunctionSummaryMap("pipe",
2251febe7503SGabor Marton Signature(ArgTypes{IntPtrTy}, RetType{IntTy}),
2252febe7503SGabor Marton Summary(NoEvalCall)
2253957014daSBalázs Kéri .Case(ReturnsZero, ErrnoMustNotBeChecked)
2254957014daSBalázs Kéri .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2255febe7503SGabor Marton .ArgConstraint(NotNull(ArgNo(0))));
2256db4d5f70SGabor Marton
2257db4d5f70SGabor Marton // off_t lseek(int fildes, off_t offset, int whence);
2258957014daSBalázs Kéri // In the first case we can not tell for sure if it failed or not.
2259957014daSBalázs Kéri // A return value different from of the expected offset (that is unknown
2260957014daSBalázs Kéri // here) may indicate failure. For this reason we do not enforce the errno
2261957014daSBalázs Kéri // check (can cause false positive).
2262db4d5f70SGabor Marton addToFunctionSummaryMap(
226311d2e63aSGabor Marton "lseek", Signature(ArgTypes{IntTy, Off_tTy, IntTy}, RetType{Off_tTy}),
226411d2e63aSGabor Marton Summary(NoEvalCall)
2265957014daSBalázs Kéri .Case(ReturnsNonnegative, ErrnoIrrelevant)
2266957014daSBalázs Kéri .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2267a787a4edSGabor Marton .ArgConstraint(
2268a787a4edSGabor Marton ArgumentCondition(0, WithinRange, Range(0, IntMax))));
2269db4d5f70SGabor Marton
2270db4d5f70SGabor Marton // ssize_t readlink(const char *restrict path, char *restrict buf,
2271db4d5f70SGabor Marton // size_t bufsize);
2272db4d5f70SGabor Marton addToFunctionSummaryMap(
2273db4d5f70SGabor Marton "readlink",
227411d2e63aSGabor Marton Signature(ArgTypes{ConstCharPtrRestrictTy, CharPtrRestrictTy, SizeTy},
227511d2e63aSGabor Marton RetType{Ssize_tTy}),
227611d2e63aSGabor Marton Summary(NoEvalCall)
2277b40b3196SGabor Marton .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)),
2278957014daSBalázs Kéri ReturnValueCondition(WithinRange, Range(0, Ssize_tMax))},
2279957014daSBalázs Kéri ErrnoMustNotBeChecked)
2280957014daSBalázs Kéri .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2281db4d5f70SGabor Marton .ArgConstraint(NotNull(ArgNo(0)))
2282db4d5f70SGabor Marton .ArgConstraint(NotNull(ArgNo(1)))
2283db4d5f70SGabor Marton .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
2284db4d5f70SGabor Marton /*BufSize=*/ArgNo(2)))
2285db4d5f70SGabor Marton .ArgConstraint(
2286db4d5f70SGabor Marton ArgumentCondition(2, WithinRange, Range(0, SizeMax))));
2287db4d5f70SGabor Marton
2288db4d5f70SGabor Marton // ssize_t readlinkat(int fd, const char *restrict path,
2289db4d5f70SGabor Marton // char *restrict buf, size_t bufsize);
2290db4d5f70SGabor Marton addToFunctionSummaryMap(
2291a787a4edSGabor Marton "readlinkat",
229211d2e63aSGabor Marton Signature(
2293a787a4edSGabor Marton ArgTypes{IntTy, ConstCharPtrRestrictTy, CharPtrRestrictTy, SizeTy},
229411d2e63aSGabor Marton RetType{Ssize_tTy}),
229511d2e63aSGabor Marton Summary(NoEvalCall)
2296b40b3196SGabor Marton .Case({ReturnValueCondition(LessThanOrEq, ArgNo(3)),
2297957014daSBalázs Kéri ReturnValueCondition(WithinRange, Range(0, Ssize_tMax))},
2298957014daSBalázs Kéri ErrnoMustNotBeChecked)
2299957014daSBalázs Kéri .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2300a787a4edSGabor Marton .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
2301db4d5f70SGabor Marton .ArgConstraint(NotNull(ArgNo(1)))
2302db4d5f70SGabor Marton .ArgConstraint(NotNull(ArgNo(2)))
2303db4d5f70SGabor Marton .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(2),
2304db4d5f70SGabor Marton /*BufSize=*/ArgNo(3)))
2305a787a4edSGabor Marton .ArgConstraint(
2306a787a4edSGabor Marton ArgumentCondition(3, WithinRange, Range(0, SizeMax))));
2307db4d5f70SGabor Marton
2308db4d5f70SGabor Marton // int renameat(int olddirfd, const char *oldpath, int newdirfd, const char
2309db4d5f70SGabor Marton // *newpath);
231011d2e63aSGabor Marton addToFunctionSummaryMap(
231111d2e63aSGabor Marton "renameat",
231211d2e63aSGabor Marton Signature(ArgTypes{IntTy, ConstCharPtrTy, IntTy, ConstCharPtrTy},
231311d2e63aSGabor Marton RetType{IntTy}),
231411d2e63aSGabor Marton Summary(NoEvalCall)
2315957014daSBalázs Kéri .Case(ReturnsZero, ErrnoMustNotBeChecked)
2316957014daSBalázs Kéri .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2317db4d5f70SGabor Marton .ArgConstraint(NotNull(ArgNo(1)))
2318db4d5f70SGabor Marton .ArgConstraint(NotNull(ArgNo(3))));
2319db4d5f70SGabor Marton
2320db4d5f70SGabor Marton // char *realpath(const char *restrict file_name,
2321db4d5f70SGabor Marton // char *restrict resolved_name);
2322957014daSBalázs Kéri // FIXME: Improve for errno modeling.
2323db4d5f70SGabor Marton addToFunctionSummaryMap(
232411d2e63aSGabor Marton "realpath",
232511d2e63aSGabor Marton Signature(ArgTypes{ConstCharPtrRestrictTy, CharPtrRestrictTy},
232611d2e63aSGabor Marton RetType{CharPtrTy}),
232711d2e63aSGabor Marton Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2328db4d5f70SGabor Marton
2329a787a4edSGabor Marton QualType CharPtrConstPtr = getPointerTy(getConstTy(CharPtrTy));
2330db4d5f70SGabor Marton
2331db4d5f70SGabor Marton // int execv(const char *path, char *const argv[]);
233211d2e63aSGabor Marton addToFunctionSummaryMap(
233311d2e63aSGabor Marton "execv",
233411d2e63aSGabor Marton Signature(ArgTypes{ConstCharPtrTy, CharPtrConstPtr}, RetType{IntTy}),
2335febe7503SGabor Marton Summary(NoEvalCall)
2336957014daSBalázs Kéri .Case({ReturnValueCondition(WithinRange, SingleValue(-1))},
2337957014daSBalázs Kéri ErrnoIrrelevant)
2338febe7503SGabor Marton .ArgConstraint(NotNull(ArgNo(0))));
2339db4d5f70SGabor Marton
2340db4d5f70SGabor Marton // int execvp(const char *file, char *const argv[]);
234111d2e63aSGabor Marton addToFunctionSummaryMap(
234211d2e63aSGabor Marton "execvp",
234311d2e63aSGabor Marton Signature(ArgTypes{ConstCharPtrTy, CharPtrConstPtr}, RetType{IntTy}),
2344febe7503SGabor Marton Summary(NoEvalCall)
2345957014daSBalázs Kéri .Case({ReturnValueCondition(WithinRange, SingleValue(-1))},
2346957014daSBalázs Kéri ErrnoIrrelevant)
2347febe7503SGabor Marton .ArgConstraint(NotNull(ArgNo(0))));
2348db4d5f70SGabor Marton
2349db4d5f70SGabor Marton // int getopt(int argc, char * const argv[], const char *optstring);
2350db4d5f70SGabor Marton addToFunctionSummaryMap(
2351db4d5f70SGabor Marton "getopt",
235211d2e63aSGabor Marton Signature(ArgTypes{IntTy, CharPtrConstPtr, ConstCharPtrTy},
235311d2e63aSGabor Marton RetType{IntTy}),
235411d2e63aSGabor Marton Summary(NoEvalCall)
2355957014daSBalázs Kéri .Case({ReturnValueCondition(WithinRange, Range(-1, UCharRangeMax))},
2356957014daSBalázs Kéri ErrnoIrrelevant)
2357db4d5f70SGabor Marton .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
2358db4d5f70SGabor Marton .ArgConstraint(NotNull(ArgNo(1)))
2359db4d5f70SGabor Marton .ArgConstraint(NotNull(ArgNo(2))));
23603ff220deSGabor Marton
2361a787a4edSGabor Marton Optional<QualType> StructSockaddrTy = lookupTy("sockaddr");
2362a787a4edSGabor Marton Optional<QualType> StructSockaddrPtrTy = getPointerTy(StructSockaddrTy);
2363a787a4edSGabor Marton Optional<QualType> ConstStructSockaddrPtrTy =
2364a787a4edSGabor Marton getPointerTy(getConstTy(StructSockaddrTy));
2365a787a4edSGabor Marton Optional<QualType> StructSockaddrPtrRestrictTy =
2366a787a4edSGabor Marton getRestrictTy(StructSockaddrPtrTy);
2367a787a4edSGabor Marton Optional<QualType> ConstStructSockaddrPtrRestrictTy =
2368a787a4edSGabor Marton getRestrictTy(ConstStructSockaddrPtrTy);
2369a787a4edSGabor Marton Optional<QualType> Socklen_tTy = lookupTy("socklen_t");
2370a787a4edSGabor Marton Optional<QualType> Socklen_tPtrTy = getPointerTy(Socklen_tTy);
2371a787a4edSGabor Marton Optional<QualType> Socklen_tPtrRestrictTy = getRestrictTy(Socklen_tPtrTy);
2372a787a4edSGabor Marton Optional<RangeInt> Socklen_tMax = getMaxValue(Socklen_tTy);
23733ff220deSGabor Marton
23743ff220deSGabor Marton // In 'socket.h' of some libc implementations with C99, sockaddr parameter
23753ff220deSGabor Marton // is a transparent union of the underlying sockaddr_ family of pointers
23763ff220deSGabor Marton // instead of being a pointer to struct sockaddr. In these cases, the
23773ff220deSGabor Marton // standardized signature will not match, thus we try to match with another
23783ff220deSGabor Marton // signature that has the joker Irrelevant type. We also remove those
23793ff220deSGabor Marton // constraints which require pointer types for the sockaddr param.
2380a787a4edSGabor Marton auto Accept =
2381a787a4edSGabor Marton Summary(NoEvalCall)
2382957014daSBalázs Kéri .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked)
2383957014daSBalázs Kéri .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2384a787a4edSGabor Marton .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)));
23853ff220deSGabor Marton if (!addToFunctionSummaryMap(
23863ff220deSGabor Marton "accept",
23873ff220deSGabor Marton // int accept(int socket, struct sockaddr *restrict address,
23883ff220deSGabor Marton // socklen_t *restrict address_len);
2389a787a4edSGabor Marton Signature(ArgTypes{IntTy, StructSockaddrPtrRestrictTy,
2390a787a4edSGabor Marton Socklen_tPtrRestrictTy},
23913ff220deSGabor Marton RetType{IntTy}),
23923ff220deSGabor Marton Accept))
23933ff220deSGabor Marton addToFunctionSummaryMap(
23943ff220deSGabor Marton "accept",
2395a787a4edSGabor Marton Signature(ArgTypes{IntTy, Irrelevant, Socklen_tPtrRestrictTy},
23963ff220deSGabor Marton RetType{IntTy}),
23973ff220deSGabor Marton Accept);
23983ff220deSGabor Marton
23993ff220deSGabor Marton // int bind(int socket, const struct sockaddr *address, socklen_t
24003ff220deSGabor Marton // address_len);
24013ff220deSGabor Marton if (!addToFunctionSummaryMap(
24023ff220deSGabor Marton "bind",
240311d2e63aSGabor Marton Signature(ArgTypes{IntTy, ConstStructSockaddrPtrTy, Socklen_tTy},
240411d2e63aSGabor Marton RetType{IntTy}),
240511d2e63aSGabor Marton Summary(NoEvalCall)
2406957014daSBalázs Kéri .Case(ReturnsZero, ErrnoMustNotBeChecked)
2407957014daSBalázs Kéri .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
24083ff220deSGabor Marton .ArgConstraint(
24093ff220deSGabor Marton ArgumentCondition(0, WithinRange, Range(0, IntMax)))
24103ff220deSGabor Marton .ArgConstraint(NotNull(ArgNo(1)))
24113ff220deSGabor Marton .ArgConstraint(
24123ff220deSGabor Marton BufferSize(/*Buffer=*/ArgNo(1), /*BufSize=*/ArgNo(2)))
2413a787a4edSGabor Marton .ArgConstraint(
2414a787a4edSGabor Marton ArgumentCondition(2, WithinRange, Range(0, Socklen_tMax)))))
24153ff220deSGabor Marton // Do not add constraints on sockaddr.
24163ff220deSGabor Marton addToFunctionSummaryMap(
241711d2e63aSGabor Marton "bind",
241811d2e63aSGabor Marton Signature(ArgTypes{IntTy, Irrelevant, Socklen_tTy}, RetType{IntTy}),
241911d2e63aSGabor Marton Summary(NoEvalCall)
2420957014daSBalázs Kéri .Case(ReturnsZero, ErrnoMustNotBeChecked)
2421957014daSBalázs Kéri .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
24223ff220deSGabor Marton .ArgConstraint(
24233ff220deSGabor Marton ArgumentCondition(0, WithinRange, Range(0, IntMax)))
242411d2e63aSGabor Marton .ArgConstraint(
242511d2e63aSGabor Marton ArgumentCondition(2, WithinRange, Range(0, Socklen_tMax))));
24263ff220deSGabor Marton
24273ff220deSGabor Marton // int getpeername(int socket, struct sockaddr *restrict address,
24283ff220deSGabor Marton // socklen_t *restrict address_len);
24293ff220deSGabor Marton if (!addToFunctionSummaryMap(
243011d2e63aSGabor Marton "getpeername",
243111d2e63aSGabor Marton Signature(ArgTypes{IntTy, StructSockaddrPtrRestrictTy,
2432a787a4edSGabor Marton Socklen_tPtrRestrictTy},
243311d2e63aSGabor Marton RetType{IntTy}),
243411d2e63aSGabor Marton Summary(NoEvalCall)
2435957014daSBalázs Kéri .Case(ReturnsZero, ErrnoMustNotBeChecked)
2436957014daSBalázs Kéri .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
243711d2e63aSGabor Marton .ArgConstraint(
243811d2e63aSGabor Marton ArgumentCondition(0, WithinRange, Range(0, IntMax)))
24393ff220deSGabor Marton .ArgConstraint(NotNull(ArgNo(1)))
24403ff220deSGabor Marton .ArgConstraint(NotNull(ArgNo(2)))))
24413ff220deSGabor Marton addToFunctionSummaryMap(
24423ff220deSGabor Marton "getpeername",
244311d2e63aSGabor Marton Signature(ArgTypes{IntTy, Irrelevant, Socklen_tPtrRestrictTy},
244411d2e63aSGabor Marton RetType{IntTy}),
244511d2e63aSGabor Marton Summary(NoEvalCall)
2446957014daSBalázs Kéri .Case(ReturnsZero, ErrnoMustNotBeChecked)
2447957014daSBalázs Kéri .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
24483ff220deSGabor Marton .ArgConstraint(
24493ff220deSGabor Marton ArgumentCondition(0, WithinRange, Range(0, IntMax))));
24503ff220deSGabor Marton
24513ff220deSGabor Marton // int getsockname(int socket, struct sockaddr *restrict address,
24523ff220deSGabor Marton // socklen_t *restrict address_len);
24533ff220deSGabor Marton if (!addToFunctionSummaryMap(
245411d2e63aSGabor Marton "getsockname",
245511d2e63aSGabor Marton Signature(ArgTypes{IntTy, StructSockaddrPtrRestrictTy,
2456a787a4edSGabor Marton Socklen_tPtrRestrictTy},
245711d2e63aSGabor Marton RetType{IntTy}),
245811d2e63aSGabor Marton Summary(NoEvalCall)
2459957014daSBalázs Kéri .Case(ReturnsZero, ErrnoMustNotBeChecked)
2460957014daSBalázs Kéri .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
246111d2e63aSGabor Marton .ArgConstraint(
246211d2e63aSGabor Marton ArgumentCondition(0, WithinRange, Range(0, IntMax)))
24633ff220deSGabor Marton .ArgConstraint(NotNull(ArgNo(1)))
24643ff220deSGabor Marton .ArgConstraint(NotNull(ArgNo(2)))))
24653ff220deSGabor Marton addToFunctionSummaryMap(
24663ff220deSGabor Marton "getsockname",
246711d2e63aSGabor Marton Signature(ArgTypes{IntTy, Irrelevant, Socklen_tPtrRestrictTy},
246811d2e63aSGabor Marton RetType{IntTy}),
246911d2e63aSGabor Marton Summary(NoEvalCall)
2470957014daSBalázs Kéri .Case(ReturnsZero, ErrnoMustNotBeChecked)
2471957014daSBalázs Kéri .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
24723ff220deSGabor Marton .ArgConstraint(
24733ff220deSGabor Marton ArgumentCondition(0, WithinRange, Range(0, IntMax))));
24743ff220deSGabor Marton
24753ff220deSGabor Marton // int connect(int socket, const struct sockaddr *address, socklen_t
24763ff220deSGabor Marton // address_len);
24773ff220deSGabor Marton if (!addToFunctionSummaryMap(
24783ff220deSGabor Marton "connect",
247911d2e63aSGabor Marton Signature(ArgTypes{IntTy, ConstStructSockaddrPtrTy, Socklen_tTy},
248011d2e63aSGabor Marton RetType{IntTy}),
248111d2e63aSGabor Marton Summary(NoEvalCall)
2482957014daSBalázs Kéri .Case(ReturnsZero, ErrnoMustNotBeChecked)
2483957014daSBalázs Kéri .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
24843ff220deSGabor Marton .ArgConstraint(
24853ff220deSGabor Marton ArgumentCondition(0, WithinRange, Range(0, IntMax)))
24863ff220deSGabor Marton .ArgConstraint(NotNull(ArgNo(1)))))
24873ff220deSGabor Marton addToFunctionSummaryMap(
248811d2e63aSGabor Marton "connect",
248911d2e63aSGabor Marton Signature(ArgTypes{IntTy, Irrelevant, Socklen_tTy}, RetType{IntTy}),
249011d2e63aSGabor Marton Summary(NoEvalCall)
2491957014daSBalázs Kéri .Case(ReturnsZero, ErrnoMustNotBeChecked)
2492957014daSBalázs Kéri .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
249311d2e63aSGabor Marton .ArgConstraint(
249411d2e63aSGabor Marton ArgumentCondition(0, WithinRange, Range(0, IntMax))));
24953ff220deSGabor Marton
2496a787a4edSGabor Marton auto Recvfrom =
2497a787a4edSGabor Marton Summary(NoEvalCall)
2498b40b3196SGabor Marton .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)),
2499957014daSBalázs Kéri ReturnValueCondition(WithinRange, Range(0, Ssize_tMax))},
2500957014daSBalázs Kéri ErrnoMustNotBeChecked)
2501957014daSBalázs Kéri .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2502a787a4edSGabor Marton .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
25033ff220deSGabor Marton .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
25043ff220deSGabor Marton /*BufSize=*/ArgNo(2)));
2505a787a4edSGabor Marton if (!addToFunctionSummaryMap(
25063ff220deSGabor Marton "recvfrom",
25073ff220deSGabor Marton // ssize_t recvfrom(int socket, void *restrict buffer,
25083ff220deSGabor Marton // size_t length,
25093ff220deSGabor Marton // int flags, struct sockaddr *restrict address,
25103ff220deSGabor Marton // socklen_t *restrict address_len);
25113ff220deSGabor Marton Signature(ArgTypes{IntTy, VoidPtrRestrictTy, SizeTy, IntTy,
2512a787a4edSGabor Marton StructSockaddrPtrRestrictTy,
2513a787a4edSGabor Marton Socklen_tPtrRestrictTy},
2514a787a4edSGabor Marton RetType{Ssize_tTy}),
25153ff220deSGabor Marton Recvfrom))
25163ff220deSGabor Marton addToFunctionSummaryMap(
25173ff220deSGabor Marton "recvfrom",
25183ff220deSGabor Marton Signature(ArgTypes{IntTy, VoidPtrRestrictTy, SizeTy, IntTy,
2519a787a4edSGabor Marton Irrelevant, Socklen_tPtrRestrictTy},
2520a787a4edSGabor Marton RetType{Ssize_tTy}),
25213ff220deSGabor Marton Recvfrom);
25223ff220deSGabor Marton
2523a787a4edSGabor Marton auto Sendto =
2524a787a4edSGabor Marton Summary(NoEvalCall)
2525b40b3196SGabor Marton .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)),
2526957014daSBalázs Kéri ReturnValueCondition(WithinRange, Range(0, Ssize_tMax))},
2527957014daSBalázs Kéri ErrnoMustNotBeChecked)
2528957014daSBalázs Kéri .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2529a787a4edSGabor Marton .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
25303ff220deSGabor Marton .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
25313ff220deSGabor Marton /*BufSize=*/ArgNo(2)));
2532a787a4edSGabor Marton if (!addToFunctionSummaryMap(
25333ff220deSGabor Marton "sendto",
25343ff220deSGabor Marton // ssize_t sendto(int socket, const void *message, size_t length,
25353ff220deSGabor Marton // int flags, const struct sockaddr *dest_addr,
25363ff220deSGabor Marton // socklen_t dest_len);
25373ff220deSGabor Marton Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTy, IntTy,
2538a787a4edSGabor Marton ConstStructSockaddrPtrTy, Socklen_tTy},
2539a787a4edSGabor Marton RetType{Ssize_tTy}),
25403ff220deSGabor Marton Sendto))
25413ff220deSGabor Marton addToFunctionSummaryMap(
25423ff220deSGabor Marton "sendto",
25433ff220deSGabor Marton Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTy, IntTy, Irrelevant,
2544a787a4edSGabor Marton Socklen_tTy},
2545a787a4edSGabor Marton RetType{Ssize_tTy}),
25463ff220deSGabor Marton Sendto);
25473ff220deSGabor Marton
25483ff220deSGabor Marton // int listen(int sockfd, int backlog);
254911d2e63aSGabor Marton addToFunctionSummaryMap("listen",
255011d2e63aSGabor Marton Signature(ArgTypes{IntTy, IntTy}, RetType{IntTy}),
255111d2e63aSGabor Marton Summary(NoEvalCall)
2552957014daSBalázs Kéri .Case(ReturnsZero, ErrnoMustNotBeChecked)
2553957014daSBalázs Kéri .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
255411d2e63aSGabor Marton .ArgConstraint(ArgumentCondition(
255511d2e63aSGabor Marton 0, WithinRange, Range(0, IntMax))));
25563ff220deSGabor Marton
25573ff220deSGabor Marton // ssize_t recv(int sockfd, void *buf, size_t len, int flags);
25583ff220deSGabor Marton addToFunctionSummaryMap(
2559a787a4edSGabor Marton "recv",
256011d2e63aSGabor Marton Signature(ArgTypes{IntTy, VoidPtrTy, SizeTy, IntTy},
256111d2e63aSGabor Marton RetType{Ssize_tTy}),
256211d2e63aSGabor Marton Summary(NoEvalCall)
2563b40b3196SGabor Marton .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)),
2564957014daSBalázs Kéri ReturnValueCondition(WithinRange, Range(0, Ssize_tMax))},
2565957014daSBalázs Kéri ErrnoMustNotBeChecked)
2566957014daSBalázs Kéri .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2567a787a4edSGabor Marton .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
25683ff220deSGabor Marton .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
25693ff220deSGabor Marton /*BufSize=*/ArgNo(2))));
25703ff220deSGabor Marton
2571a787a4edSGabor Marton Optional<QualType> StructMsghdrTy = lookupTy("msghdr");
2572a787a4edSGabor Marton Optional<QualType> StructMsghdrPtrTy = getPointerTy(StructMsghdrTy);
2573a787a4edSGabor Marton Optional<QualType> ConstStructMsghdrPtrTy =
2574a787a4edSGabor Marton getPointerTy(getConstTy(StructMsghdrTy));
25753ff220deSGabor Marton
25763ff220deSGabor Marton // ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);
2577b40b3196SGabor Marton addToFunctionSummaryMap(
2578b40b3196SGabor Marton "recvmsg",
257911d2e63aSGabor Marton Signature(ArgTypes{IntTy, StructMsghdrPtrTy, IntTy},
258011d2e63aSGabor Marton RetType{Ssize_tTy}),
258111d2e63aSGabor Marton Summary(NoEvalCall)
2582957014daSBalázs Kéri .Case({ReturnValueCondition(WithinRange, Range(0, Ssize_tMax))},
2583957014daSBalázs Kéri ErrnoMustNotBeChecked)
2584957014daSBalázs Kéri .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2585b40b3196SGabor Marton .ArgConstraint(
2586b40b3196SGabor Marton ArgumentCondition(0, WithinRange, Range(0, IntMax))));
25873ff220deSGabor Marton
25883ff220deSGabor Marton // ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
25893ff220deSGabor Marton addToFunctionSummaryMap(
259011d2e63aSGabor Marton "sendmsg",
259111d2e63aSGabor Marton Signature(ArgTypes{IntTy, ConstStructMsghdrPtrTy, IntTy},
259211d2e63aSGabor Marton RetType{Ssize_tTy}),
259311d2e63aSGabor Marton Summary(NoEvalCall)
2594957014daSBalázs Kéri .Case({ReturnValueCondition(WithinRange, Range(0, Ssize_tMax))},
2595957014daSBalázs Kéri ErrnoMustNotBeChecked)
2596957014daSBalázs Kéri .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
259711d2e63aSGabor Marton .ArgConstraint(
259811d2e63aSGabor Marton ArgumentCondition(0, WithinRange, Range(0, IntMax))));
25993ff220deSGabor Marton
26003ff220deSGabor Marton // int setsockopt(int socket, int level, int option_name,
26013ff220deSGabor Marton // const void *option_value, socklen_t option_len);
26023ff220deSGabor Marton addToFunctionSummaryMap(
26033ff220deSGabor Marton "setsockopt",
260411d2e63aSGabor Marton Signature(ArgTypes{IntTy, IntTy, IntTy, ConstVoidPtrTy, Socklen_tTy},
260511d2e63aSGabor Marton RetType{IntTy}),
260611d2e63aSGabor Marton Summary(NoEvalCall)
2607957014daSBalázs Kéri .Case(ReturnsZero, ErrnoMustNotBeChecked)
2608957014daSBalázs Kéri .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
26093ff220deSGabor Marton .ArgConstraint(NotNull(ArgNo(3)))
26103ff220deSGabor Marton .ArgConstraint(
26113ff220deSGabor Marton BufferSize(/*Buffer=*/ArgNo(3), /*BufSize=*/ArgNo(4)))
26123ff220deSGabor Marton .ArgConstraint(
2613a787a4edSGabor Marton ArgumentCondition(4, WithinRange, Range(0, Socklen_tMax))));
26143ff220deSGabor Marton
26153ff220deSGabor Marton // int getsockopt(int socket, int level, int option_name,
26163ff220deSGabor Marton // void *restrict option_value,
26173ff220deSGabor Marton // socklen_t *restrict option_len);
26183ff220deSGabor Marton addToFunctionSummaryMap(
261911d2e63aSGabor Marton "getsockopt",
262011d2e63aSGabor Marton Signature(ArgTypes{IntTy, IntTy, IntTy, VoidPtrRestrictTy,
2621a787a4edSGabor Marton Socklen_tPtrRestrictTy},
262211d2e63aSGabor Marton RetType{IntTy}),
262311d2e63aSGabor Marton Summary(NoEvalCall)
2624957014daSBalázs Kéri .Case(ReturnsZero, ErrnoMustNotBeChecked)
2625957014daSBalázs Kéri .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
26263ff220deSGabor Marton .ArgConstraint(NotNull(ArgNo(3)))
26273ff220deSGabor Marton .ArgConstraint(NotNull(ArgNo(4))));
26283ff220deSGabor Marton
26293ff220deSGabor Marton // ssize_t send(int sockfd, const void *buf, size_t len, int flags);
26303ff220deSGabor Marton addToFunctionSummaryMap(
2631a787a4edSGabor Marton "send",
263211d2e63aSGabor Marton Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTy, IntTy},
263311d2e63aSGabor Marton RetType{Ssize_tTy}),
263411d2e63aSGabor Marton Summary(NoEvalCall)
2635b40b3196SGabor Marton .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)),
2636957014daSBalázs Kéri ReturnValueCondition(WithinRange, Range(0, Ssize_tMax))},
2637957014daSBalázs Kéri ErrnoMustNotBeChecked)
2638957014daSBalázs Kéri .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2639a787a4edSGabor Marton .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
26403ff220deSGabor Marton .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
26413ff220deSGabor Marton /*BufSize=*/ArgNo(2))));
26423ff220deSGabor Marton
26433ff220deSGabor Marton // int socketpair(int domain, int type, int protocol, int sv[2]);
264411d2e63aSGabor Marton addToFunctionSummaryMap(
264511d2e63aSGabor Marton "socketpair",
264611d2e63aSGabor Marton Signature(ArgTypes{IntTy, IntTy, IntTy, IntPtrTy}, RetType{IntTy}),
2647b40b3196SGabor Marton Summary(NoEvalCall)
2648957014daSBalázs Kéri .Case(ReturnsZero, ErrnoMustNotBeChecked)
2649957014daSBalázs Kéri .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2650b40b3196SGabor Marton .ArgConstraint(NotNull(ArgNo(3))));
26513ff220deSGabor Marton
26523ff220deSGabor Marton // int getnameinfo(const struct sockaddr *restrict sa, socklen_t salen,
26533ff220deSGabor Marton // char *restrict node, socklen_t nodelen,
26543ff220deSGabor Marton // char *restrict service,
26553ff220deSGabor Marton // socklen_t servicelen, int flags);
26563ff220deSGabor Marton //
26573ff220deSGabor Marton // This is defined in netdb.h. And contrary to 'socket.h', the sockaddr
26583ff220deSGabor Marton // parameter is never handled as a transparent union in netdb.h
26593ff220deSGabor Marton addToFunctionSummaryMap(
26603ff220deSGabor Marton "getnameinfo",
266111d2e63aSGabor Marton Signature(ArgTypes{ConstStructSockaddrPtrRestrictTy, Socklen_tTy,
2662a787a4edSGabor Marton CharPtrRestrictTy, Socklen_tTy, CharPtrRestrictTy,
2663a787a4edSGabor Marton Socklen_tTy, IntTy},
266411d2e63aSGabor Marton RetType{IntTy}),
266511d2e63aSGabor Marton Summary(NoEvalCall)
26663ff220deSGabor Marton .ArgConstraint(
26673ff220deSGabor Marton BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1)))
26683ff220deSGabor Marton .ArgConstraint(
2669a787a4edSGabor Marton ArgumentCondition(1, WithinRange, Range(0, Socklen_tMax)))
26703ff220deSGabor Marton .ArgConstraint(
26713ff220deSGabor Marton BufferSize(/*Buffer=*/ArgNo(2), /*BufSize=*/ArgNo(3)))
26723ff220deSGabor Marton .ArgConstraint(
2673a787a4edSGabor Marton ArgumentCondition(3, WithinRange, Range(0, Socklen_tMax)))
26743ff220deSGabor Marton .ArgConstraint(
26753ff220deSGabor Marton BufferSize(/*Buffer=*/ArgNo(4), /*BufSize=*/ArgNo(5)))
26763ff220deSGabor Marton .ArgConstraint(
2677a787a4edSGabor Marton ArgumentCondition(5, WithinRange, Range(0, Socklen_tMax))));
2678f0b9dbcfSGabor Marton
2679f0b9dbcfSGabor Marton Optional<QualType> StructUtimbufTy = lookupTy("utimbuf");
2680f0b9dbcfSGabor Marton Optional<QualType> StructUtimbufPtrTy = getPointerTy(StructUtimbufTy);
2681f0b9dbcfSGabor Marton
2682f0b9dbcfSGabor Marton // int utime(const char *filename, struct utimbuf *buf);
2683f0b9dbcfSGabor Marton addToFunctionSummaryMap(
268411d2e63aSGabor Marton "utime",
268511d2e63aSGabor Marton Signature(ArgTypes{ConstCharPtrTy, StructUtimbufPtrTy}, RetType{IntTy}),
2686febe7503SGabor Marton Summary(NoEvalCall)
2687957014daSBalázs Kéri .Case(ReturnsZero, ErrnoMustNotBeChecked)
2688957014daSBalázs Kéri .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2689febe7503SGabor Marton .ArgConstraint(NotNull(ArgNo(0))));
2690f0b9dbcfSGabor Marton
2691f0b9dbcfSGabor Marton Optional<QualType> StructTimespecTy = lookupTy("timespec");
2692f0b9dbcfSGabor Marton Optional<QualType> StructTimespecPtrTy = getPointerTy(StructTimespecTy);
2693f0b9dbcfSGabor Marton Optional<QualType> ConstStructTimespecPtrTy =
2694f0b9dbcfSGabor Marton getPointerTy(getConstTy(StructTimespecTy));
2695f0b9dbcfSGabor Marton
2696f0b9dbcfSGabor Marton // int futimens(int fd, const struct timespec times[2]);
2697f0b9dbcfSGabor Marton addToFunctionSummaryMap(
269811d2e63aSGabor Marton "futimens",
269911d2e63aSGabor Marton Signature(ArgTypes{IntTy, ConstStructTimespecPtrTy}, RetType{IntTy}),
270011d2e63aSGabor Marton Summary(NoEvalCall)
2701957014daSBalázs Kéri .Case(ReturnsZero, ErrnoMustNotBeChecked)
2702957014daSBalázs Kéri .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
270311d2e63aSGabor Marton .ArgConstraint(
270411d2e63aSGabor Marton ArgumentCondition(0, WithinRange, Range(0, IntMax))));
2705f0b9dbcfSGabor Marton
2706f0b9dbcfSGabor Marton // int utimensat(int dirfd, const char *pathname,
2707f0b9dbcfSGabor Marton // const struct timespec times[2], int flags);
2708febe7503SGabor Marton addToFunctionSummaryMap("utimensat",
2709febe7503SGabor Marton Signature(ArgTypes{IntTy, ConstCharPtrTy,
2710febe7503SGabor Marton ConstStructTimespecPtrTy, IntTy},
271111d2e63aSGabor Marton RetType{IntTy}),
2712febe7503SGabor Marton Summary(NoEvalCall)
2713957014daSBalázs Kéri .Case(ReturnsZero, ErrnoMustNotBeChecked)
2714957014daSBalázs Kéri .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2715febe7503SGabor Marton .ArgConstraint(NotNull(ArgNo(1))));
2716f0b9dbcfSGabor Marton
2717f0b9dbcfSGabor Marton Optional<QualType> StructTimevalTy = lookupTy("timeval");
2718f0b9dbcfSGabor Marton Optional<QualType> ConstStructTimevalPtrTy =
2719f0b9dbcfSGabor Marton getPointerTy(getConstTy(StructTimevalTy));
2720f0b9dbcfSGabor Marton
2721f0b9dbcfSGabor Marton // int utimes(const char *filename, const struct timeval times[2]);
2722f0b9dbcfSGabor Marton addToFunctionSummaryMap(
272311d2e63aSGabor Marton "utimes",
272411d2e63aSGabor Marton Signature(ArgTypes{ConstCharPtrTy, ConstStructTimevalPtrTy},
272511d2e63aSGabor Marton RetType{IntTy}),
2726febe7503SGabor Marton Summary(NoEvalCall)
2727957014daSBalázs Kéri .Case(ReturnsZero, ErrnoMustNotBeChecked)
2728957014daSBalázs Kéri .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2729febe7503SGabor Marton .ArgConstraint(NotNull(ArgNo(0))));
2730f0b9dbcfSGabor Marton
2731f0b9dbcfSGabor Marton // int nanosleep(const struct timespec *rqtp, struct timespec *rmtp);
2732f0b9dbcfSGabor Marton addToFunctionSummaryMap(
2733f0b9dbcfSGabor Marton "nanosleep",
273411d2e63aSGabor Marton Signature(ArgTypes{ConstStructTimespecPtrTy, StructTimespecPtrTy},
273511d2e63aSGabor Marton RetType{IntTy}),
2736febe7503SGabor Marton Summary(NoEvalCall)
2737957014daSBalázs Kéri .Case(ReturnsZero, ErrnoMustNotBeChecked)
2738957014daSBalázs Kéri .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2739febe7503SGabor Marton .ArgConstraint(NotNull(ArgNo(0))));
2740f0b9dbcfSGabor Marton
2741f0b9dbcfSGabor Marton Optional<QualType> Time_tTy = lookupTy("time_t");
2742f0b9dbcfSGabor Marton Optional<QualType> ConstTime_tPtrTy = getPointerTy(getConstTy(Time_tTy));
2743f0b9dbcfSGabor Marton Optional<QualType> ConstTime_tPtrRestrictTy =
2744f0b9dbcfSGabor Marton getRestrictTy(ConstTime_tPtrTy);
2745f0b9dbcfSGabor Marton
2746f0b9dbcfSGabor Marton Optional<QualType> StructTmTy = lookupTy("tm");
2747f0b9dbcfSGabor Marton Optional<QualType> StructTmPtrTy = getPointerTy(StructTmTy);
2748f0b9dbcfSGabor Marton Optional<QualType> StructTmPtrRestrictTy = getRestrictTy(StructTmPtrTy);
2749f0b9dbcfSGabor Marton Optional<QualType> ConstStructTmPtrTy =
2750f0b9dbcfSGabor Marton getPointerTy(getConstTy(StructTmTy));
2751f0b9dbcfSGabor Marton Optional<QualType> ConstStructTmPtrRestrictTy =
2752f0b9dbcfSGabor Marton getRestrictTy(ConstStructTmPtrTy);
2753f0b9dbcfSGabor Marton
2754f0b9dbcfSGabor Marton // struct tm * localtime(const time_t *tp);
2755f0b9dbcfSGabor Marton addToFunctionSummaryMap(
2756f0b9dbcfSGabor Marton "localtime",
275711d2e63aSGabor Marton Signature(ArgTypes{ConstTime_tPtrTy}, RetType{StructTmPtrTy}),
275811d2e63aSGabor Marton Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2759f0b9dbcfSGabor Marton
2760f0b9dbcfSGabor Marton // struct tm *localtime_r(const time_t *restrict timer,
2761f0b9dbcfSGabor Marton // struct tm *restrict result);
2762f0b9dbcfSGabor Marton addToFunctionSummaryMap(
2763f0b9dbcfSGabor Marton "localtime_r",
276411d2e63aSGabor Marton Signature(ArgTypes{ConstTime_tPtrRestrictTy, StructTmPtrRestrictTy},
276511d2e63aSGabor Marton RetType{StructTmPtrTy}),
276611d2e63aSGabor Marton Summary(NoEvalCall)
2767f0b9dbcfSGabor Marton .ArgConstraint(NotNull(ArgNo(0)))
2768f0b9dbcfSGabor Marton .ArgConstraint(NotNull(ArgNo(1))));
2769f0b9dbcfSGabor Marton
2770f0b9dbcfSGabor Marton // char *asctime_r(const struct tm *restrict tm, char *restrict buf);
2771f0b9dbcfSGabor Marton addToFunctionSummaryMap(
2772f0b9dbcfSGabor Marton "asctime_r",
277311d2e63aSGabor Marton Signature(ArgTypes{ConstStructTmPtrRestrictTy, CharPtrRestrictTy},
277411d2e63aSGabor Marton RetType{CharPtrTy}),
277511d2e63aSGabor Marton Summary(NoEvalCall)
2776f0b9dbcfSGabor Marton .ArgConstraint(NotNull(ArgNo(0)))
2777f0b9dbcfSGabor Marton .ArgConstraint(NotNull(ArgNo(1)))
2778f0b9dbcfSGabor Marton .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
2779f0b9dbcfSGabor Marton /*MinBufSize=*/BVF.getValue(26, IntTy))));
2780f0b9dbcfSGabor Marton
2781f0b9dbcfSGabor Marton // char *ctime_r(const time_t *timep, char *buf);
278211d2e63aSGabor Marton addToFunctionSummaryMap(
278311d2e63aSGabor Marton "ctime_r",
278411d2e63aSGabor Marton Signature(ArgTypes{ConstTime_tPtrTy, CharPtrTy}, RetType{CharPtrTy}),
278511d2e63aSGabor Marton Summary(NoEvalCall)
2786f0b9dbcfSGabor Marton .ArgConstraint(NotNull(ArgNo(0)))
2787f0b9dbcfSGabor Marton .ArgConstraint(NotNull(ArgNo(1)))
2788f0b9dbcfSGabor Marton .ArgConstraint(BufferSize(
2789f0b9dbcfSGabor Marton /*Buffer=*/ArgNo(1),
2790f0b9dbcfSGabor Marton /*MinBufSize=*/BVF.getValue(26, IntTy))));
2791f0b9dbcfSGabor Marton
2792f0b9dbcfSGabor Marton // struct tm *gmtime_r(const time_t *restrict timer,
2793f0b9dbcfSGabor Marton // struct tm *restrict result);
2794f0b9dbcfSGabor Marton addToFunctionSummaryMap(
2795f0b9dbcfSGabor Marton "gmtime_r",
279611d2e63aSGabor Marton Signature(ArgTypes{ConstTime_tPtrRestrictTy, StructTmPtrRestrictTy},
279711d2e63aSGabor Marton RetType{StructTmPtrTy}),
279811d2e63aSGabor Marton Summary(NoEvalCall)
2799f0b9dbcfSGabor Marton .ArgConstraint(NotNull(ArgNo(0)))
2800f0b9dbcfSGabor Marton .ArgConstraint(NotNull(ArgNo(1))));
2801f0b9dbcfSGabor Marton
2802f0b9dbcfSGabor Marton // struct tm * gmtime(const time_t *tp);
2803f0b9dbcfSGabor Marton addToFunctionSummaryMap(
280411d2e63aSGabor Marton "gmtime", Signature(ArgTypes{ConstTime_tPtrTy}, RetType{StructTmPtrTy}),
280511d2e63aSGabor Marton Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2806f0b9dbcfSGabor Marton
2807f0b9dbcfSGabor Marton Optional<QualType> Clockid_tTy = lookupTy("clockid_t");
2808f0b9dbcfSGabor Marton
2809f0b9dbcfSGabor Marton // int clock_gettime(clockid_t clock_id, struct timespec *tp);
281011d2e63aSGabor Marton addToFunctionSummaryMap(
281111d2e63aSGabor Marton "clock_gettime",
281211d2e63aSGabor Marton Signature(ArgTypes{Clockid_tTy, StructTimespecPtrTy}, RetType{IntTy}),
2813febe7503SGabor Marton Summary(NoEvalCall)
2814957014daSBalázs Kéri .Case(ReturnsZero, ErrnoMustNotBeChecked)
2815957014daSBalázs Kéri .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2816febe7503SGabor Marton .ArgConstraint(NotNull(ArgNo(1))));
2817f0b9dbcfSGabor Marton
2818f0b9dbcfSGabor Marton Optional<QualType> StructItimervalTy = lookupTy("itimerval");
2819f0b9dbcfSGabor Marton Optional<QualType> StructItimervalPtrTy = getPointerTy(StructItimervalTy);
2820f0b9dbcfSGabor Marton
2821f0b9dbcfSGabor Marton // int getitimer(int which, struct itimerval *curr_value);
282211d2e63aSGabor Marton addToFunctionSummaryMap(
282311d2e63aSGabor Marton "getitimer",
282411d2e63aSGabor Marton Signature(ArgTypes{IntTy, StructItimervalPtrTy}, RetType{IntTy}),
2825febe7503SGabor Marton Summary(NoEvalCall)
2826957014daSBalázs Kéri .Case(ReturnsZero, ErrnoMustNotBeChecked)
2827957014daSBalázs Kéri .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
2828febe7503SGabor Marton .ArgConstraint(NotNull(ArgNo(1))));
2829d0128058SGabor Marton
2830d0128058SGabor Marton Optional<QualType> Pthread_cond_tTy = lookupTy("pthread_cond_t");
2831d0128058SGabor Marton Optional<QualType> Pthread_cond_tPtrTy = getPointerTy(Pthread_cond_tTy);
2832d0128058SGabor Marton Optional<QualType> Pthread_tTy = lookupTy("pthread_t");
2833d0128058SGabor Marton Optional<QualType> Pthread_tPtrTy = getPointerTy(Pthread_tTy);
2834d0128058SGabor Marton Optional<QualType> Pthread_tPtrRestrictTy = getRestrictTy(Pthread_tPtrTy);
2835d0128058SGabor Marton Optional<QualType> Pthread_mutex_tTy = lookupTy("pthread_mutex_t");
2836d0128058SGabor Marton Optional<QualType> Pthread_mutex_tPtrTy = getPointerTy(Pthread_mutex_tTy);
2837d0128058SGabor Marton Optional<QualType> Pthread_mutex_tPtrRestrictTy =
2838d0128058SGabor Marton getRestrictTy(Pthread_mutex_tPtrTy);
2839d0128058SGabor Marton Optional<QualType> Pthread_attr_tTy = lookupTy("pthread_attr_t");
2840d0128058SGabor Marton Optional<QualType> Pthread_attr_tPtrTy = getPointerTy(Pthread_attr_tTy);
2841d0128058SGabor Marton Optional<QualType> ConstPthread_attr_tPtrTy =
2842d0128058SGabor Marton getPointerTy(getConstTy(Pthread_attr_tTy));
2843d0128058SGabor Marton Optional<QualType> ConstPthread_attr_tPtrRestrictTy =
2844d0128058SGabor Marton getRestrictTy(ConstPthread_attr_tPtrTy);
2845d0128058SGabor Marton Optional<QualType> Pthread_mutexattr_tTy = lookupTy("pthread_mutexattr_t");
2846d0128058SGabor Marton Optional<QualType> ConstPthread_mutexattr_tPtrTy =
2847d0128058SGabor Marton getPointerTy(getConstTy(Pthread_mutexattr_tTy));
2848d0128058SGabor Marton Optional<QualType> ConstPthread_mutexattr_tPtrRestrictTy =
2849d0128058SGabor Marton getRestrictTy(ConstPthread_mutexattr_tPtrTy);
2850d0128058SGabor Marton
2851d0128058SGabor Marton QualType PthreadStartRoutineTy = getPointerTy(
2852d0128058SGabor Marton ACtx.getFunctionType(/*ResultTy=*/VoidPtrTy, /*Args=*/VoidPtrTy,
2853d0128058SGabor Marton FunctionProtoType::ExtProtoInfo()));
2854d0128058SGabor Marton
2855d0128058SGabor Marton // int pthread_cond_signal(pthread_cond_t *cond);
2856d0128058SGabor Marton // int pthread_cond_broadcast(pthread_cond_t *cond);
2857d0128058SGabor Marton addToFunctionSummaryMap(
2858d0128058SGabor Marton {"pthread_cond_signal", "pthread_cond_broadcast"},
2859d0128058SGabor Marton Signature(ArgTypes{Pthread_cond_tPtrTy}, RetType{IntTy}),
2860d0128058SGabor Marton Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2861d0128058SGabor Marton
2862d0128058SGabor Marton // int pthread_create(pthread_t *restrict thread,
2863d0128058SGabor Marton // const pthread_attr_t *restrict attr,
2864d0128058SGabor Marton // void *(*start_routine)(void*), void *restrict arg);
2865d0128058SGabor Marton addToFunctionSummaryMap(
2866d0128058SGabor Marton "pthread_create",
2867d0128058SGabor Marton Signature(ArgTypes{Pthread_tPtrRestrictTy,
2868d0128058SGabor Marton ConstPthread_attr_tPtrRestrictTy,
2869d0128058SGabor Marton PthreadStartRoutineTy, VoidPtrRestrictTy},
2870d0128058SGabor Marton RetType{IntTy}),
2871d0128058SGabor Marton Summary(NoEvalCall)
2872d0128058SGabor Marton .ArgConstraint(NotNull(ArgNo(0)))
2873d0128058SGabor Marton .ArgConstraint(NotNull(ArgNo(2))));
2874d0128058SGabor Marton
2875d0128058SGabor Marton // int pthread_attr_destroy(pthread_attr_t *attr);
2876d0128058SGabor Marton // int pthread_attr_init(pthread_attr_t *attr);
2877d0128058SGabor Marton addToFunctionSummaryMap(
2878d0128058SGabor Marton {"pthread_attr_destroy", "pthread_attr_init"},
2879d0128058SGabor Marton Signature(ArgTypes{Pthread_attr_tPtrTy}, RetType{IntTy}),
2880d0128058SGabor Marton Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2881d0128058SGabor Marton
2882d0128058SGabor Marton // int pthread_attr_getstacksize(const pthread_attr_t *restrict attr,
2883d0128058SGabor Marton // size_t *restrict stacksize);
2884d0128058SGabor Marton // int pthread_attr_getguardsize(const pthread_attr_t *restrict attr,
2885d0128058SGabor Marton // size_t *restrict guardsize);
2886d0128058SGabor Marton addToFunctionSummaryMap(
2887d0128058SGabor Marton {"pthread_attr_getstacksize", "pthread_attr_getguardsize"},
2888d0128058SGabor Marton Signature(ArgTypes{ConstPthread_attr_tPtrRestrictTy, SizePtrRestrictTy},
2889d0128058SGabor Marton RetType{IntTy}),
2890d0128058SGabor Marton Summary(NoEvalCall)
2891d0128058SGabor Marton .ArgConstraint(NotNull(ArgNo(0)))
2892d0128058SGabor Marton .ArgConstraint(NotNull(ArgNo(1))));
2893d0128058SGabor Marton
2894d0128058SGabor Marton // int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize);
2895d0128058SGabor Marton // int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize);
2896d0128058SGabor Marton addToFunctionSummaryMap(
2897d0128058SGabor Marton {"pthread_attr_setstacksize", "pthread_attr_setguardsize"},
2898d0128058SGabor Marton Signature(ArgTypes{Pthread_attr_tPtrTy, SizeTy}, RetType{IntTy}),
2899d0128058SGabor Marton Summary(NoEvalCall)
2900d0128058SGabor Marton .ArgConstraint(NotNull(ArgNo(0)))
2901d0128058SGabor Marton .ArgConstraint(
2902d0128058SGabor Marton ArgumentCondition(1, WithinRange, Range(0, SizeMax))));
2903d0128058SGabor Marton
2904d0128058SGabor Marton // int pthread_mutex_init(pthread_mutex_t *restrict mutex, const
2905d0128058SGabor Marton // pthread_mutexattr_t *restrict attr);
2906d0128058SGabor Marton addToFunctionSummaryMap(
2907d0128058SGabor Marton "pthread_mutex_init",
2908d0128058SGabor Marton Signature(ArgTypes{Pthread_mutex_tPtrRestrictTy,
2909d0128058SGabor Marton ConstPthread_mutexattr_tPtrRestrictTy},
2910d0128058SGabor Marton RetType{IntTy}),
2911d0128058SGabor Marton Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2912d0128058SGabor Marton
2913d0128058SGabor Marton // int pthread_mutex_destroy(pthread_mutex_t *mutex);
2914d0128058SGabor Marton // int pthread_mutex_lock(pthread_mutex_t *mutex);
2915d0128058SGabor Marton // int pthread_mutex_trylock(pthread_mutex_t *mutex);
2916d0128058SGabor Marton // int pthread_mutex_unlock(pthread_mutex_t *mutex);
2917d0128058SGabor Marton addToFunctionSummaryMap(
2918d0128058SGabor Marton {"pthread_mutex_destroy", "pthread_mutex_lock", "pthread_mutex_trylock",
2919d0128058SGabor Marton "pthread_mutex_unlock"},
2920d0128058SGabor Marton Signature(ArgTypes{Pthread_mutex_tPtrTy}, RetType{IntTy}),
2921d0128058SGabor Marton Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2922db4d5f70SGabor Marton }
2923db4d5f70SGabor Marton
29241525232eSGabor Marton // Functions for testing.
29251525232eSGabor Marton if (ChecksEnabled[CK_StdCLibraryFunctionsTesterChecker]) {
292662e747f6SGabor Marton addToFunctionSummaryMap(
2927a7cb951fSGabor Marton "__not_null", Signature(ArgTypes{IntPtrTy}, RetType{IntTy}),
2928a7cb951fSGabor Marton Summary(EvalCallAsPure).ArgConstraint(NotNull(ArgNo(0))));
2929a7cb951fSGabor Marton
2930a7cb951fSGabor Marton // Test range values.
2931a7cb951fSGabor Marton addToFunctionSummaryMap(
2932a7cb951fSGabor Marton "__single_val_1", Signature(ArgTypes{IntTy}, RetType{IntTy}),
2933a7cb951fSGabor Marton Summary(EvalCallAsPure)
2934a7cb951fSGabor Marton .ArgConstraint(ArgumentCondition(0U, WithinRange, SingleValue(1))));
2935a7cb951fSGabor Marton addToFunctionSummaryMap(
2936a7cb951fSGabor Marton "__range_1_2", Signature(ArgTypes{IntTy}, RetType{IntTy}),
2937a7cb951fSGabor Marton Summary(EvalCallAsPure)
2938a7cb951fSGabor Marton .ArgConstraint(ArgumentCondition(0U, WithinRange, Range(1, 2))));
2939a7cb951fSGabor Marton addToFunctionSummaryMap("__range_1_2__4_5",
2940a7cb951fSGabor Marton Signature(ArgTypes{IntTy}, RetType{IntTy}),
2941a7cb951fSGabor Marton Summary(EvalCallAsPure)
2942a7cb951fSGabor Marton .ArgConstraint(ArgumentCondition(
2943a7cb951fSGabor Marton 0U, WithinRange, Range({1, 2}, {4, 5}))));
2944a7cb951fSGabor Marton
2945a7cb951fSGabor Marton // Test range kind.
2946a7cb951fSGabor Marton addToFunctionSummaryMap(
2947a7cb951fSGabor Marton "__within", Signature(ArgTypes{IntTy}, RetType{IntTy}),
2948a7cb951fSGabor Marton Summary(EvalCallAsPure)
2949a7cb951fSGabor Marton .ArgConstraint(ArgumentCondition(0U, WithinRange, SingleValue(1))));
2950a7cb951fSGabor Marton addToFunctionSummaryMap(
2951a7cb951fSGabor Marton "__out_of", Signature(ArgTypes{IntTy}, RetType{IntTy}),
2952a7cb951fSGabor Marton Summary(EvalCallAsPure)
2953a7cb951fSGabor Marton .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(1))));
2954a7cb951fSGabor Marton
2955a7cb951fSGabor Marton addToFunctionSummaryMap(
295662e747f6SGabor Marton "__two_constrained_args",
295711d2e63aSGabor Marton Signature(ArgTypes{IntTy, IntTy}, RetType{IntTy}),
295811d2e63aSGabor Marton Summary(EvalCallAsPure)
295962e747f6SGabor Marton .ArgConstraint(ArgumentCondition(0U, WithinRange, SingleValue(1)))
296062e747f6SGabor Marton .ArgConstraint(ArgumentCondition(1U, WithinRange, SingleValue(1))));
296162e747f6SGabor Marton addToFunctionSummaryMap(
296211d2e63aSGabor Marton "__arg_constrained_twice", Signature(ArgTypes{IntTy}, RetType{IntTy}),
296311d2e63aSGabor Marton Summary(EvalCallAsPure)
296462e747f6SGabor Marton .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(1)))
296562e747f6SGabor Marton .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(2))));
296662e747f6SGabor Marton addToFunctionSummaryMap(
296762e747f6SGabor Marton "__defaultparam",
296811d2e63aSGabor Marton Signature(ArgTypes{Irrelevant, IntTy}, RetType{IntTy}),
296911d2e63aSGabor Marton Summary(EvalCallAsPure).ArgConstraint(NotNull(ArgNo(0))));
297011d2e63aSGabor Marton addToFunctionSummaryMap(
297111d2e63aSGabor Marton "__variadic",
297211d2e63aSGabor Marton Signature(ArgTypes{VoidPtrTy, ConstCharPtrTy}, RetType{IntTy}),
297311d2e63aSGabor Marton Summary(EvalCallAsPure)
29748f961399SGabor Marton .ArgConstraint(NotNull(ArgNo(0)))
297562e747f6SGabor Marton .ArgConstraint(NotNull(ArgNo(1))));
2976bd03ef19SGabor Marton addToFunctionSummaryMap(
2977bd03ef19SGabor Marton "__buf_size_arg_constraint",
297811d2e63aSGabor Marton Signature(ArgTypes{ConstVoidPtrTy, SizeTy}, RetType{IntTy}),
297911d2e63aSGabor Marton Summary(EvalCallAsPure)
2980bd03ef19SGabor Marton .ArgConstraint(
2981bd03ef19SGabor Marton BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1))));
298241928c97SGabor Marton addToFunctionSummaryMap(
298341928c97SGabor Marton "__buf_size_arg_constraint_mul",
298411d2e63aSGabor Marton Signature(ArgTypes{ConstVoidPtrTy, SizeTy, SizeTy}, RetType{IntTy}),
298511d2e63aSGabor Marton Summary(EvalCallAsPure)
298641928c97SGabor Marton .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1),
298741928c97SGabor Marton /*BufSizeMultiplier=*/ArgNo(2))));
2988fe0972d3SGabor Marton addToFunctionSummaryMap(
2989f0b9dbcfSGabor Marton "__buf_size_arg_constraint_concrete",
299011d2e63aSGabor Marton Signature(ArgTypes{ConstVoidPtrTy}, RetType{IntTy}),
299111d2e63aSGabor Marton Summary(EvalCallAsPure)
2992f0b9dbcfSGabor Marton .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(0),
2993f0b9dbcfSGabor Marton /*BufSize=*/BVF.getValue(10, IntTy))));
2994f0b9dbcfSGabor Marton addToFunctionSummaryMap(
2995fe0972d3SGabor Marton {"__test_restrict_param_0", "__test_restrict_param_1",
2996fe0972d3SGabor Marton "__test_restrict_param_2"},
2997fe0972d3SGabor Marton Signature(ArgTypes{VoidPtrRestrictTy}, RetType{VoidTy}),
2998fe0972d3SGabor Marton Summary(EvalCallAsPure));
29991525232eSGabor Marton }
3000c7635040SValeriy Savchenko
3001c7635040SValeriy Savchenko SummariesInitialized = true;
3002bba497fbSArtem Dergachev }
3003bba497fbSArtem Dergachev
registerStdCLibraryFunctionsChecker(CheckerManager & mgr)3004bba497fbSArtem Dergachev void ento::registerStdCLibraryFunctionsChecker(CheckerManager &mgr) {
3005ff4492c8SGabor Marton auto *Checker = mgr.registerChecker<StdLibraryFunctionsChecker>();
3006edde4efcSBalazs Benics const AnalyzerOptions &Opts = mgr.getAnalyzerOptions();
3007ff4492c8SGabor Marton Checker->DisplayLoadedSummaries =
3008edde4efcSBalazs Benics Opts.getCheckerBooleanOption(Checker, "DisplayLoadedSummaries");
3009edde4efcSBalazs Benics Checker->ModelPOSIX = Opts.getCheckerBooleanOption(Checker, "ModelPOSIX");
3010edde4efcSBalazs Benics Checker->ShouldAssumeControlledEnvironment =
3011edde4efcSBalazs Benics Opts.ShouldAssumeControlledEnvironment;
3012bba497fbSArtem Dergachev }
3013058a7a45SKristof Umann
shouldRegisterStdCLibraryFunctionsChecker(const CheckerManager & mgr)301425bbe234SZurab Tsinadze bool ento::shouldRegisterStdCLibraryFunctionsChecker(
301525bbe234SZurab Tsinadze const CheckerManager &mgr) {
3016058a7a45SKristof Umann return true;
3017058a7a45SKristof Umann }
301894061df6SGabor Marton
301994061df6SGabor Marton #define REGISTER_CHECKER(name) \
302094061df6SGabor Marton void ento::register##name(CheckerManager &mgr) { \
302194061df6SGabor Marton StdLibraryFunctionsChecker *checker = \
302294061df6SGabor Marton mgr.getChecker<StdLibraryFunctionsChecker>(); \
302394061df6SGabor Marton checker->ChecksEnabled[StdLibraryFunctionsChecker::CK_##name] = true; \
302494061df6SGabor Marton checker->CheckNames[StdLibraryFunctionsChecker::CK_##name] = \
302594061df6SGabor Marton mgr.getCurrentCheckerName(); \
302694061df6SGabor Marton } \
302794061df6SGabor Marton \
3028bda3dd0dSKirstóf Umann bool ento::shouldRegister##name(const CheckerManager &mgr) { return true; }
302994061df6SGabor Marton
303094061df6SGabor Marton REGISTER_CHECKER(StdCLibraryFunctionArgsChecker)
30311525232eSGabor Marton REGISTER_CHECKER(StdCLibraryFunctionsTesterChecker)
3032