Bug Summary

File:clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
Warning:line 743, column 17
Called C++ object pointer is null

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name StdLibraryFunctionsChecker.cpp -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -mframe-pointer=none -relaxed-aliasing -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -ffunction-sections -fdata-sections -resource-dir /usr/lib/llvm-12/lib/clang/12.0.0 -D CLANG_VENDOR="Debian " -D _DEBUG -D _GNU_SOURCE -D __STDC_CONSTANT_MACROS -D __STDC_FORMAT_MACROS -D __STDC_LIMIT_MACROS -I /build/llvm-toolchain-snapshot-12~++20200926111128+c6c5629f2fb/build-llvm/tools/clang/lib/StaticAnalyzer/Checkers -I /build/llvm-toolchain-snapshot-12~++20200926111128+c6c5629f2fb/clang/lib/StaticAnalyzer/Checkers -I /build/llvm-toolchain-snapshot-12~++20200926111128+c6c5629f2fb/clang/include -I /build/llvm-toolchain-snapshot-12~++20200926111128+c6c5629f2fb/build-llvm/tools/clang/include -I /build/llvm-toolchain-snapshot-12~++20200926111128+c6c5629f2fb/build-llvm/include -I /build/llvm-toolchain-snapshot-12~++20200926111128+c6c5629f2fb/llvm/include -U NDEBUG -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/6.3.0/../../../../include/c++/6.3.0 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/6.3.0/../../../../include/x86_64-linux-gnu/c++/6.3.0 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/6.3.0/../../../../include/x86_64-linux-gnu/c++/6.3.0 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/6.3.0/../../../../include/c++/6.3.0/backward -internal-isystem /usr/local/include -internal-isystem /usr/lib/llvm-12/lib/clang/12.0.0/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wwrite-strings -Wno-missing-field-initializers -Wno-long-long -Wno-maybe-uninitialized -Wno-comment -std=c++14 -fdeprecated-macro -fdebug-compilation-dir /build/llvm-toolchain-snapshot-12~++20200926111128+c6c5629f2fb/build-llvm/tools/clang/lib/StaticAnalyzer/Checkers -fdebug-prefix-map=/build/llvm-toolchain-snapshot-12~++20200926111128+c6c5629f2fb=. -ferror-limit 19 -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -o /tmp/scan-build-2020-09-26-161721-17566-1 -x c++ /build/llvm-toolchain-snapshot-12~++20200926111128+c6c5629f2fb/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp

/build/llvm-toolchain-snapshot-12~++20200926111128+c6c5629f2fb/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp

1//=== StdLibraryFunctionsChecker.cpp - Model standard functions -*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This checker improves modeling of a few simple library functions.
10//
11// This checker provides a specification format - `Summary' - and
12// contains descriptions of some library functions in this format. Each
13// specification contains a list of branches for splitting the program state
14// upon call, and range constraints on argument and return-value symbols that
15// are satisfied on each branch. This spec can be expanded to include more
16// items, like external effects of the function.
17//
18// The main difference between this approach and the body farms technique is
19// in more explicit control over how many branches are produced. For example,
20// consider standard C function `ispunct(int x)', which returns a non-zero value
21// iff `x' is a punctuation character, that is, when `x' is in range
22// ['!', '/'] [':', '@'] U ['[', '\`'] U ['{', '~'].
23// `Summary' provides only two branches for this function. However,
24// any attempt to describe this range with if-statements in the body farm
25// would result in many more branches. Because each branch needs to be analyzed
26// independently, this significantly reduces performance. Additionally,
27// once we consider a branch on which `x' is in range, say, ['!', '/'],
28// we assume that such branch is an important separate path through the program,
29// which may lead to false positives because considering this particular path
30// was not consciously intended, and therefore it might have been unreachable.
31//
32// This checker uses eval::Call for modeling pure functions (functions without
33// side effets), for which their `Summary' is a precise model. This avoids
34// unnecessary invalidation passes. Conflicts with other checkers are unlikely
35// because if the function has no other effects, other checkers would probably
36// never want to improve upon the modeling done by this checker.
37//
38// Non-pure functions, for which only partial improvement over the default
39// behavior is expected, are modeled via check::PostCall, non-intrusively.
40//
41// The following standard C functions are currently supported:
42//
43// fgetc getline isdigit isupper toascii
44// fread isalnum isgraph isxdigit
45// fwrite isalpha islower read
46// getc isascii isprint write
47// getchar isblank ispunct toupper
48// getdelim iscntrl isspace tolower
49//
50//===----------------------------------------------------------------------===//
51
52#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
53#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
54#include "clang/StaticAnalyzer/Core/Checker.h"
55#include "clang/StaticAnalyzer/Core/CheckerManager.h"
56#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
57#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
58#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h"
59#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicSize.h"
60
61using namespace clang;
62using namespace clang::ento;
63
64namespace {
65class StdLibraryFunctionsChecker
66 : public Checker<check::PreCall, check::PostCall, eval::Call> {
67
68 class Summary;
69
70 /// Specify how much the analyzer engine should entrust modeling this function
71 /// to us. If he doesn't, he performs additional invalidations.
72 enum InvalidationKind { NoEvalCall, EvalCallAsPure };
73
74 // The universal integral type to use in value range descriptions.
75 // Unsigned to make sure overflows are well-defined.
76 typedef uint64_t RangeInt;
77
78 /// Normally, describes a single range constraint, eg. {{0, 1}, {3, 4}} is
79 /// a non-negative integer, which less than 5 and not equal to 2. For
80 /// `ComparesToArgument', holds information about how exactly to compare to
81 /// the argument.
82 typedef std::vector<std::pair<RangeInt, RangeInt>> IntRangeVector;
83
84 /// A reference to an argument or return value by its number.
85 /// ArgNo in CallExpr and CallEvent is defined as Unsigned, but
86 /// obviously uint32_t should be enough for all practical purposes.
87 typedef uint32_t ArgNo;
88 static const ArgNo Ret;
89
90 class ValueConstraint;
91
92 // Pointer to the ValueConstraint. We need a copyable, polymorphic and
93 // default initialize able type (vector needs that). A raw pointer was good,
94 // however, we cannot default initialize that. unique_ptr makes the Summary
95 // class non-copyable, therefore not an option. Releasing the copyability
96 // requirement would render the initialization of the Summary map infeasible.
97 using ValueConstraintPtr = std::shared_ptr<ValueConstraint>;
98
99 /// Polymorphic base class that represents a constraint on a given argument
100 /// (or return value) of a function. Derived classes implement different kind
101 /// of constraints, e.g range constraints or correlation between two
102 /// arguments.
103 class ValueConstraint {
104 public:
105 ValueConstraint(ArgNo ArgN) : ArgN(ArgN) {}
106 virtual ~ValueConstraint() {}
107 /// Apply the effects of the constraint on the given program state. If null
108 /// is returned then the constraint is not feasible.
109 virtual ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
110 const Summary &Summary,
111 CheckerContext &C) const = 0;
112 virtual ValueConstraintPtr negate() const {
113 llvm_unreachable("Not implemented")::llvm::llvm_unreachable_internal("Not implemented", "/build/llvm-toolchain-snapshot-12~++20200926111128+c6c5629f2fb/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp"
, 113)
;
114 };
115
116 // Check whether the constraint is malformed or not. It is malformed if the
117 // specified argument has a mismatch with the given FunctionDecl (e.g. the
118 // arg number is out-of-range of the function's argument list).
119 bool checkValidity(const FunctionDecl *FD) const {
120 const bool ValidArg = ArgN == Ret || ArgN < FD->getNumParams();
121 assert(ValidArg && "Arg out of range!")((ValidArg && "Arg out of range!") ? static_cast<void
> (0) : __assert_fail ("ValidArg && \"Arg out of range!\""
, "/build/llvm-toolchain-snapshot-12~++20200926111128+c6c5629f2fb/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp"
, 121, __PRETTY_FUNCTION__))
;
122 if (!ValidArg)
123 return false;
124 // Subclasses may further refine the validation.
125 return checkSpecificValidity(FD);
126 }
127 ArgNo getArgNo() const { return ArgN; }
128
129 virtual StringRef getName() const = 0;
130
131 protected:
132 ArgNo ArgN; // Argument to which we apply the constraint.
133
134 /// Do polymorphic sanity check on the constraint.
135 virtual bool checkSpecificValidity(const FunctionDecl *FD) const {
136 return true;
137 }
138 };
139
140 /// Given a range, should the argument stay inside or outside this range?
141 enum RangeKind { OutOfRange, WithinRange };
142
143 /// Encapsulates a range on a single symbol.
144 class RangeConstraint : public ValueConstraint {
145 RangeKind Kind;
146 // A range is formed as a set of intervals (sub-ranges).
147 // E.g. {['A', 'Z'], ['a', 'z']}
148 //
149 // The default constructed RangeConstraint has an empty range set, applying
150 // such constraint does not involve any assumptions, thus the State remains
151 // unchanged. This is meaningful, if the range is dependent on a looked up
152 // type (e.g. [0, Socklen_tMax]). If the type is not found, then the range
153 // is default initialized to be empty.
154 IntRangeVector Ranges;
155
156 public:
157 StringRef getName() const override { return "Range"; }
158 RangeConstraint(ArgNo ArgN, RangeKind Kind, const IntRangeVector &Ranges)
159 : ValueConstraint(ArgN), Kind(Kind), Ranges(Ranges) {}
160
161 const IntRangeVector &getRanges() const { return Ranges; }
162
163 private:
164 ProgramStateRef applyAsOutOfRange(ProgramStateRef State,
165 const CallEvent &Call,
166 const Summary &Summary) const;
167 ProgramStateRef applyAsWithinRange(ProgramStateRef State,
168 const CallEvent &Call,
169 const Summary &Summary) const;
170
171 public:
172 ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
173 const Summary &Summary,
174 CheckerContext &C) const override {
175 switch (Kind) {
176 case OutOfRange:
177 return applyAsOutOfRange(State, Call, Summary);
178 case WithinRange:
179 return applyAsWithinRange(State, Call, Summary);
180 }
181 llvm_unreachable("Unknown range kind!")::llvm::llvm_unreachable_internal("Unknown range kind!", "/build/llvm-toolchain-snapshot-12~++20200926111128+c6c5629f2fb/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp"
, 181)
;
182 }
183
184 ValueConstraintPtr negate() const override {
185 RangeConstraint Tmp(*this);
186 switch (Kind) {
187 case OutOfRange:
188 Tmp.Kind = WithinRange;
189 break;
190 case WithinRange:
191 Tmp.Kind = OutOfRange;
192 break;
193 }
194 return std::make_shared<RangeConstraint>(Tmp);
195 }
196
197 bool checkSpecificValidity(const FunctionDecl *FD) const override {
198 const bool ValidArg =
199 getArgType(FD, ArgN)->isIntegralType(FD->getASTContext());
200 assert(ValidArg &&((ValidArg && "This constraint should be applied on an integral type"
) ? static_cast<void> (0) : __assert_fail ("ValidArg && \"This constraint should be applied on an integral type\""
, "/build/llvm-toolchain-snapshot-12~++20200926111128+c6c5629f2fb/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp"
, 201, __PRETTY_FUNCTION__))
201 "This constraint should be applied on an integral type")((ValidArg && "This constraint should be applied on an integral type"
) ? static_cast<void> (0) : __assert_fail ("ValidArg && \"This constraint should be applied on an integral type\""
, "/build/llvm-toolchain-snapshot-12~++20200926111128+c6c5629f2fb/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp"
, 201, __PRETTY_FUNCTION__))
;
202 return ValidArg;
203 }
204 };
205
206 class ComparisonConstraint : public ValueConstraint {
207 BinaryOperator::Opcode Opcode;
208 ArgNo OtherArgN;
209
210 public:
211 virtual StringRef getName() const override { return "Comparison"; };
212 ComparisonConstraint(ArgNo ArgN, BinaryOperator::Opcode Opcode,
213 ArgNo OtherArgN)
214 : ValueConstraint(ArgN), Opcode(Opcode), OtherArgN(OtherArgN) {}
215 ArgNo getOtherArgNo() const { return OtherArgN; }
216 BinaryOperator::Opcode getOpcode() const { return Opcode; }
217 ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
218 const Summary &Summary,
219 CheckerContext &C) const override;
220 };
221
222 class NotNullConstraint : public ValueConstraint {
223 using ValueConstraint::ValueConstraint;
224 // This variable has a role when we negate the constraint.
225 bool CannotBeNull = true;
226
227 public:
228 StringRef getName() const override { return "NonNull"; }
229 ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
230 const Summary &Summary,
231 CheckerContext &C) const override {
232 SVal V = getArgSVal(Call, getArgNo());
233 if (V.isUndef())
234 return State;
235
236 DefinedOrUnknownSVal L = V.castAs<DefinedOrUnknownSVal>();
237 if (!L.getAs<Loc>())
238 return State;
239
240 return State->assume(L, CannotBeNull);
241 }
242
243 ValueConstraintPtr negate() const override {
244 NotNullConstraint Tmp(*this);
245 Tmp.CannotBeNull = !this->CannotBeNull;
246 return std::make_shared<NotNullConstraint>(Tmp);
247 }
248
249 bool checkSpecificValidity(const FunctionDecl *FD) const override {
250 const bool ValidArg = getArgType(FD, ArgN)->isPointerType();
251 assert(ValidArg &&((ValidArg && "This constraint should be applied only on a pointer type"
) ? static_cast<void> (0) : __assert_fail ("ValidArg && \"This constraint should be applied only on a pointer type\""
, "/build/llvm-toolchain-snapshot-12~++20200926111128+c6c5629f2fb/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp"
, 252, __PRETTY_FUNCTION__))
252 "This constraint should be applied only on a pointer type")((ValidArg && "This constraint should be applied only on a pointer type"
) ? static_cast<void> (0) : __assert_fail ("ValidArg && \"This constraint should be applied only on a pointer type\""
, "/build/llvm-toolchain-snapshot-12~++20200926111128+c6c5629f2fb/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp"
, 252, __PRETTY_FUNCTION__))
;
253 return ValidArg;
254 }
255 };
256
257 // Represents a buffer argument with an additional size constraint. The
258 // constraint may be a concrete value, or a symbolic value in an argument.
259 // Example 1. Concrete value as the minimum buffer size.
260 // char *asctime_r(const struct tm *restrict tm, char *restrict buf);
261 // // `buf` size must be at least 26 bytes according the POSIX standard.
262 // Example 2. Argument as a buffer size.
263 // ctime_s(char *buffer, rsize_t bufsz, const time_t *time);
264 // Example 3. The size is computed as a multiplication of other args.
265 // size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
266 // // Here, ptr is the buffer, and its minimum size is `size * nmemb`.
267 class BufferSizeConstraint : public ValueConstraint {
268 // The concrete value which is the minimum size for the buffer.
269 llvm::Optional<llvm::APSInt> ConcreteSize;
270 // The argument which holds the size of the buffer.
271 llvm::Optional<ArgNo> SizeArgN;
272 // The argument which is a multiplier to size. This is set in case of
273 // `fread` like functions where the size is computed as a multiplication of
274 // two arguments.
275 llvm::Optional<ArgNo> SizeMultiplierArgN;
276 // The operator we use in apply. This is negated in negate().
277 BinaryOperator::Opcode Op = BO_LE;
278
279 public:
280 StringRef getName() const override { return "BufferSize"; }
281 BufferSizeConstraint(ArgNo Buffer, llvm::APSInt BufMinSize)
282 : ValueConstraint(Buffer), ConcreteSize(BufMinSize) {}
283 BufferSizeConstraint(ArgNo Buffer, ArgNo BufSize)
284 : ValueConstraint(Buffer), SizeArgN(BufSize) {}
285 BufferSizeConstraint(ArgNo Buffer, ArgNo BufSize, ArgNo BufSizeMultiplier)
286 : ValueConstraint(Buffer), SizeArgN(BufSize),
287 SizeMultiplierArgN(BufSizeMultiplier) {}
288
289 ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
290 const Summary &Summary,
291 CheckerContext &C) const override {
292 SValBuilder &SvalBuilder = C.getSValBuilder();
293 // The buffer argument.
294 SVal BufV = getArgSVal(Call, getArgNo());
295
296 // Get the size constraint.
297 const SVal SizeV = [this, &State, &Call, &Summary, &SvalBuilder]() {
298 if (ConcreteSize) {
299 return SVal(SvalBuilder.makeIntVal(*ConcreteSize));
300 } else if (SizeArgN) {
301 // The size argument.
302 SVal SizeV = getArgSVal(Call, *SizeArgN);
303 // Multiply with another argument if given.
304 if (SizeMultiplierArgN) {
305 SVal SizeMulV = getArgSVal(Call, *SizeMultiplierArgN);
306 SizeV = SvalBuilder.evalBinOp(State, BO_Mul, SizeV, SizeMulV,
307 Summary.getArgType(*SizeArgN));
308 }
309 return SizeV;
310 } else {
311 llvm_unreachable("The constraint must be either a concrete value or "::llvm::llvm_unreachable_internal("The constraint must be either a concrete value or "
"encoded in an arguement.", "/build/llvm-toolchain-snapshot-12~++20200926111128+c6c5629f2fb/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp"
, 312)
312 "encoded in an arguement.")::llvm::llvm_unreachable_internal("The constraint must be either a concrete value or "
"encoded in an arguement.", "/build/llvm-toolchain-snapshot-12~++20200926111128+c6c5629f2fb/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp"
, 312)
;
313 }
314 }();
315
316 // The dynamic size of the buffer argument, got from the analyzer engine.
317 SVal BufDynSize = getDynamicSizeWithOffset(State, BufV);
318
319 SVal Feasible = SvalBuilder.evalBinOp(State, Op, SizeV, BufDynSize,
320 SvalBuilder.getContext().BoolTy);
321 if (auto F = Feasible.getAs<DefinedOrUnknownSVal>())
322 return State->assume(*F, true);
323
324 // We can get here only if the size argument or the dynamic size is
325 // undefined. But the dynamic size should never be undefined, only
326 // unknown. So, here, the size of the argument is undefined, i.e. we
327 // cannot apply the constraint. Actually, other checkers like
328 // CallAndMessage should catch this situation earlier, because we call a
329 // function with an uninitialized argument.
330 llvm_unreachable("Size argument or the dynamic size is Undefined")::llvm::llvm_unreachable_internal("Size argument or the dynamic size is Undefined"
, "/build/llvm-toolchain-snapshot-12~++20200926111128+c6c5629f2fb/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp"
, 330)
;
331 }
332
333 ValueConstraintPtr negate() const override {
334 BufferSizeConstraint Tmp(*this);
335 Tmp.Op = BinaryOperator::negateComparisonOp(Op);
336 return std::make_shared<BufferSizeConstraint>(Tmp);
337 }
338
339 bool checkSpecificValidity(const FunctionDecl *FD) const override {
340 const bool ValidArg = getArgType(FD, ArgN)->isPointerType();
341 assert(ValidArg &&((ValidArg && "This constraint should be applied only on a pointer type"
) ? static_cast<void> (0) : __assert_fail ("ValidArg && \"This constraint should be applied only on a pointer type\""
, "/build/llvm-toolchain-snapshot-12~++20200926111128+c6c5629f2fb/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp"
, 342, __PRETTY_FUNCTION__))
342 "This constraint should be applied only on a pointer type")((ValidArg && "This constraint should be applied only on a pointer type"
) ? static_cast<void> (0) : __assert_fail ("ValidArg && \"This constraint should be applied only on a pointer type\""
, "/build/llvm-toolchain-snapshot-12~++20200926111128+c6c5629f2fb/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp"
, 342, __PRETTY_FUNCTION__))
;
343 return ValidArg;
344 }
345 };
346
347 /// The complete list of constraints that defines a single branch.
348 typedef std::vector<ValueConstraintPtr> ConstraintSet;
349
350 using ArgTypes = std::vector<Optional<QualType>>;
351 using RetType = Optional<QualType>;
352
353 // A placeholder type, we use it whenever we do not care about the concrete
354 // type in a Signature.
355 const QualType Irrelevant{};
356 bool static isIrrelevant(QualType T) { return T.isNull(); }
357
358 // The signature of a function we want to describe with a summary. This is a
359 // concessive signature, meaning there may be irrelevant types in the
360 // signature which we do not check against a function with concrete types.
361 // All types in the spec need to be canonical.
362 class Signature {
363 using ArgQualTypes = std::vector<QualType>;
364 ArgQualTypes ArgTys;
365 QualType RetTy;
366 // True if any component type is not found by lookup.
367 bool Invalid = false;
368
369 public:
370 // Construct a signature from optional types. If any of the optional types
371 // are not set then the signature will be invalid.
372 Signature(ArgTypes ArgTys, RetType RetTy) {
373 for (Optional<QualType> Arg : ArgTys) {
374 if (!Arg) {
375 Invalid = true;
376 return;
377 } else {
378 assertArgTypeSuitableForSignature(*Arg);
379 this->ArgTys.push_back(*Arg);
380 }
381 }
382 if (!RetTy) {
383 Invalid = true;
384 return;
385 } else {
386 assertRetTypeSuitableForSignature(*RetTy);
387 this->RetTy = *RetTy;
388 }
389 }
390
391 bool isInvalid() const { return Invalid; }
392 bool matches(const FunctionDecl *FD) const;
393
394 private:
395 static void assertArgTypeSuitableForSignature(QualType T) {
396 assert((T.isNull() || !T->isVoidType()) &&(((T.isNull() || !T->isVoidType()) && "We should have no void types in the spec"
) ? static_cast<void> (0) : __assert_fail ("(T.isNull() || !T->isVoidType()) && \"We should have no void types in the spec\""
, "/build/llvm-toolchain-snapshot-12~++20200926111128+c6c5629f2fb/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp"
, 397, __PRETTY_FUNCTION__))
397 "We should have no void types in the spec")(((T.isNull() || !T->isVoidType()) && "We should have no void types in the spec"
) ? static_cast<void> (0) : __assert_fail ("(T.isNull() || !T->isVoidType()) && \"We should have no void types in the spec\""
, "/build/llvm-toolchain-snapshot-12~++20200926111128+c6c5629f2fb/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp"
, 397, __PRETTY_FUNCTION__))
;
398 assert((T.isNull() || T.isCanonical()) &&(((T.isNull() || T.isCanonical()) && "We should only have canonical types in the spec"
) ? static_cast<void> (0) : __assert_fail ("(T.isNull() || T.isCanonical()) && \"We should only have canonical types in the spec\""
, "/build/llvm-toolchain-snapshot-12~++20200926111128+c6c5629f2fb/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp"
, 399, __PRETTY_FUNCTION__))
399 "We should only have canonical types in the spec")(((T.isNull() || T.isCanonical()) && "We should only have canonical types in the spec"
) ? static_cast<void> (0) : __assert_fail ("(T.isNull() || T.isCanonical()) && \"We should only have canonical types in the spec\""
, "/build/llvm-toolchain-snapshot-12~++20200926111128+c6c5629f2fb/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp"
, 399, __PRETTY_FUNCTION__))
;
400 }
401 static void assertRetTypeSuitableForSignature(QualType T) {
402 assert((T.isNull() || T.isCanonical()) &&(((T.isNull() || T.isCanonical()) && "We should only have canonical types in the spec"
) ? static_cast<void> (0) : __assert_fail ("(T.isNull() || T.isCanonical()) && \"We should only have canonical types in the spec\""
, "/build/llvm-toolchain-snapshot-12~++20200926111128+c6c5629f2fb/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp"
, 403, __PRETTY_FUNCTION__))
403 "We should only have canonical types in the spec")(((T.isNull() || T.isCanonical()) && "We should only have canonical types in the spec"
) ? static_cast<void> (0) : __assert_fail ("(T.isNull() || T.isCanonical()) && \"We should only have canonical types in the spec\""
, "/build/llvm-toolchain-snapshot-12~++20200926111128+c6c5629f2fb/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp"
, 403, __PRETTY_FUNCTION__))
;
404 }
405 };
406
407 static QualType getArgType(const FunctionDecl *FD, ArgNo ArgN) {
408 assert(FD && "Function must be set")((FD && "Function must be set") ? static_cast<void
> (0) : __assert_fail ("FD && \"Function must be set\""
, "/build/llvm-toolchain-snapshot-12~++20200926111128+c6c5629f2fb/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp"
, 408, __PRETTY_FUNCTION__))
;
409 QualType T = (ArgN == Ret)
410 ? FD->getReturnType().getCanonicalType()
411 : FD->getParamDecl(ArgN)->getType().getCanonicalType();
412 return T;
413 }
414
415 using Cases = std::vector<ConstraintSet>;
416
417 /// A summary includes information about
418 /// * function prototype (signature)
419 /// * approach to invalidation,
420 /// * a list of branches - a list of list of ranges -
421 /// A branch represents a path in the exploded graph of a function (which
422 /// is a tree). So, a branch is a series of assumptions. In other words,
423 /// branches represent split states and additional assumptions on top of
424 /// the splitting assumption.
425 /// For example, consider the branches in `isalpha(x)`
426 /// Branch 1)
427 /// x is in range ['A', 'Z'] or in ['a', 'z']
428 /// then the return value is not 0. (I.e. out-of-range [0, 0])
429 /// Branch 2)
430 /// x is out-of-range ['A', 'Z'] and out-of-range ['a', 'z']
431 /// then the return value is 0.
432 /// * a list of argument constraints, that must be true on every branch.
433 /// If these constraints are not satisfied that means a fatal error
434 /// usually resulting in undefined behaviour.
435 ///
436 /// Application of a summary:
437 /// The signature and argument constraints together contain information
438 /// about which functions are handled by the summary. The signature can use
439 /// "wildcards", i.e. Irrelevant types. Irrelevant type of a parameter in
440 /// a signature means that type is not compared to the type of the parameter
441 /// in the found FunctionDecl. Argument constraints may specify additional
442 /// rules for the given parameter's type, those rules are checked once the
443 /// signature is matched.
444 class Summary {
445 const InvalidationKind InvalidationKd;
446 Cases CaseConstraints;
447 ConstraintSet ArgConstraints;
448
449 // The function to which the summary applies. This is set after lookup and
450 // match to the signature.
451 const FunctionDecl *FD = nullptr;
452
453 public:
454 Summary(InvalidationKind InvalidationKd) : InvalidationKd(InvalidationKd) {}
455
456 Summary &Case(ConstraintSet &&CS) {
457 CaseConstraints.push_back(std::move(CS));
458 return *this;
459 }
460 Summary &ArgConstraint(ValueConstraintPtr VC) {
461 assert(VC->getArgNo() != Ret &&((VC->getArgNo() != Ret && "Arg constraint should not refer to the return value"
) ? static_cast<void> (0) : __assert_fail ("VC->getArgNo() != Ret && \"Arg constraint should not refer to the return value\""
, "/build/llvm-toolchain-snapshot-12~++20200926111128+c6c5629f2fb/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp"
, 462, __PRETTY_FUNCTION__))
462 "Arg constraint should not refer to the return value")((VC->getArgNo() != Ret && "Arg constraint should not refer to the return value"
) ? static_cast<void> (0) : __assert_fail ("VC->getArgNo() != Ret && \"Arg constraint should not refer to the return value\""
, "/build/llvm-toolchain-snapshot-12~++20200926111128+c6c5629f2fb/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp"
, 462, __PRETTY_FUNCTION__))
;
463 ArgConstraints.push_back(VC);
464 return *this;
465 }
466
467 InvalidationKind getInvalidationKd() const { return InvalidationKd; }
468 const Cases &getCaseConstraints() const { return CaseConstraints; }
469 const ConstraintSet &getArgConstraints() const { return ArgConstraints; }
470
471 QualType getArgType(ArgNo ArgN) const {
472 return StdLibraryFunctionsChecker::getArgType(FD, ArgN);
473 }
474
475 // Returns true if the summary should be applied to the given function.
476 // And if yes then store the function declaration.
477 bool matchesAndSet(const Signature &Sign, const FunctionDecl *FD) {
478 bool Result = Sign.matches(FD) && validateByConstraints(FD);
479 if (Result) {
480 assert(!this->FD && "FD must not be set more than once")((!this->FD && "FD must not be set more than once"
) ? static_cast<void> (0) : __assert_fail ("!this->FD && \"FD must not be set more than once\""
, "/build/llvm-toolchain-snapshot-12~++20200926111128+c6c5629f2fb/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp"
, 480, __PRETTY_FUNCTION__))
;
481 this->FD = FD;
482 }
483 return Result;
484 }
485
486 private:
487 // Once we know the exact type of the function then do sanity check on all
488 // the given constraints.
489 bool validateByConstraints(const FunctionDecl *FD) const {
490 for (const ConstraintSet &Case : CaseConstraints)
491 for (const ValueConstraintPtr &Constraint : Case)
492 if (!Constraint->checkValidity(FD))
493 return false;
494 for (const ValueConstraintPtr &Constraint : ArgConstraints)
495 if (!Constraint->checkValidity(FD))
496 return false;
497 return true;
498 }
499 };
500
501 // The map of all functions supported by the checker. It is initialized
502 // lazily, and it doesn't change after initialization.
503 using FunctionSummaryMapType = llvm::DenseMap<const FunctionDecl *, Summary>;
504 mutable FunctionSummaryMapType FunctionSummaryMap;
505
506 mutable std::unique_ptr<BugType> BT_InvalidArg;
507
508 static SVal getArgSVal(const CallEvent &Call, ArgNo ArgN) {
509 return ArgN == Ret ? Call.getReturnValue() : Call.getArgSVal(ArgN);
510 }
511
512public:
513 void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
514 void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
515 bool evalCall(const CallEvent &Call, CheckerContext &C) const;
516
517 enum CheckKind {
518 CK_StdCLibraryFunctionArgsChecker,
519 CK_StdCLibraryFunctionsTesterChecker,
520 CK_NumCheckKinds
521 };
522 DefaultBool ChecksEnabled[CK_NumCheckKinds];
523 CheckerNameRef CheckNames[CK_NumCheckKinds];
524
525 bool DisplayLoadedSummaries = false;
526 bool ModelPOSIX = false;
527
528private:
529 Optional<Summary> findFunctionSummary(const FunctionDecl *FD,
530 CheckerContext &C) const;
531 Optional<Summary> findFunctionSummary(const CallEvent &Call,
532 CheckerContext &C) const;
533
534 void initFunctionSummaries(CheckerContext &C) const;
535
536 void reportBug(const CallEvent &Call, ExplodedNode *N,
537 const ValueConstraint *VC, CheckerContext &C) const {
538 if (!ChecksEnabled[CK_StdCLibraryFunctionArgsChecker])
539 return;
540 // TODO Add more detailed diagnostic.
541 std::string Msg =
542 (Twine("Function argument constraint is not satisfied, constraint: ") +
543 VC->getName().data() + ", ArgN: " + Twine(VC->getArgNo()))
544 .str();
545 if (!BT_InvalidArg)
546 BT_InvalidArg = std::make_unique<BugType>(
547 CheckNames[CK_StdCLibraryFunctionArgsChecker],
548 "Unsatisfied argument constraints", categories::LogicError);
549 auto R = std::make_unique<PathSensitiveBugReport>(*BT_InvalidArg, Msg, N);
550 bugreporter::trackExpressionValue(N, Call.getArgExpr(VC->getArgNo()), *R);
551
552 // Highlight the range of the argument that was violated.
553 R->addRange(Call.getArgSourceRange(VC->getArgNo()));
554
555 C.emitReport(std::move(R));
556 }
557};
558
559const StdLibraryFunctionsChecker::ArgNo StdLibraryFunctionsChecker::Ret =
560 std::numeric_limits<ArgNo>::max();
561
562} // end of anonymous namespace
563
564ProgramStateRef StdLibraryFunctionsChecker::RangeConstraint::applyAsOutOfRange(
565 ProgramStateRef State, const CallEvent &Call,
566 const Summary &Summary) const {
567 if (Ranges.empty())
568 return State;
569
570 ProgramStateManager &Mgr = State->getStateManager();
571 SValBuilder &SVB = Mgr.getSValBuilder();
572 BasicValueFactory &BVF = SVB.getBasicValueFactory();
573 ConstraintManager &CM = Mgr.getConstraintManager();
574 QualType T = Summary.getArgType(getArgNo());
575 SVal V = getArgSVal(Call, getArgNo());
576
577 if (auto N = V.getAs<NonLoc>()) {
578 const IntRangeVector &R = getRanges();
579 size_t E = R.size();
580 for (size_t I = 0; I != E; ++I) {
581 const llvm::APSInt &Min = BVF.getValue(R[I].first, T);
582 const llvm::APSInt &Max = BVF.getValue(R[I].second, T);
583 assert(Min <= Max)((Min <= Max) ? static_cast<void> (0) : __assert_fail
("Min <= Max", "/build/llvm-toolchain-snapshot-12~++20200926111128+c6c5629f2fb/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp"
, 583, __PRETTY_FUNCTION__))
;
584 State = CM.assumeInclusiveRange(State, *N, Min, Max, false);
585 if (!State)
586 break;
587 }
588 }
589
590 return State;
591}
592
593ProgramStateRef StdLibraryFunctionsChecker::RangeConstraint::applyAsWithinRange(
594 ProgramStateRef State, const CallEvent &Call,
595 const Summary &Summary) const {
596 if (Ranges.empty())
597 return State;
598
599 ProgramStateManager &Mgr = State->getStateManager();
600 SValBuilder &SVB = Mgr.getSValBuilder();
601 BasicValueFactory &BVF = SVB.getBasicValueFactory();
602 ConstraintManager &CM = Mgr.getConstraintManager();
603 QualType T = Summary.getArgType(getArgNo());
604 SVal V = getArgSVal(Call, getArgNo());
605
606 // "WithinRange R" is treated as "outside [T_MIN, T_MAX] \ R".
607 // We cut off [T_MIN, min(R) - 1] and [max(R) + 1, T_MAX] if necessary,
608 // and then cut away all holes in R one by one.
609 //
610 // E.g. consider a range list R as [A, B] and [C, D]
611 // -------+--------+------------------+------------+----------->
612 // A B C D
613 // Then we assume that the value is not in [-inf, A - 1],
614 // then not in [D + 1, +inf], then not in [B + 1, C - 1]
615 if (auto N = V.getAs<NonLoc>()) {
616 const IntRangeVector &R = getRanges();
617 size_t E = R.size();
618
619 const llvm::APSInt &MinusInf = BVF.getMinValue(T);
620 const llvm::APSInt &PlusInf = BVF.getMaxValue(T);
621
622 const llvm::APSInt &Left = BVF.getValue(R[0].first - 1ULL, T);
623 if (Left != PlusInf) {
624 assert(MinusInf <= Left)((MinusInf <= Left) ? static_cast<void> (0) : __assert_fail
("MinusInf <= Left", "/build/llvm-toolchain-snapshot-12~++20200926111128+c6c5629f2fb/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp"
, 624, __PRETTY_FUNCTION__))
;
625 State = CM.assumeInclusiveRange(State, *N, MinusInf, Left, false);
626 if (!State)
627 return nullptr;
628 }
629
630 const llvm::APSInt &Right = BVF.getValue(R[E - 1].second + 1ULL, T);
631 if (Right != MinusInf) {
632 assert(Right <= PlusInf)((Right <= PlusInf) ? static_cast<void> (0) : __assert_fail
("Right <= PlusInf", "/build/llvm-toolchain-snapshot-12~++20200926111128+c6c5629f2fb/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp"
, 632, __PRETTY_FUNCTION__))
;
633 State = CM.assumeInclusiveRange(State, *N, Right, PlusInf, false);
634 if (!State)
635 return nullptr;
636 }
637
638 for (size_t I = 1; I != E; ++I) {
639 const llvm::APSInt &Min = BVF.getValue(R[I - 1].second + 1ULL, T);
640 const llvm::APSInt &Max = BVF.getValue(R[I].first - 1ULL, T);
641 if (Min <= Max) {
642 State = CM.assumeInclusiveRange(State, *N, Min, Max, false);
643 if (!State)
644 return nullptr;
645 }
646 }
647 }
648
649 return State;
650}
651
652ProgramStateRef StdLibraryFunctionsChecker::ComparisonConstraint::apply(
653 ProgramStateRef State, const CallEvent &Call, const Summary &Summary,
654 CheckerContext &C) const {
655
656 ProgramStateManager &Mgr = State->getStateManager();
657 SValBuilder &SVB = Mgr.getSValBuilder();
658 QualType CondT = SVB.getConditionType();
659 QualType T = Summary.getArgType(getArgNo());
660 SVal V = getArgSVal(Call, getArgNo());
661
662 BinaryOperator::Opcode Op = getOpcode();
663 ArgNo OtherArg = getOtherArgNo();
664 SVal OtherV = getArgSVal(Call, OtherArg);
665 QualType OtherT = Summary.getArgType(OtherArg);
666 // Note: we avoid integral promotion for comparison.
667 OtherV = SVB.evalCast(OtherV, T, OtherT);
668 if (auto CompV = SVB.evalBinOp(State, Op, V, OtherV, CondT)
669 .getAs<DefinedOrUnknownSVal>())
670 State = State->assume(*CompV, true);
671 return State;
672}
673
674void StdLibraryFunctionsChecker::checkPreCall(const CallEvent &Call,
675 CheckerContext &C) const {
676 Optional<Summary> FoundSummary = findFunctionSummary(Call, C);
677 if (!FoundSummary)
678 return;
679
680 const Summary &Summary = *FoundSummary;
681 ProgramStateRef State = C.getState();
682
683 ProgramStateRef NewState = State;
684 for (const ValueConstraintPtr &Constraint : Summary.getArgConstraints()) {
685 ProgramStateRef SuccessSt = Constraint->apply(NewState, Call, Summary, C);
686 ProgramStateRef FailureSt =
687 Constraint->negate()->apply(NewState, Call, Summary, C);
688 // The argument constraint is not satisfied.
689 if (FailureSt && !SuccessSt) {
690 if (ExplodedNode *N = C.generateErrorNode(NewState))
691 reportBug(Call, N, Constraint.get(), C);
692 break;
693 } else {
694 // We will apply the constraint even if we cannot reason about the
695 // argument. This means both SuccessSt and FailureSt can be true. If we
696 // weren't applying the constraint that would mean that symbolic
697 // execution continues on a code whose behaviour is undefined.
698 assert(SuccessSt)((SuccessSt) ? static_cast<void> (0) : __assert_fail ("SuccessSt"
, "/build/llvm-toolchain-snapshot-12~++20200926111128+c6c5629f2fb/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp"
, 698, __PRETTY_FUNCTION__))
;
699 NewState = SuccessSt;
700 }
701 }
702 if (NewState && NewState != State)
703 C.addTransition(NewState);
704}
705
706void StdLibraryFunctionsChecker::checkPostCall(const CallEvent &Call,
707 CheckerContext &C) const {
708 Optional<Summary> FoundSummary = findFunctionSummary(Call, C);
709 if (!FoundSummary)
710 return;
711
712 // Now apply the constraints.
713 const Summary &Summary = *FoundSummary;
714 ProgramStateRef State = C.getState();
715
716 // Apply case/branch specifications.
717 for (const ConstraintSet &Case : Summary.getCaseConstraints()) {
718 ProgramStateRef NewState = State;
719 for (const ValueConstraintPtr &Constraint : Case) {
720 NewState = Constraint->apply(NewState, Call, Summary, C);
721 if (!NewState)
722 break;
723 }
724
725 if (NewState && NewState != State)
726 C.addTransition(NewState);
727 }
728}
729
730bool StdLibraryFunctionsChecker::evalCall(const CallEvent &Call,
731 CheckerContext &C) const {
732 Optional<Summary> FoundSummary = findFunctionSummary(Call, C);
733 if (!FoundSummary)
1
Calling 'Optional::operator bool'
9
Returning from 'Optional::operator bool'
10
Taking false branch
734 return false;
735
736 const Summary &Summary = *FoundSummary;
737 switch (Summary.getInvalidationKd()) {
11
Control jumps to 'case EvalCallAsPure:' at line 738
738 case EvalCallAsPure: {
739 ProgramStateRef State = C.getState();
740 const LocationContext *LC = C.getLocationContext();
741 const auto *CE = cast_or_null<CallExpr>(Call.getOriginExpr());
12
Assuming null pointer is passed into cast
13
'CE' initialized to a null pointer value
742 SVal V = C.getSValBuilder().conjureSymbolVal(
743 CE, LC, CE->getType().getCanonicalType(), C.blockCount());
14
Called C++ object pointer is null
744 State = State->BindExpr(CE, LC, V);
745 C.addTransition(State);
746 return true;
747 }
748 case NoEvalCall:
749 // Summary tells us to avoid performing eval::Call. The function is possibly
750 // evaluated by another checker, or evaluated conservatively.
751 return false;
752 }
753 llvm_unreachable("Unknown invalidation kind!")::llvm::llvm_unreachable_internal("Unknown invalidation kind!"
, "/build/llvm-toolchain-snapshot-12~++20200926111128+c6c5629f2fb/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp"
, 753)
;
754}
755
756bool StdLibraryFunctionsChecker::Signature::matches(
757 const FunctionDecl *FD) const {
758 assert(!isInvalid())((!isInvalid()) ? static_cast<void> (0) : __assert_fail
("!isInvalid()", "/build/llvm-toolchain-snapshot-12~++20200926111128+c6c5629f2fb/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp"
, 758, __PRETTY_FUNCTION__))
;
759 // Check the number of arguments.
760 if (FD->param_size() != ArgTys.size())
761 return false;
762
763 // The "restrict" keyword is illegal in C++, however, many libc
764 // implementations use the "__restrict" compiler intrinsic in functions
765 // prototypes. The "__restrict" keyword qualifies a type as a restricted type
766 // even in C++.
767 // In case of any non-C99 languages, we don't want to match based on the
768 // restrict qualifier because we cannot know if the given libc implementation
769 // qualifies the paramter type or not.
770 auto RemoveRestrict = [&FD](QualType T) {
771 if (!FD->getASTContext().getLangOpts().C99)
772 T.removeLocalRestrict();
773 return T;
774 };
775
776 // Check the return type.
777 if (!isIrrelevant(RetTy)) {
778 QualType FDRetTy = RemoveRestrict(FD->getReturnType().getCanonicalType());
779 if (RetTy != FDRetTy)
780 return false;
781 }
782
783 // Check the argument types.
784 for (size_t I = 0, E = ArgTys.size(); I != E; ++I) {
785 QualType ArgTy = ArgTys[I];
786 if (isIrrelevant(ArgTy))
787 continue;
788 QualType FDArgTy =
789 RemoveRestrict(FD->getParamDecl(I)->getType().getCanonicalType());
790 if (ArgTy != FDArgTy)
791 return false;
792 }
793
794 return true;
795}
796
797Optional<StdLibraryFunctionsChecker::Summary>
798StdLibraryFunctionsChecker::findFunctionSummary(const FunctionDecl *FD,
799 CheckerContext &C) const {
800 if (!FD)
801 return None;
802
803 initFunctionSummaries(C);
804
805 auto FSMI = FunctionSummaryMap.find(FD->getCanonicalDecl());
806 if (FSMI == FunctionSummaryMap.end())
807 return None;
808 return FSMI->second;
809}
810
811Optional<StdLibraryFunctionsChecker::Summary>
812StdLibraryFunctionsChecker::findFunctionSummary(const CallEvent &Call,
813 CheckerContext &C) const {
814 const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
815 if (!FD)
816 return None;
817 return findFunctionSummary(FD, C);
818}
819
820void StdLibraryFunctionsChecker::initFunctionSummaries(
821 CheckerContext &C) const {
822 if (!FunctionSummaryMap.empty())
823 return;
824
825 SValBuilder &SVB = C.getSValBuilder();
826 BasicValueFactory &BVF = SVB.getBasicValueFactory();
827 const ASTContext &ACtx = BVF.getContext();
828
829 // Helper class to lookup a type by its name.
830 class LookupType {
831 const ASTContext &ACtx;
832
833 public:
834 LookupType(const ASTContext &ACtx) : ACtx(ACtx) {}
835
836 // Find the type. If not found then the optional is not set.
837 llvm::Optional<QualType> operator()(StringRef Name) {
838 IdentifierInfo &II = ACtx.Idents.get(Name);
839 auto LookupRes = ACtx.getTranslationUnitDecl()->lookup(&II);
840 if (LookupRes.size() == 0)
841 return None;
842
843 // Prioritze typedef declarations.
844 // This is needed in case of C struct typedefs. E.g.:
845 // typedef struct FILE FILE;
846 // In this case, we have a RecordDecl 'struct FILE' with the name 'FILE'
847 // and we have a TypedefDecl with the name 'FILE'.
848 for (Decl *D : LookupRes)
849 if (auto *TD = dyn_cast<TypedefNameDecl>(D))
850 return ACtx.getTypeDeclType(TD).getCanonicalType();
851
852 // Find the first TypeDecl.
853 // There maybe cases when a function has the same name as a struct.
854 // E.g. in POSIX: `struct stat` and the function `stat()`:
855 // int stat(const char *restrict path, struct stat *restrict buf);
856 for (Decl *D : LookupRes)
857 if (auto *TD = dyn_cast<TypeDecl>(D))
858 return ACtx.getTypeDeclType(TD).getCanonicalType();
859 return None;
860 }
861 } lookupTy(ACtx);
862
863 // Below are auxiliary classes to handle optional types that we get as a
864 // result of the lookup.
865 class GetRestrictTy {
866 const ASTContext &ACtx;
867
868 public:
869 GetRestrictTy(const ASTContext &ACtx) : ACtx(ACtx) {}
870 QualType operator()(QualType Ty) {
871 return ACtx.getLangOpts().C99 ? ACtx.getRestrictType(Ty) : Ty;
872 }
873 Optional<QualType> operator()(Optional<QualType> Ty) {
874 if (Ty)
875 return operator()(*Ty);
876 return None;
877 }
878 } getRestrictTy(ACtx);
879 class GetPointerTy {
880 const ASTContext &ACtx;
881
882 public:
883 GetPointerTy(const ASTContext &ACtx) : ACtx(ACtx) {}
884 QualType operator()(QualType Ty) { return ACtx.getPointerType(Ty); }
885 Optional<QualType> operator()(Optional<QualType> Ty) {
886 if (Ty)
887 return operator()(*Ty);
888 return None;
889 }
890 } getPointerTy(ACtx);
891 class {
892 public:
893 Optional<QualType> operator()(Optional<QualType> Ty) {
894 return Ty ? Optional<QualType>(Ty->withConst()) : None;
895 }
896 QualType operator()(QualType Ty) { return Ty.withConst(); }
897 } getConstTy;
898 class GetMaxValue {
899 BasicValueFactory &BVF;
900
901 public:
902 GetMaxValue(BasicValueFactory &BVF) : BVF(BVF) {}
903 Optional<RangeInt> operator()(QualType Ty) {
904 return BVF.getMaxValue(Ty).getLimitedValue();
905 }
906 Optional<RangeInt> operator()(Optional<QualType> Ty) {
907 if (Ty) {
908 return operator()(*Ty);
909 }
910 return None;
911 }
912 } getMaxValue(BVF);
913
914 // These types are useful for writing specifications quickly,
915 // New specifications should probably introduce more types.
916 // Some types are hard to obtain from the AST, eg. "ssize_t".
917 // In such cases it should be possible to provide multiple variants
918 // of function summary for common cases (eg. ssize_t could be int or long
919 // or long long, so three summary variants would be enough).
920 // Of course, function variants are also useful for C++ overloads.
921 const QualType VoidTy = ACtx.VoidTy;
922 const QualType CharTy = ACtx.CharTy;
923 const QualType WCharTy = ACtx.WCharTy;
924 const QualType IntTy = ACtx.IntTy;
925 const QualType UnsignedIntTy = ACtx.UnsignedIntTy;
926 const QualType LongTy = ACtx.LongTy;
927 const QualType SizeTy = ACtx.getSizeType();
928
929 const QualType VoidPtrTy = getPointerTy(VoidTy); // void *
930 const QualType IntPtrTy = getPointerTy(IntTy); // int *
931 const QualType UnsignedIntPtrTy =
932 getPointerTy(UnsignedIntTy); // unsigned int *
933 const QualType VoidPtrRestrictTy = getRestrictTy(VoidPtrTy);
934 const QualType ConstVoidPtrTy =
935 getPointerTy(getConstTy(VoidTy)); // const void *
936 const QualType CharPtrTy = getPointerTy(CharTy); // char *
937 const QualType CharPtrRestrictTy = getRestrictTy(CharPtrTy);
938 const QualType ConstCharPtrTy =
939 getPointerTy(getConstTy(CharTy)); // const char *
940 const QualType ConstCharPtrRestrictTy = getRestrictTy(ConstCharPtrTy);
941 const QualType Wchar_tPtrTy = getPointerTy(WCharTy); // wchar_t *
942 const QualType ConstWchar_tPtrTy =
943 getPointerTy(getConstTy(WCharTy)); // const wchar_t *
944 const QualType ConstVoidPtrRestrictTy = getRestrictTy(ConstVoidPtrTy);
945 const QualType SizePtrTy = getPointerTy(SizeTy);
946 const QualType SizePtrRestrictTy = getRestrictTy(SizePtrTy);
947
948 const RangeInt IntMax = BVF.getMaxValue(IntTy).getLimitedValue();
949 const RangeInt UnsignedIntMax =
950 BVF.getMaxValue(UnsignedIntTy).getLimitedValue();
951 const RangeInt LongMax = BVF.getMaxValue(LongTy).getLimitedValue();
952 const RangeInt SizeMax = BVF.getMaxValue(SizeTy).getLimitedValue();
953
954 // Set UCharRangeMax to min of int or uchar maximum value.
955 // The C standard states that the arguments of functions like isalpha must
956 // be representable as an unsigned char. Their type is 'int', so the max
957 // value of the argument should be min(UCharMax, IntMax). This just happen
958 // to be true for commonly used and well tested instruction set
959 // architectures, but not for others.
960 const RangeInt UCharRangeMax =
961 std::min(BVF.getMaxValue(ACtx.UnsignedCharTy).getLimitedValue(), IntMax);
962
963 // The platform dependent value of EOF.
964 // Try our best to parse this from the Preprocessor, otherwise fallback to -1.
965 const auto EOFv = [&C]() -> RangeInt {
966 if (const llvm::Optional<int> OptInt =
967 tryExpandAsInteger("EOF", C.getPreprocessor()))
968 return *OptInt;
969 return -1;
970 }();
971
972 // Auxiliary class to aid adding summaries to the summary map.
973 struct AddToFunctionSummaryMap {
974 const ASTContext &ACtx;
975 FunctionSummaryMapType &Map;
976 bool DisplayLoadedSummaries;
977 AddToFunctionSummaryMap(const ASTContext &ACtx, FunctionSummaryMapType &FSM,
978 bool DisplayLoadedSummaries)
979 : ACtx(ACtx), Map(FSM), DisplayLoadedSummaries(DisplayLoadedSummaries) {
980 }
981
982 // Add a summary to a FunctionDecl found by lookup. The lookup is performed
983 // by the given Name, and in the global scope. The summary will be attached
984 // to the found FunctionDecl only if the signatures match.
985 //
986 // Returns true if the summary has been added, false otherwise.
987 bool operator()(StringRef Name, Signature Sign, Summary Sum) {
988 if (Sign.isInvalid())
989 return false;
990 IdentifierInfo &II = ACtx.Idents.get(Name);
991 auto LookupRes = ACtx.getTranslationUnitDecl()->lookup(&II);
992 if (LookupRes.size() == 0)
993 return false;
994 for (Decl *D : LookupRes) {
995 if (auto *FD = dyn_cast<FunctionDecl>(D)) {
996 if (Sum.matchesAndSet(Sign, FD)) {
997 auto Res = Map.insert({FD->getCanonicalDecl(), Sum});
998 assert(Res.second && "Function already has a summary set!")((Res.second && "Function already has a summary set!"
) ? static_cast<void> (0) : __assert_fail ("Res.second && \"Function already has a summary set!\""
, "/build/llvm-toolchain-snapshot-12~++20200926111128+c6c5629f2fb/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp"
, 998, __PRETTY_FUNCTION__))
;
999 (void)Res;
1000 if (DisplayLoadedSummaries) {
1001 llvm::errs() << "Loaded summary for: ";
1002 FD->print(llvm::errs());
1003 llvm::errs() << "\n";
1004 }
1005 return true;
1006 }
1007 }
1008 }
1009 return false;
1010 }
1011 // Add the same summary for different names with the Signature explicitly
1012 // given.
1013 void operator()(std::vector<StringRef> Names, Signature Sign, Summary Sum) {
1014 for (StringRef Name : Names)
1015 operator()(Name, Sign, Sum);
1016 }
1017 } addToFunctionSummaryMap(ACtx, FunctionSummaryMap, DisplayLoadedSummaries);
1018
1019 // Below are helpers functions to create the summaries.
1020 auto ArgumentCondition = [](ArgNo ArgN, RangeKind Kind,
1021 IntRangeVector Ranges) {
1022 return std::make_shared<RangeConstraint>(ArgN, Kind, Ranges);
1023 };
1024 auto BufferSize = [](auto... Args) {
1025 return std::make_shared<BufferSizeConstraint>(Args...);
1026 };
1027 struct {
1028 auto operator()(RangeKind Kind, IntRangeVector Ranges) {
1029 return std::make_shared<RangeConstraint>(Ret, Kind, Ranges);
1030 }
1031 auto operator()(BinaryOperator::Opcode Op, ArgNo OtherArgN) {
1032 return std::make_shared<ComparisonConstraint>(Ret, Op, OtherArgN);
1033 }
1034 } ReturnValueCondition;
1035 struct {
1036 auto operator()(RangeInt b, RangeInt e) {
1037 return IntRangeVector{std::pair<RangeInt, RangeInt>{b, e}};
1038 }
1039 auto operator()(RangeInt b, Optional<RangeInt> e) {
1040 if (e)
1041 return IntRangeVector{std::pair<RangeInt, RangeInt>{b, *e}};
1042 return IntRangeVector{};
1043 }
1044 auto operator()(std::pair<RangeInt, RangeInt> i0,
1045 std::pair<RangeInt, Optional<RangeInt>> i1) {
1046 if (i1.second)
1047 return IntRangeVector{i0, {i1.first, *(i1.second)}};
1048 return IntRangeVector{i0};
1049 }
1050 } Range;
1051 auto SingleValue = [](RangeInt v) {
1052 return IntRangeVector{std::pair<RangeInt, RangeInt>{v, v}};
1053 };
1054 auto LessThanOrEq = BO_LE;
1055 auto NotNull = [&](ArgNo ArgN) {
1056 return std::make_shared<NotNullConstraint>(ArgN);
1057 };
1058
1059 Optional<QualType> FileTy = lookupTy("FILE");
1060 Optional<QualType> FilePtrTy = getPointerTy(FileTy);
1061 Optional<QualType> FilePtrRestrictTy = getRestrictTy(FilePtrTy);
1062
1063 // We are finally ready to define specifications for all supported functions.
1064 //
1065 // Argument ranges should always cover all variants. If return value
1066 // is completely unknown, omit it from the respective range set.
1067 //
1068 // Every item in the list of range sets represents a particular
1069 // execution path the analyzer would need to explore once
1070 // the call is modeled - a new program state is constructed
1071 // for every range set, and each range line in the range set
1072 // corresponds to a specific constraint within this state.
1073
1074 // The isascii() family of functions.
1075 // The behavior is undefined if the value of the argument is not
1076 // representable as unsigned char or is not equal to EOF. See e.g. C99
1077 // 7.4.1.2 The isalpha function (p: 181-182).
1078 addToFunctionSummaryMap(
1079 "isalnum", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1080 Summary(EvalCallAsPure)
1081 // Boils down to isupper() or islower() or isdigit().
1082 .Case({ArgumentCondition(0U, WithinRange,
1083 {{'0', '9'}, {'A', 'Z'}, {'a', 'z'}}),
1084 ReturnValueCondition(OutOfRange, SingleValue(0))})
1085 // The locale-specific range.
1086 // No post-condition. We are completely unaware of
1087 // locale-specific return values.
1088 .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})})
1089 .Case(
1090 {ArgumentCondition(
1091 0U, OutOfRange,
1092 {{'0', '9'}, {'A', 'Z'}, {'a', 'z'}, {128, UCharRangeMax}}),
1093 ReturnValueCondition(WithinRange, SingleValue(0))})
1094 .ArgConstraint(ArgumentCondition(
1095 0U, WithinRange, {{EOFv, EOFv}, {0, UCharRangeMax}})));
1096 addToFunctionSummaryMap(
1097 "isalpha", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1098 Summary(EvalCallAsPure)
1099 .Case({ArgumentCondition(0U, WithinRange, {{'A', 'Z'}, {'a', 'z'}}),
1100 ReturnValueCondition(OutOfRange, SingleValue(0))})
1101 // The locale-specific range.
1102 .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})})
1103 .Case({ArgumentCondition(
1104 0U, OutOfRange,
1105 {{'A', 'Z'}, {'a', 'z'}, {128, UCharRangeMax}}),
1106 ReturnValueCondition(WithinRange, SingleValue(0))}));
1107 addToFunctionSummaryMap(
1108 "isascii", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1109 Summary(EvalCallAsPure)
1110 .Case({ArgumentCondition(0U, WithinRange, Range(0, 127)),
1111 ReturnValueCondition(OutOfRange, SingleValue(0))})
1112 .Case({ArgumentCondition(0U, OutOfRange, Range(0, 127)),
1113 ReturnValueCondition(WithinRange, SingleValue(0))}));
1114 addToFunctionSummaryMap(
1115 "isblank", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1116 Summary(EvalCallAsPure)
1117 .Case({ArgumentCondition(0U, WithinRange, {{'\t', '\t'}, {' ', ' '}}),
1118 ReturnValueCondition(OutOfRange, SingleValue(0))})
1119 .Case({ArgumentCondition(0U, OutOfRange, {{'\t', '\t'}, {' ', ' '}}),
1120 ReturnValueCondition(WithinRange, SingleValue(0))}));
1121 addToFunctionSummaryMap(
1122 "iscntrl", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1123 Summary(EvalCallAsPure)
1124 .Case({ArgumentCondition(0U, WithinRange, {{0, 32}, {127, 127}}),
1125 ReturnValueCondition(OutOfRange, SingleValue(0))})
1126 .Case({ArgumentCondition(0U, OutOfRange, {{0, 32}, {127, 127}}),
1127 ReturnValueCondition(WithinRange, SingleValue(0))}));
1128 addToFunctionSummaryMap(
1129 "isdigit", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1130 Summary(EvalCallAsPure)
1131 .Case({ArgumentCondition(0U, WithinRange, Range('0', '9')),
1132 ReturnValueCondition(OutOfRange, SingleValue(0))})
1133 .Case({ArgumentCondition(0U, OutOfRange, Range('0', '9')),
1134 ReturnValueCondition(WithinRange, SingleValue(0))}));
1135 addToFunctionSummaryMap(
1136 "isgraph", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1137 Summary(EvalCallAsPure)
1138 .Case({ArgumentCondition(0U, WithinRange, Range(33, 126)),
1139 ReturnValueCondition(OutOfRange, SingleValue(0))})
1140 .Case({ArgumentCondition(0U, OutOfRange, Range(33, 126)),
1141 ReturnValueCondition(WithinRange, SingleValue(0))}));
1142 addToFunctionSummaryMap(
1143 "islower", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1144 Summary(EvalCallAsPure)
1145 // Is certainly lowercase.
1146 .Case({ArgumentCondition(0U, WithinRange, Range('a', 'z')),
1147 ReturnValueCondition(OutOfRange, SingleValue(0))})
1148 // Is ascii but not lowercase.
1149 .Case({ArgumentCondition(0U, WithinRange, Range(0, 127)),
1150 ArgumentCondition(0U, OutOfRange, Range('a', 'z')),
1151 ReturnValueCondition(WithinRange, SingleValue(0))})
1152 // The locale-specific range.
1153 .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})})
1154 // Is not an unsigned char.
1155 .Case({ArgumentCondition(0U, OutOfRange, Range(0, UCharRangeMax)),
1156 ReturnValueCondition(WithinRange, SingleValue(0))}));
1157 addToFunctionSummaryMap(
1158 "isprint", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1159 Summary(EvalCallAsPure)
1160 .Case({ArgumentCondition(0U, WithinRange, Range(32, 126)),
1161 ReturnValueCondition(OutOfRange, SingleValue(0))})
1162 .Case({ArgumentCondition(0U, OutOfRange, Range(32, 126)),
1163 ReturnValueCondition(WithinRange, SingleValue(0))}));
1164 addToFunctionSummaryMap(
1165 "ispunct", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1166 Summary(EvalCallAsPure)
1167 .Case({ArgumentCondition(
1168 0U, WithinRange,
1169 {{'!', '/'}, {':', '@'}, {'[', '`'}, {'{', '~'}}),
1170 ReturnValueCondition(OutOfRange, SingleValue(0))})
1171 .Case({ArgumentCondition(
1172 0U, OutOfRange,
1173 {{'!', '/'}, {':', '@'}, {'[', '`'}, {'{', '~'}}),
1174 ReturnValueCondition(WithinRange, SingleValue(0))}));
1175 addToFunctionSummaryMap(
1176 "isspace", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1177 Summary(EvalCallAsPure)
1178 // Space, '\f', '\n', '\r', '\t', '\v'.
1179 .Case({ArgumentCondition(0U, WithinRange, {{9, 13}, {' ', ' '}}),
1180 ReturnValueCondition(OutOfRange, SingleValue(0))})
1181 // The locale-specific range.
1182 .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})})
1183 .Case({ArgumentCondition(0U, OutOfRange,
1184 {{9, 13}, {' ', ' '}, {128, UCharRangeMax}}),
1185 ReturnValueCondition(WithinRange, SingleValue(0))}));
1186 addToFunctionSummaryMap(
1187 "isupper", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1188 Summary(EvalCallAsPure)
1189 // Is certainly uppercase.
1190 .Case({ArgumentCondition(0U, WithinRange, Range('A', 'Z')),
1191 ReturnValueCondition(OutOfRange, SingleValue(0))})
1192 // The locale-specific range.
1193 .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})})
1194 // Other.
1195 .Case({ArgumentCondition(0U, OutOfRange,
1196 {{'A', 'Z'}, {128, UCharRangeMax}}),
1197 ReturnValueCondition(WithinRange, SingleValue(0))}));
1198 addToFunctionSummaryMap(
1199 "isxdigit", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1200 Summary(EvalCallAsPure)
1201 .Case({ArgumentCondition(0U, WithinRange,
1202 {{'0', '9'}, {'A', 'F'}, {'a', 'f'}}),
1203 ReturnValueCondition(OutOfRange, SingleValue(0))})
1204 .Case({ArgumentCondition(0U, OutOfRange,
1205 {{'0', '9'}, {'A', 'F'}, {'a', 'f'}}),
1206 ReturnValueCondition(WithinRange, SingleValue(0))}));
1207 addToFunctionSummaryMap(
1208 "toupper", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1209 Summary(EvalCallAsPure)
1210 .ArgConstraint(ArgumentCondition(
1211 0U, WithinRange, {{EOFv, EOFv}, {0, UCharRangeMax}})));
1212 addToFunctionSummaryMap(
1213 "tolower", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1214 Summary(EvalCallAsPure)
1215 .ArgConstraint(ArgumentCondition(
1216 0U, WithinRange, {{EOFv, EOFv}, {0, UCharRangeMax}})));
1217 addToFunctionSummaryMap(
1218 "toascii", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1219 Summary(EvalCallAsPure)
1220 .ArgConstraint(ArgumentCondition(
1221 0U, WithinRange, {{EOFv, EOFv}, {0, UCharRangeMax}})));
1222
1223 // The getc() family of functions that returns either a char or an EOF.
1224 addToFunctionSummaryMap(
1225 {"getc", "fgetc"}, Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
1226 Summary(NoEvalCall)
1227 .Case({ReturnValueCondition(WithinRange,
1228 {{EOFv, EOFv}, {0, UCharRangeMax}})}));
1229 addToFunctionSummaryMap(
1230 "getchar", Signature(ArgTypes{}, RetType{IntTy}),
1231 Summary(NoEvalCall)
1232 .Case({ReturnValueCondition(WithinRange,
1233 {{EOFv, EOFv}, {0, UCharRangeMax}})}));
1234
1235 // read()-like functions that never return more than buffer size.
1236 auto FreadSummary =
1237 Summary(NoEvalCall)
1238 .Case({
1239 ReturnValueCondition(LessThanOrEq, ArgNo(2)),
1240 })
1241 .ArgConstraint(NotNull(ArgNo(0)))
1242 .ArgConstraint(NotNull(ArgNo(3)))
1243 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1),
1244 /*BufSizeMultiplier=*/ArgNo(2)));
1245
1246 // size_t fread(void *restrict ptr, size_t size, size_t nitems,
1247 // FILE *restrict stream);
1248 addToFunctionSummaryMap(
1249 "fread",
1250 Signature(ArgTypes{VoidPtrRestrictTy, SizeTy, SizeTy, FilePtrRestrictTy},
1251 RetType{SizeTy}),
1252 FreadSummary);
1253 // size_t fwrite(const void *restrict ptr, size_t size, size_t nitems,
1254 // FILE *restrict stream);
1255 addToFunctionSummaryMap("fwrite",
1256 Signature(ArgTypes{ConstVoidPtrRestrictTy, SizeTy,
1257 SizeTy, FilePtrRestrictTy},
1258 RetType{SizeTy}),
1259 FreadSummary);
1260
1261 Optional<QualType> Ssize_tTy = lookupTy("ssize_t");
1262 Optional<RangeInt> Ssize_tMax = getMaxValue(Ssize_tTy);
1263
1264 auto ReadSummary =
1265 Summary(NoEvalCall)
1266 .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)),
1267 ReturnValueCondition(WithinRange, Range(-1, Ssize_tMax))});
1268
1269 // FIXME these are actually defined by POSIX and not by the C standard, we
1270 // should handle them together with the rest of the POSIX functions.
1271 // ssize_t read(int fildes, void *buf, size_t nbyte);
1272 addToFunctionSummaryMap(
1273 "read", Signature(ArgTypes{IntTy, VoidPtrTy, SizeTy}, RetType{Ssize_tTy}),
1274 ReadSummary);
1275 // ssize_t write(int fildes, const void *buf, size_t nbyte);
1276 addToFunctionSummaryMap(
1277 "write",
1278 Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTy}, RetType{Ssize_tTy}),
1279 ReadSummary);
1280
1281 auto GetLineSummary =
1282 Summary(NoEvalCall)
1283 .Case({ReturnValueCondition(WithinRange,
1284 Range({-1, -1}, {1, Ssize_tMax}))});
1285
1286 QualType CharPtrPtrRestrictTy = getRestrictTy(getPointerTy(CharPtrTy));
1287
1288 // getline()-like functions either fail or read at least the delimiter.
1289 // FIXME these are actually defined by POSIX and not by the C standard, we
1290 // should handle them together with the rest of the POSIX functions.
1291 // ssize_t getline(char **restrict lineptr, size_t *restrict n,
1292 // FILE *restrict stream);
1293 addToFunctionSummaryMap(
1294 "getline",
1295 Signature(
1296 ArgTypes{CharPtrPtrRestrictTy, SizePtrRestrictTy, FilePtrRestrictTy},
1297 RetType{Ssize_tTy}),
1298 GetLineSummary);
1299 // ssize_t getdelim(char **restrict lineptr, size_t *restrict n,
1300 // int delimiter, FILE *restrict stream);
1301 addToFunctionSummaryMap(
1302 "getdelim",
1303 Signature(ArgTypes{CharPtrPtrRestrictTy, SizePtrRestrictTy, IntTy,
1304 FilePtrRestrictTy},
1305 RetType{Ssize_tTy}),
1306 GetLineSummary);
1307
1308 if (ModelPOSIX) {
1309
1310 // long a64l(const char *str64);
1311 addToFunctionSummaryMap(
1312 "a64l", Signature(ArgTypes{ConstCharPtrTy}, RetType{LongTy}),
1313 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
1314
1315 // char *l64a(long value);
1316 addToFunctionSummaryMap("l64a",
1317 Signature(ArgTypes{LongTy}, RetType{CharPtrTy}),
1318 Summary(NoEvalCall)
1319 .ArgConstraint(ArgumentCondition(
1320 0, WithinRange, Range(0, LongMax))));
1321
1322 // int access(const char *pathname, int amode);
1323 addToFunctionSummaryMap(
1324 "access", Signature(ArgTypes{ConstCharPtrTy, IntTy}, RetType{IntTy}),
1325 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
1326
1327 // int faccessat(int dirfd, const char *pathname, int mode, int flags);
1328 addToFunctionSummaryMap(
1329 "faccessat",
1330 Signature(ArgTypes{IntTy, ConstCharPtrTy, IntTy, IntTy},
1331 RetType{IntTy}),
1332 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(1))));
1333
1334 // int dup(int fildes);
1335 addToFunctionSummaryMap("dup", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1336 Summary(NoEvalCall)
1337 .ArgConstraint(ArgumentCondition(
1338 0, WithinRange, Range(0, IntMax))));
1339
1340 // int dup2(int fildes1, int filedes2);
1341 addToFunctionSummaryMap(
1342 "dup2", Signature(ArgTypes{IntTy, IntTy}, RetType{IntTy}),
1343 Summary(NoEvalCall)
1344 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
1345 .ArgConstraint(
1346 ArgumentCondition(1, WithinRange, Range(0, IntMax))));
1347
1348 // int fdatasync(int fildes);
1349 addToFunctionSummaryMap("fdatasync",
1350 Signature(ArgTypes{IntTy}, RetType{IntTy}),
1351 Summary(NoEvalCall)
1352 .ArgConstraint(ArgumentCondition(
1353 0, WithinRange, Range(0, IntMax))));
1354
1355 // int fnmatch(const char *pattern, const char *string, int flags);
1356 addToFunctionSummaryMap(
1357 "fnmatch",
1358 Signature(ArgTypes{ConstCharPtrTy, ConstCharPtrTy, IntTy},
1359 RetType{IntTy}),
1360 Summary(EvalCallAsPure)
1361 .ArgConstraint(NotNull(ArgNo(0)))
1362 .ArgConstraint(NotNull(ArgNo(1))));
1363
1364 // int fsync(int fildes);
1365 addToFunctionSummaryMap("fsync", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1366 Summary(NoEvalCall)
1367 .ArgConstraint(ArgumentCondition(
1368 0, WithinRange, Range(0, IntMax))));
1369
1370 Optional<QualType> Off_tTy = lookupTy("off_t");
1371
1372 // int truncate(const char *path, off_t length);
1373 addToFunctionSummaryMap(
1374 "truncate",
1375 Signature(ArgTypes{ConstCharPtrTy, Off_tTy}, RetType{IntTy}),
1376 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
1377
1378 // int symlink(const char *oldpath, const char *newpath);
1379 addToFunctionSummaryMap(
1380 "symlink",
1381 Signature(ArgTypes{ConstCharPtrTy, ConstCharPtrTy}, RetType{IntTy}),
1382 Summary(NoEvalCall)
1383 .ArgConstraint(NotNull(ArgNo(0)))
1384 .ArgConstraint(NotNull(ArgNo(1))));
1385
1386 // int symlinkat(const char *oldpath, int newdirfd, const char *newpath);
1387 addToFunctionSummaryMap(
1388 "symlinkat",
1389 Signature(ArgTypes{ConstCharPtrTy, IntTy, ConstCharPtrTy},
1390 RetType{IntTy}),
1391 Summary(NoEvalCall)
1392 .ArgConstraint(NotNull(ArgNo(0)))
1393 .ArgConstraint(ArgumentCondition(1, WithinRange, Range(0, IntMax)))
1394 .ArgConstraint(NotNull(ArgNo(2))));
1395
1396 // int lockf(int fd, int cmd, off_t len);
1397 addToFunctionSummaryMap(
1398 "lockf", Signature(ArgTypes{IntTy, IntTy, Off_tTy}, RetType{IntTy}),
1399 Summary(NoEvalCall)
1400 .ArgConstraint(
1401 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
1402
1403 Optional<QualType> Mode_tTy = lookupTy("mode_t");
1404
1405 // int creat(const char *pathname, mode_t mode);
1406 addToFunctionSummaryMap(
1407 "creat", Signature(ArgTypes{ConstCharPtrTy, Mode_tTy}, RetType{IntTy}),
1408 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
1409
1410 // unsigned int sleep(unsigned int seconds);
1411 addToFunctionSummaryMap(
1412 "sleep", Signature(ArgTypes{UnsignedIntTy}, RetType{UnsignedIntTy}),
1413 Summary(NoEvalCall)
1414 .ArgConstraint(
1415 ArgumentCondition(0, WithinRange, Range(0, UnsignedIntMax))));
1416
1417 Optional<QualType> DirTy = lookupTy("DIR");
1418 Optional<QualType> DirPtrTy = getPointerTy(DirTy);
1419
1420 // int dirfd(DIR *dirp);
1421 addToFunctionSummaryMap(
1422 "dirfd", Signature(ArgTypes{DirPtrTy}, RetType{IntTy}),
1423 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
1424
1425 // unsigned int alarm(unsigned int seconds);
1426 addToFunctionSummaryMap(
1427 "alarm", Signature(ArgTypes{UnsignedIntTy}, RetType{UnsignedIntTy}),
1428 Summary(NoEvalCall)
1429 .ArgConstraint(
1430 ArgumentCondition(0, WithinRange, Range(0, UnsignedIntMax))));
1431
1432 // int closedir(DIR *dir);
1433 addToFunctionSummaryMap(
1434 "closedir", Signature(ArgTypes{DirPtrTy}, RetType{IntTy}),
1435 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
1436
1437 // char *strdup(const char *s);
1438 addToFunctionSummaryMap(
1439 "strdup", Signature(ArgTypes{ConstCharPtrTy}, RetType{CharPtrTy}),
1440 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
1441
1442 // char *strndup(const char *s, size_t n);
1443 addToFunctionSummaryMap(
1444 "strndup",
1445 Signature(ArgTypes{ConstCharPtrTy, SizeTy}, RetType{CharPtrTy}),
1446 Summary(NoEvalCall)
1447 .ArgConstraint(NotNull(ArgNo(0)))
1448 .ArgConstraint(
1449 ArgumentCondition(1, WithinRange, Range(0, SizeMax))));
1450
1451 // wchar_t *wcsdup(const wchar_t *s);
1452 addToFunctionSummaryMap(
1453 "wcsdup", Signature(ArgTypes{ConstWchar_tPtrTy}, RetType{Wchar_tPtrTy}),
1454 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
1455
1456 // int mkstemp(char *template);
1457 addToFunctionSummaryMap(
1458 "mkstemp", Signature(ArgTypes{CharPtrTy}, RetType{IntTy}),
1459 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
1460
1461 // char *mkdtemp(char *template);
1462 addToFunctionSummaryMap(
1463 "mkdtemp", Signature(ArgTypes{CharPtrTy}, RetType{CharPtrTy}),
1464 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
1465
1466 // char *getcwd(char *buf, size_t size);
1467 addToFunctionSummaryMap(
1468 "getcwd", Signature(ArgTypes{CharPtrTy, SizeTy}, RetType{CharPtrTy}),
1469 Summary(NoEvalCall)
1470 .ArgConstraint(
1471 ArgumentCondition(1, WithinRange, Range(0, SizeMax))));
1472
1473 // int mkdir(const char *pathname, mode_t mode);
1474 addToFunctionSummaryMap(
1475 "mkdir", Signature(ArgTypes{ConstCharPtrTy, Mode_tTy}, RetType{IntTy}),
1476 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
1477
1478 // int mkdirat(int dirfd, const char *pathname, mode_t mode);
1479 addToFunctionSummaryMap(
1480 "mkdirat",
1481 Signature(ArgTypes{IntTy, ConstCharPtrTy, Mode_tTy}, RetType{IntTy}),
1482 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(1))));
1483
1484 Optional<QualType> Dev_tTy = lookupTy("dev_t");
1485
1486 // int mknod(const char *pathname, mode_t mode, dev_t dev);
1487 addToFunctionSummaryMap(
1488 "mknod",
1489 Signature(ArgTypes{ConstCharPtrTy, Mode_tTy, Dev_tTy}, RetType{IntTy}),
1490 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
1491
1492 // int mknodat(int dirfd, const char *pathname, mode_t mode, dev_t dev);
1493 addToFunctionSummaryMap(
1494 "mknodat",
1495 Signature(ArgTypes{IntTy, ConstCharPtrTy, Mode_tTy, Dev_tTy},
1496 RetType{IntTy}),
1497 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(1))));
1498
1499 // int chmod(const char *path, mode_t mode);
1500 addToFunctionSummaryMap(
1501 "chmod", Signature(ArgTypes{ConstCharPtrTy, Mode_tTy}, RetType{IntTy}),
1502 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
1503
1504 // int fchmodat(int dirfd, const char *pathname, mode_t mode, int flags);
1505 addToFunctionSummaryMap(
1506 "fchmodat",
1507 Signature(ArgTypes{IntTy, ConstCharPtrTy, Mode_tTy, IntTy},
1508 RetType{IntTy}),
1509 Summary(NoEvalCall)
1510 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
1511 .ArgConstraint(NotNull(ArgNo(1))));
1512
1513 // int fchmod(int fildes, mode_t mode);
1514 addToFunctionSummaryMap(
1515 "fchmod", Signature(ArgTypes{IntTy, Mode_tTy}, RetType{IntTy}),
1516 Summary(NoEvalCall)
1517 .ArgConstraint(
1518 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
1519
1520 Optional<QualType> Uid_tTy = lookupTy("uid_t");
1521 Optional<QualType> Gid_tTy = lookupTy("gid_t");
1522
1523 // int fchownat(int dirfd, const char *pathname, uid_t owner, gid_t group,
1524 // int flags);
1525 addToFunctionSummaryMap(
1526 "fchownat",
1527 Signature(ArgTypes{IntTy, ConstCharPtrTy, Uid_tTy, Gid_tTy, IntTy},
1528 RetType{IntTy}),
1529 Summary(NoEvalCall)
1530 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
1531 .ArgConstraint(NotNull(ArgNo(1))));
1532
1533 // int chown(const char *path, uid_t owner, gid_t group);
1534 addToFunctionSummaryMap(
1535 "chown",
1536 Signature(ArgTypes{ConstCharPtrTy, Uid_tTy, Gid_tTy}, RetType{IntTy}),
1537 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
1538
1539 // int lchown(const char *path, uid_t owner, gid_t group);
1540 addToFunctionSummaryMap(
1541 "lchown",
1542 Signature(ArgTypes{ConstCharPtrTy, Uid_tTy, Gid_tTy}, RetType{IntTy}),
1543 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
1544
1545 // int fchown(int fildes, uid_t owner, gid_t group);
1546 addToFunctionSummaryMap(
1547 "fchown", Signature(ArgTypes{IntTy, Uid_tTy, Gid_tTy}, RetType{IntTy}),
1548 Summary(NoEvalCall)
1549 .ArgConstraint(
1550 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
1551
1552 // int rmdir(const char *pathname);
1553 addToFunctionSummaryMap(
1554 "rmdir", Signature(ArgTypes{ConstCharPtrTy}, RetType{IntTy}),
1555 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
1556
1557 // int chdir(const char *path);
1558 addToFunctionSummaryMap(
1559 "chdir", Signature(ArgTypes{ConstCharPtrTy}, RetType{IntTy}),
1560 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
1561
1562 // int link(const char *oldpath, const char *newpath);
1563 addToFunctionSummaryMap(
1564 "link",
1565 Signature(ArgTypes{ConstCharPtrTy, ConstCharPtrTy}, RetType{IntTy}),
1566 Summary(NoEvalCall)
1567 .ArgConstraint(NotNull(ArgNo(0)))
1568 .ArgConstraint(NotNull(ArgNo(1))));
1569
1570 // int linkat(int fd1, const char *path1, int fd2, const char *path2,
1571 // int flag);
1572 addToFunctionSummaryMap(
1573 "linkat",
1574 Signature(ArgTypes{IntTy, ConstCharPtrTy, IntTy, ConstCharPtrTy, IntTy},
1575 RetType{IntTy}),
1576 Summary(NoEvalCall)
1577 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
1578 .ArgConstraint(NotNull(ArgNo(1)))
1579 .ArgConstraint(ArgumentCondition(2, WithinRange, Range(0, IntMax)))
1580 .ArgConstraint(NotNull(ArgNo(3))));
1581
1582 // int unlink(const char *pathname);
1583 addToFunctionSummaryMap(
1584 "unlink", Signature(ArgTypes{ConstCharPtrTy}, RetType{IntTy}),
1585 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
1586
1587 // int unlinkat(int fd, const char *path, int flag);
1588 addToFunctionSummaryMap(
1589 "unlinkat",
1590 Signature(ArgTypes{IntTy, ConstCharPtrTy, IntTy}, RetType{IntTy}),
1591 Summary(NoEvalCall)
1592 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
1593 .ArgConstraint(NotNull(ArgNo(1))));
1594
1595 Optional<QualType> StructStatTy = lookupTy("stat");
1596 Optional<QualType> StructStatPtrTy = getPointerTy(StructStatTy);
1597 Optional<QualType> StructStatPtrRestrictTy = getRestrictTy(StructStatPtrTy);
1598
1599 // int fstat(int fd, struct stat *statbuf);
1600 addToFunctionSummaryMap(
1601 "fstat", Signature(ArgTypes{IntTy, StructStatPtrTy}, RetType{IntTy}),
1602 Summary(NoEvalCall)
1603 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
1604 .ArgConstraint(NotNull(ArgNo(1))));
1605
1606 // int stat(const char *restrict path, struct stat *restrict buf);
1607 addToFunctionSummaryMap(
1608 "stat",
1609 Signature(ArgTypes{ConstCharPtrRestrictTy, StructStatPtrRestrictTy},
1610 RetType{IntTy}),
1611 Summary(NoEvalCall)
1612 .ArgConstraint(NotNull(ArgNo(0)))
1613 .ArgConstraint(NotNull(ArgNo(1))));
1614
1615 // int lstat(const char *restrict path, struct stat *restrict buf);
1616 addToFunctionSummaryMap(
1617 "lstat",
1618 Signature(ArgTypes{ConstCharPtrRestrictTy, StructStatPtrRestrictTy},
1619 RetType{IntTy}),
1620 Summary(NoEvalCall)
1621 .ArgConstraint(NotNull(ArgNo(0)))
1622 .ArgConstraint(NotNull(ArgNo(1))));
1623
1624 // int fstatat(int fd, const char *restrict path,
1625 // struct stat *restrict buf, int flag);
1626 addToFunctionSummaryMap(
1627 "fstatat",
1628 Signature(ArgTypes{IntTy, ConstCharPtrRestrictTy,
1629 StructStatPtrRestrictTy, IntTy},
1630 RetType{IntTy}),
1631 Summary(NoEvalCall)
1632 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
1633 .ArgConstraint(NotNull(ArgNo(1)))
1634 .ArgConstraint(NotNull(ArgNo(2))));
1635
1636 // DIR *opendir(const char *name);
1637 addToFunctionSummaryMap(
1638 "opendir", Signature(ArgTypes{ConstCharPtrTy}, RetType{DirPtrTy}),
1639 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
1640
1641 // DIR *fdopendir(int fd);
1642 addToFunctionSummaryMap("fdopendir",
1643 Signature(ArgTypes{IntTy}, RetType{DirPtrTy}),
1644 Summary(NoEvalCall)
1645 .ArgConstraint(ArgumentCondition(
1646 0, WithinRange, Range(0, IntMax))));
1647
1648 // int isatty(int fildes);
1649 addToFunctionSummaryMap("isatty",
1650 Signature(ArgTypes{IntTy}, RetType{IntTy}),
1651 Summary(NoEvalCall)
1652 .ArgConstraint(ArgumentCondition(
1653 0, WithinRange, Range(0, IntMax))));
1654
1655 // FILE *popen(const char *command, const char *type);
1656 addToFunctionSummaryMap(
1657 "popen",
1658 Signature(ArgTypes{ConstCharPtrTy, ConstCharPtrTy}, RetType{FilePtrTy}),
1659 Summary(NoEvalCall)
1660 .ArgConstraint(NotNull(ArgNo(0)))
1661 .ArgConstraint(NotNull(ArgNo(1))));
1662
1663 // int pclose(FILE *stream);
1664 addToFunctionSummaryMap(
1665 "pclose", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
1666 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
1667
1668 // int close(int fildes);
1669 addToFunctionSummaryMap("close", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1670 Summary(NoEvalCall)
1671 .ArgConstraint(ArgumentCondition(
1672 0, WithinRange, Range(0, IntMax))));
1673
1674 // long fpathconf(int fildes, int name);
1675 addToFunctionSummaryMap("fpathconf",
1676 Signature(ArgTypes{IntTy, IntTy}, RetType{LongTy}),
1677 Summary(NoEvalCall)
1678 .ArgConstraint(ArgumentCondition(
1679 0, WithinRange, Range(0, IntMax))));
1680
1681 // long pathconf(const char *path, int name);
1682 addToFunctionSummaryMap(
1683 "pathconf", Signature(ArgTypes{ConstCharPtrTy, IntTy}, RetType{LongTy}),
1684 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
1685
1686 // FILE *fdopen(int fd, const char *mode);
1687 addToFunctionSummaryMap(
1688 "fdopen",
1689 Signature(ArgTypes{IntTy, ConstCharPtrTy}, RetType{FilePtrTy}),
1690 Summary(NoEvalCall)
1691 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
1692 .ArgConstraint(NotNull(ArgNo(1))));
1693
1694 // void rewinddir(DIR *dir);
1695 addToFunctionSummaryMap(
1696 "rewinddir", Signature(ArgTypes{DirPtrTy}, RetType{VoidTy}),
1697 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
1698
1699 // void seekdir(DIR *dirp, long loc);
1700 addToFunctionSummaryMap(
1701 "seekdir", Signature(ArgTypes{DirPtrTy, LongTy}, RetType{VoidTy}),
1702 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
1703
1704 // int rand_r(unsigned int *seedp);
1705 addToFunctionSummaryMap(
1706 "rand_r", Signature(ArgTypes{UnsignedIntPtrTy}, RetType{IntTy}),
1707 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
1708
1709 // int fileno(FILE *stream);
1710 addToFunctionSummaryMap(
1711 "fileno", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
1712 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
1713
1714 // int fseeko(FILE *stream, off_t offset, int whence);
1715 addToFunctionSummaryMap(
1716 "fseeko",
1717 Signature(ArgTypes{FilePtrTy, Off_tTy, IntTy}, RetType{IntTy}),
1718 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
1719
1720 // off_t ftello(FILE *stream);
1721 addToFunctionSummaryMap(
1722 "ftello", Signature(ArgTypes{FilePtrTy}, RetType{Off_tTy}),
1723 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
1724
1725 Optional<RangeInt> Off_tMax = getMaxValue(Off_tTy);
1726 // void *mmap(void *addr, size_t length, int prot, int flags, int fd,
1727 // off_t offset);
1728 addToFunctionSummaryMap(
1729 "mmap",
1730 Signature(ArgTypes{VoidPtrTy, SizeTy, IntTy, IntTy, IntTy, Off_tTy},
1731 RetType{VoidPtrTy}),
1732 Summary(NoEvalCall)
1733 .ArgConstraint(ArgumentCondition(1, WithinRange, Range(1, SizeMax)))
1734 .ArgConstraint(
1735 ArgumentCondition(4, WithinRange, Range(0, Off_tMax))));
1736
1737 Optional<QualType> Off64_tTy = lookupTy("off64_t");
1738 Optional<RangeInt> Off64_tMax = getMaxValue(Off_tTy);
1739 // void *mmap64(void *addr, size_t length, int prot, int flags, int fd,
1740 // off64_t offset);
1741 addToFunctionSummaryMap(
1742 "mmap64",
1743 Signature(ArgTypes{VoidPtrTy, SizeTy, IntTy, IntTy, IntTy, Off64_tTy},
1744 RetType{VoidPtrTy}),
1745 Summary(NoEvalCall)
1746 .ArgConstraint(ArgumentCondition(1, WithinRange, Range(1, SizeMax)))
1747 .ArgConstraint(
1748 ArgumentCondition(4, WithinRange, Range(0, Off64_tMax))));
1749
1750 // int pipe(int fildes[2]);
1751 addToFunctionSummaryMap(
1752 "pipe", Signature(ArgTypes{IntPtrTy}, RetType{IntTy}),
1753 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
1754
1755 // off_t lseek(int fildes, off_t offset, int whence);
1756 addToFunctionSummaryMap(
1757 "lseek", Signature(ArgTypes{IntTy, Off_tTy, IntTy}, RetType{Off_tTy}),
1758 Summary(NoEvalCall)
1759 .ArgConstraint(
1760 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
1761
1762 // ssize_t readlink(const char *restrict path, char *restrict buf,
1763 // size_t bufsize);
1764 addToFunctionSummaryMap(
1765 "readlink",
1766 Signature(ArgTypes{ConstCharPtrRestrictTy, CharPtrRestrictTy, SizeTy},
1767 RetType{Ssize_tTy}),
1768 Summary(NoEvalCall)
1769 .ArgConstraint(NotNull(ArgNo(0)))
1770 .ArgConstraint(NotNull(ArgNo(1)))
1771 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
1772 /*BufSize=*/ArgNo(2)))
1773 .ArgConstraint(
1774 ArgumentCondition(2, WithinRange, Range(0, SizeMax))));
1775
1776 // ssize_t readlinkat(int fd, const char *restrict path,
1777 // char *restrict buf, size_t bufsize);
1778 addToFunctionSummaryMap(
1779 "readlinkat",
1780 Signature(
1781 ArgTypes{IntTy, ConstCharPtrRestrictTy, CharPtrRestrictTy, SizeTy},
1782 RetType{Ssize_tTy}),
1783 Summary(NoEvalCall)
1784 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
1785 .ArgConstraint(NotNull(ArgNo(1)))
1786 .ArgConstraint(NotNull(ArgNo(2)))
1787 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(2),
1788 /*BufSize=*/ArgNo(3)))
1789 .ArgConstraint(
1790 ArgumentCondition(3, WithinRange, Range(0, SizeMax))));
1791
1792 // int renameat(int olddirfd, const char *oldpath, int newdirfd, const char
1793 // *newpath);
1794 addToFunctionSummaryMap(
1795 "renameat",
1796 Signature(ArgTypes{IntTy, ConstCharPtrTy, IntTy, ConstCharPtrTy},
1797 RetType{IntTy}),
1798 Summary(NoEvalCall)
1799 .ArgConstraint(NotNull(ArgNo(1)))
1800 .ArgConstraint(NotNull(ArgNo(3))));
1801
1802 // char *realpath(const char *restrict file_name,
1803 // char *restrict resolved_name);
1804 addToFunctionSummaryMap(
1805 "realpath",
1806 Signature(ArgTypes{ConstCharPtrRestrictTy, CharPtrRestrictTy},
1807 RetType{CharPtrTy}),
1808 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
1809
1810 QualType CharPtrConstPtr = getPointerTy(getConstTy(CharPtrTy));
1811
1812 // int execv(const char *path, char *const argv[]);
1813 addToFunctionSummaryMap(
1814 "execv",
1815 Signature(ArgTypes{ConstCharPtrTy, CharPtrConstPtr}, RetType{IntTy}),
1816 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
1817
1818 // int execvp(const char *file, char *const argv[]);
1819 addToFunctionSummaryMap(
1820 "execvp",
1821 Signature(ArgTypes{ConstCharPtrTy, CharPtrConstPtr}, RetType{IntTy}),
1822 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
1823
1824 // int getopt(int argc, char * const argv[], const char *optstring);
1825 addToFunctionSummaryMap(
1826 "getopt",
1827 Signature(ArgTypes{IntTy, CharPtrConstPtr, ConstCharPtrTy},
1828 RetType{IntTy}),
1829 Summary(NoEvalCall)
1830 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
1831 .ArgConstraint(NotNull(ArgNo(1)))
1832 .ArgConstraint(NotNull(ArgNo(2))));
1833
1834 Optional<QualType> StructSockaddrTy = lookupTy("sockaddr");
1835 Optional<QualType> StructSockaddrPtrTy = getPointerTy(StructSockaddrTy);
1836 Optional<QualType> ConstStructSockaddrPtrTy =
1837 getPointerTy(getConstTy(StructSockaddrTy));
1838 Optional<QualType> StructSockaddrPtrRestrictTy =
1839 getRestrictTy(StructSockaddrPtrTy);
1840 Optional<QualType> ConstStructSockaddrPtrRestrictTy =
1841 getRestrictTy(ConstStructSockaddrPtrTy);
1842 Optional<QualType> Socklen_tTy = lookupTy("socklen_t");
1843 Optional<QualType> Socklen_tPtrTy = getPointerTy(Socklen_tTy);
1844 Optional<QualType> Socklen_tPtrRestrictTy = getRestrictTy(Socklen_tPtrTy);
1845 Optional<RangeInt> Socklen_tMax = getMaxValue(Socklen_tTy);
1846
1847 // In 'socket.h' of some libc implementations with C99, sockaddr parameter
1848 // is a transparent union of the underlying sockaddr_ family of pointers
1849 // instead of being a pointer to struct sockaddr. In these cases, the
1850 // standardized signature will not match, thus we try to match with another
1851 // signature that has the joker Irrelevant type. We also remove those
1852 // constraints which require pointer types for the sockaddr param.
1853 auto Accept =
1854 Summary(NoEvalCall)
1855 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)));
1856 if (!addToFunctionSummaryMap(
1857 "accept",
1858 // int accept(int socket, struct sockaddr *restrict address,
1859 // socklen_t *restrict address_len);
1860 Signature(ArgTypes{IntTy, StructSockaddrPtrRestrictTy,
1861 Socklen_tPtrRestrictTy},
1862 RetType{IntTy}),
1863 Accept))
1864 addToFunctionSummaryMap(
1865 "accept",
1866 Signature(ArgTypes{IntTy, Irrelevant, Socklen_tPtrRestrictTy},
1867 RetType{IntTy}),
1868 Accept);
1869
1870 // int bind(int socket, const struct sockaddr *address, socklen_t
1871 // address_len);
1872 if (!addToFunctionSummaryMap(
1873 "bind",
1874 Signature(ArgTypes{IntTy, ConstStructSockaddrPtrTy, Socklen_tTy},
1875 RetType{IntTy}),
1876 Summary(NoEvalCall)
1877 .ArgConstraint(
1878 ArgumentCondition(0, WithinRange, Range(0, IntMax)))
1879 .ArgConstraint(NotNull(ArgNo(1)))
1880 .ArgConstraint(
1881 BufferSize(/*Buffer=*/ArgNo(1), /*BufSize=*/ArgNo(2)))
1882 .ArgConstraint(
1883 ArgumentCondition(2, WithinRange, Range(0, Socklen_tMax)))))
1884 // Do not add constraints on sockaddr.
1885 addToFunctionSummaryMap(
1886 "bind",
1887 Signature(ArgTypes{IntTy, Irrelevant, Socklen_tTy}, RetType{IntTy}),
1888 Summary(NoEvalCall)
1889 .ArgConstraint(
1890 ArgumentCondition(0, WithinRange, Range(0, IntMax)))
1891 .ArgConstraint(
1892 ArgumentCondition(2, WithinRange, Range(0, Socklen_tMax))));
1893
1894 // int getpeername(int socket, struct sockaddr *restrict address,
1895 // socklen_t *restrict address_len);
1896 if (!addToFunctionSummaryMap(
1897 "getpeername",
1898 Signature(ArgTypes{IntTy, StructSockaddrPtrRestrictTy,
1899 Socklen_tPtrRestrictTy},
1900 RetType{IntTy}),
1901 Summary(NoEvalCall)
1902 .ArgConstraint(
1903 ArgumentCondition(0, WithinRange, Range(0, IntMax)))
1904 .ArgConstraint(NotNull(ArgNo(1)))
1905 .ArgConstraint(NotNull(ArgNo(2)))))
1906 addToFunctionSummaryMap(
1907 "getpeername",
1908 Signature(ArgTypes{IntTy, Irrelevant, Socklen_tPtrRestrictTy},
1909 RetType{IntTy}),
1910 Summary(NoEvalCall)
1911 .ArgConstraint(
1912 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
1913
1914 // int getsockname(int socket, struct sockaddr *restrict address,
1915 // socklen_t *restrict address_len);
1916 if (!addToFunctionSummaryMap(
1917 "getsockname",
1918 Signature(ArgTypes{IntTy, StructSockaddrPtrRestrictTy,
1919 Socklen_tPtrRestrictTy},
1920 RetType{IntTy}),
1921 Summary(NoEvalCall)
1922 .ArgConstraint(
1923 ArgumentCondition(0, WithinRange, Range(0, IntMax)))
1924 .ArgConstraint(NotNull(ArgNo(1)))
1925 .ArgConstraint(NotNull(ArgNo(2)))))
1926 addToFunctionSummaryMap(
1927 "getsockname",
1928 Signature(ArgTypes{IntTy, Irrelevant, Socklen_tPtrRestrictTy},
1929 RetType{IntTy}),
1930 Summary(NoEvalCall)
1931 .ArgConstraint(
1932 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
1933
1934 // int connect(int socket, const struct sockaddr *address, socklen_t
1935 // address_len);
1936 if (!addToFunctionSummaryMap(
1937 "connect",
1938 Signature(ArgTypes{IntTy, ConstStructSockaddrPtrTy, Socklen_tTy},
1939 RetType{IntTy}),
1940 Summary(NoEvalCall)
1941 .ArgConstraint(
1942 ArgumentCondition(0, WithinRange, Range(0, IntMax)))
1943 .ArgConstraint(NotNull(ArgNo(1)))))
1944 addToFunctionSummaryMap(
1945 "connect",
1946 Signature(ArgTypes{IntTy, Irrelevant, Socklen_tTy}, RetType{IntTy}),
1947 Summary(NoEvalCall)
1948 .ArgConstraint(
1949 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
1950
1951 auto Recvfrom =
1952 Summary(NoEvalCall)
1953 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
1954 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
1955 /*BufSize=*/ArgNo(2)));
1956 if (!addToFunctionSummaryMap(
1957 "recvfrom",
1958 // ssize_t recvfrom(int socket, void *restrict buffer,
1959 // size_t length,
1960 // int flags, struct sockaddr *restrict address,
1961 // socklen_t *restrict address_len);
1962 Signature(ArgTypes{IntTy, VoidPtrRestrictTy, SizeTy, IntTy,
1963 StructSockaddrPtrRestrictTy,
1964 Socklen_tPtrRestrictTy},
1965 RetType{Ssize_tTy}),
1966 Recvfrom))
1967 addToFunctionSummaryMap(
1968 "recvfrom",
1969 Signature(ArgTypes{IntTy, VoidPtrRestrictTy, SizeTy, IntTy,
1970 Irrelevant, Socklen_tPtrRestrictTy},
1971 RetType{Ssize_tTy}),
1972 Recvfrom);
1973
1974 auto Sendto =
1975 Summary(NoEvalCall)
1976 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
1977 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
1978 /*BufSize=*/ArgNo(2)));
1979 if (!addToFunctionSummaryMap(
1980 "sendto",
1981 // ssize_t sendto(int socket, const void *message, size_t length,
1982 // int flags, const struct sockaddr *dest_addr,
1983 // socklen_t dest_len);
1984 Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTy, IntTy,
1985 ConstStructSockaddrPtrTy, Socklen_tTy},
1986 RetType{Ssize_tTy}),
1987 Sendto))
1988 addToFunctionSummaryMap(
1989 "sendto",
1990 Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTy, IntTy, Irrelevant,
1991 Socklen_tTy},
1992 RetType{Ssize_tTy}),
1993 Sendto);
1994
1995 // int listen(int sockfd, int backlog);
1996 addToFunctionSummaryMap("listen",
1997 Signature(ArgTypes{IntTy, IntTy}, RetType{IntTy}),
1998 Summary(NoEvalCall)
1999 .ArgConstraint(ArgumentCondition(
2000 0, WithinRange, Range(0, IntMax))));
2001
2002 // ssize_t recv(int sockfd, void *buf, size_t len, int flags);
2003 addToFunctionSummaryMap(
2004 "recv",
2005 Signature(ArgTypes{IntTy, VoidPtrTy, SizeTy, IntTy},
2006 RetType{Ssize_tTy}),
2007 Summary(NoEvalCall)
2008 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
2009 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
2010 /*BufSize=*/ArgNo(2))));
2011
2012 Optional<QualType> StructMsghdrTy = lookupTy("msghdr");
2013 Optional<QualType> StructMsghdrPtrTy = getPointerTy(StructMsghdrTy);
2014 Optional<QualType> ConstStructMsghdrPtrTy =
2015 getPointerTy(getConstTy(StructMsghdrTy));
2016
2017 // ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);
2018 addToFunctionSummaryMap("recvmsg",
2019 Signature(ArgTypes{IntTy, StructMsghdrPtrTy, IntTy},
2020 RetType{Ssize_tTy}),
2021 Summary(NoEvalCall)
2022 .ArgConstraint(ArgumentCondition(
2023 0, WithinRange, Range(0, IntMax))));
2024
2025 // ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
2026 addToFunctionSummaryMap(
2027 "sendmsg",
2028 Signature(ArgTypes{IntTy, ConstStructMsghdrPtrTy, IntTy},
2029 RetType{Ssize_tTy}),
2030 Summary(NoEvalCall)
2031 .ArgConstraint(
2032 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
2033
2034 // int setsockopt(int socket, int level, int option_name,
2035 // const void *option_value, socklen_t option_len);
2036 addToFunctionSummaryMap(
2037 "setsockopt",
2038 Signature(ArgTypes{IntTy, IntTy, IntTy, ConstVoidPtrTy, Socklen_tTy},
2039 RetType{IntTy}),
2040 Summary(NoEvalCall)
2041 .ArgConstraint(NotNull(ArgNo(3)))
2042 .ArgConstraint(
2043 BufferSize(/*Buffer=*/ArgNo(3), /*BufSize=*/ArgNo(4)))
2044 .ArgConstraint(
2045 ArgumentCondition(4, WithinRange, Range(0, Socklen_tMax))));
2046
2047 // int getsockopt(int socket, int level, int option_name,
2048 // void *restrict option_value,
2049 // socklen_t *restrict option_len);
2050 addToFunctionSummaryMap(
2051 "getsockopt",
2052 Signature(ArgTypes{IntTy, IntTy, IntTy, VoidPtrRestrictTy,
2053 Socklen_tPtrRestrictTy},
2054 RetType{IntTy}),
2055 Summary(NoEvalCall)
2056 .ArgConstraint(NotNull(ArgNo(3)))
2057 .ArgConstraint(NotNull(ArgNo(4))));
2058
2059 // ssize_t send(int sockfd, const void *buf, size_t len, int flags);
2060 addToFunctionSummaryMap(
2061 "send",
2062 Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTy, IntTy},
2063 RetType{Ssize_tTy}),
2064 Summary(NoEvalCall)
2065 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
2066 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
2067 /*BufSize=*/ArgNo(2))));
2068
2069 // int socketpair(int domain, int type, int protocol, int sv[2]);
2070 addToFunctionSummaryMap(
2071 "socketpair",
2072 Signature(ArgTypes{IntTy, IntTy, IntTy, IntPtrTy}, RetType{IntTy}),
2073 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(3))));
2074
2075 // int getnameinfo(const struct sockaddr *restrict sa, socklen_t salen,
2076 // char *restrict node, socklen_t nodelen,
2077 // char *restrict service,
2078 // socklen_t servicelen, int flags);
2079 //
2080 // This is defined in netdb.h. And contrary to 'socket.h', the sockaddr
2081 // parameter is never handled as a transparent union in netdb.h
2082 addToFunctionSummaryMap(
2083 "getnameinfo",
2084 Signature(ArgTypes{ConstStructSockaddrPtrRestrictTy, Socklen_tTy,
2085 CharPtrRestrictTy, Socklen_tTy, CharPtrRestrictTy,
2086 Socklen_tTy, IntTy},
2087 RetType{IntTy}),
2088 Summary(NoEvalCall)
2089 .ArgConstraint(
2090 BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1)))
2091 .ArgConstraint(
2092 ArgumentCondition(1, WithinRange, Range(0, Socklen_tMax)))
2093 .ArgConstraint(
2094 BufferSize(/*Buffer=*/ArgNo(2), /*BufSize=*/ArgNo(3)))
2095 .ArgConstraint(
2096 ArgumentCondition(3, WithinRange, Range(0, Socklen_tMax)))
2097 .ArgConstraint(
2098 BufferSize(/*Buffer=*/ArgNo(4), /*BufSize=*/ArgNo(5)))
2099 .ArgConstraint(
2100 ArgumentCondition(5, WithinRange, Range(0, Socklen_tMax))));
2101
2102 Optional<QualType> StructUtimbufTy = lookupTy("utimbuf");
2103 Optional<QualType> StructUtimbufPtrTy = getPointerTy(StructUtimbufTy);
2104
2105 // int utime(const char *filename, struct utimbuf *buf);
2106 addToFunctionSummaryMap(
2107 "utime",
2108 Signature(ArgTypes{ConstCharPtrTy, StructUtimbufPtrTy}, RetType{IntTy}),
2109 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2110
2111 Optional<QualType> StructTimespecTy = lookupTy("timespec");
2112 Optional<QualType> StructTimespecPtrTy = getPointerTy(StructTimespecTy);
2113 Optional<QualType> ConstStructTimespecPtrTy =
2114 getPointerTy(getConstTy(StructTimespecTy));
2115
2116 // int futimens(int fd, const struct timespec times[2]);
2117 addToFunctionSummaryMap(
2118 "futimens",
2119 Signature(ArgTypes{IntTy, ConstStructTimespecPtrTy}, RetType{IntTy}),
2120 Summary(NoEvalCall)
2121 .ArgConstraint(
2122 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
2123
2124 // int utimensat(int dirfd, const char *pathname,
2125 // const struct timespec times[2], int flags);
2126 addToFunctionSummaryMap(
2127 "utimensat",
2128 Signature(
2129 ArgTypes{IntTy, ConstCharPtrTy, ConstStructTimespecPtrTy, IntTy},
2130 RetType{IntTy}),
2131 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(1))));
2132
2133 Optional<QualType> StructTimevalTy = lookupTy("timeval");
2134 Optional<QualType> ConstStructTimevalPtrTy =
2135 getPointerTy(getConstTy(StructTimevalTy));
2136
2137 // int utimes(const char *filename, const struct timeval times[2]);
2138 addToFunctionSummaryMap(
2139 "utimes",
2140 Signature(ArgTypes{ConstCharPtrTy, ConstStructTimevalPtrTy},
2141 RetType{IntTy}),
2142 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2143
2144 // int nanosleep(const struct timespec *rqtp, struct timespec *rmtp);
2145 addToFunctionSummaryMap(
2146 "nanosleep",
2147 Signature(ArgTypes{ConstStructTimespecPtrTy, StructTimespecPtrTy},
2148 RetType{IntTy}),
2149 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2150
2151 Optional<QualType> Time_tTy = lookupTy("time_t");
2152 Optional<QualType> ConstTime_tPtrTy = getPointerTy(getConstTy(Time_tTy));
2153 Optional<QualType> ConstTime_tPtrRestrictTy =
2154 getRestrictTy(ConstTime_tPtrTy);
2155
2156 Optional<QualType> StructTmTy = lookupTy("tm");
2157 Optional<QualType> StructTmPtrTy = getPointerTy(StructTmTy);
2158 Optional<QualType> StructTmPtrRestrictTy = getRestrictTy(StructTmPtrTy);
2159 Optional<QualType> ConstStructTmPtrTy =
2160 getPointerTy(getConstTy(StructTmTy));
2161 Optional<QualType> ConstStructTmPtrRestrictTy =
2162 getRestrictTy(ConstStructTmPtrTy);
2163
2164 // struct tm * localtime(const time_t *tp);
2165 addToFunctionSummaryMap(
2166 "localtime",
2167 Signature(ArgTypes{ConstTime_tPtrTy}, RetType{StructTmPtrTy}),
2168 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2169
2170 // struct tm *localtime_r(const time_t *restrict timer,
2171 // struct tm *restrict result);
2172 addToFunctionSummaryMap(
2173 "localtime_r",
2174 Signature(ArgTypes{ConstTime_tPtrRestrictTy, StructTmPtrRestrictTy},
2175 RetType{StructTmPtrTy}),
2176 Summary(NoEvalCall)
2177 .ArgConstraint(NotNull(ArgNo(0)))
2178 .ArgConstraint(NotNull(ArgNo(1))));
2179
2180 // char *asctime_r(const struct tm *restrict tm, char *restrict buf);
2181 addToFunctionSummaryMap(
2182 "asctime_r",
2183 Signature(ArgTypes{ConstStructTmPtrRestrictTy, CharPtrRestrictTy},
2184 RetType{CharPtrTy}),
2185 Summary(NoEvalCall)
2186 .ArgConstraint(NotNull(ArgNo(0)))
2187 .ArgConstraint(NotNull(ArgNo(1)))
2188 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
2189 /*MinBufSize=*/BVF.getValue(26, IntTy))));
2190
2191 // char *ctime_r(const time_t *timep, char *buf);
2192 addToFunctionSummaryMap(
2193 "ctime_r",
2194 Signature(ArgTypes{ConstTime_tPtrTy, CharPtrTy}, RetType{CharPtrTy}),
2195 Summary(NoEvalCall)
2196 .ArgConstraint(NotNull(ArgNo(0)))
2197 .ArgConstraint(NotNull(ArgNo(1)))
2198 .ArgConstraint(BufferSize(
2199 /*Buffer=*/ArgNo(1),
2200 /*MinBufSize=*/BVF.getValue(26, IntTy))));
2201
2202 // struct tm *gmtime_r(const time_t *restrict timer,
2203 // struct tm *restrict result);
2204 addToFunctionSummaryMap(
2205 "gmtime_r",
2206 Signature(ArgTypes{ConstTime_tPtrRestrictTy, StructTmPtrRestrictTy},
2207 RetType{StructTmPtrTy}),
2208 Summary(NoEvalCall)
2209 .ArgConstraint(NotNull(ArgNo(0)))
2210 .ArgConstraint(NotNull(ArgNo(1))));
2211
2212 // struct tm * gmtime(const time_t *tp);
2213 addToFunctionSummaryMap(
2214 "gmtime", Signature(ArgTypes{ConstTime_tPtrTy}, RetType{StructTmPtrTy}),
2215 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2216
2217 Optional<QualType> Clockid_tTy = lookupTy("clockid_t");
2218
2219 // int clock_gettime(clockid_t clock_id, struct timespec *tp);
2220 addToFunctionSummaryMap(
2221 "clock_gettime",
2222 Signature(ArgTypes{Clockid_tTy, StructTimespecPtrTy}, RetType{IntTy}),
2223 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(1))));
2224
2225 Optional<QualType> StructItimervalTy = lookupTy("itimerval");
2226 Optional<QualType> StructItimervalPtrTy = getPointerTy(StructItimervalTy);
2227
2228 // int getitimer(int which, struct itimerval *curr_value);
2229 addToFunctionSummaryMap(
2230 "getitimer",
2231 Signature(ArgTypes{IntTy, StructItimervalPtrTy}, RetType{IntTy}),
2232 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(1))));
2233
2234 Optional<QualType> Pthread_cond_tTy = lookupTy("pthread_cond_t");
2235 Optional<QualType> Pthread_cond_tPtrTy = getPointerTy(Pthread_cond_tTy);
2236 Optional<QualType> Pthread_tTy = lookupTy("pthread_t");
2237 Optional<QualType> Pthread_tPtrTy = getPointerTy(Pthread_tTy);
2238 Optional<QualType> Pthread_tPtrRestrictTy = getRestrictTy(Pthread_tPtrTy);
2239 Optional<QualType> Pthread_mutex_tTy = lookupTy("pthread_mutex_t");
2240 Optional<QualType> Pthread_mutex_tPtrTy = getPointerTy(Pthread_mutex_tTy);
2241 Optional<QualType> Pthread_mutex_tPtrRestrictTy =
2242 getRestrictTy(Pthread_mutex_tPtrTy);
2243 Optional<QualType> Pthread_attr_tTy = lookupTy("pthread_attr_t");
2244 Optional<QualType> Pthread_attr_tPtrTy = getPointerTy(Pthread_attr_tTy);
2245 Optional<QualType> ConstPthread_attr_tPtrTy =
2246 getPointerTy(getConstTy(Pthread_attr_tTy));
2247 Optional<QualType> ConstPthread_attr_tPtrRestrictTy =
2248 getRestrictTy(ConstPthread_attr_tPtrTy);
2249 Optional<QualType> Pthread_mutexattr_tTy = lookupTy("pthread_mutexattr_t");
2250 Optional<QualType> ConstPthread_mutexattr_tPtrTy =
2251 getPointerTy(getConstTy(Pthread_mutexattr_tTy));
2252 Optional<QualType> ConstPthread_mutexattr_tPtrRestrictTy =
2253 getRestrictTy(ConstPthread_mutexattr_tPtrTy);
2254
2255 QualType PthreadStartRoutineTy = getPointerTy(
2256 ACtx.getFunctionType(/*ResultTy=*/VoidPtrTy, /*Args=*/VoidPtrTy,
2257 FunctionProtoType::ExtProtoInfo()));
2258
2259 // int pthread_cond_signal(pthread_cond_t *cond);
2260 // int pthread_cond_broadcast(pthread_cond_t *cond);
2261 addToFunctionSummaryMap(
2262 {"pthread_cond_signal", "pthread_cond_broadcast"},
2263 Signature(ArgTypes{Pthread_cond_tPtrTy}, RetType{IntTy}),
2264 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2265
2266 // int pthread_create(pthread_t *restrict thread,
2267 // const pthread_attr_t *restrict attr,
2268 // void *(*start_routine)(void*), void *restrict arg);
2269 addToFunctionSummaryMap(
2270 "pthread_create",
2271 Signature(ArgTypes{Pthread_tPtrRestrictTy,
2272 ConstPthread_attr_tPtrRestrictTy,
2273 PthreadStartRoutineTy, VoidPtrRestrictTy},
2274 RetType{IntTy}),
2275 Summary(NoEvalCall)
2276 .ArgConstraint(NotNull(ArgNo(0)))
2277 .ArgConstraint(NotNull(ArgNo(2))));
2278
2279 // int pthread_attr_destroy(pthread_attr_t *attr);
2280 // int pthread_attr_init(pthread_attr_t *attr);
2281 addToFunctionSummaryMap(
2282 {"pthread_attr_destroy", "pthread_attr_init"},
2283 Signature(ArgTypes{Pthread_attr_tPtrTy}, RetType{IntTy}),
2284 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2285
2286 // int pthread_attr_getstacksize(const pthread_attr_t *restrict attr,
2287 // size_t *restrict stacksize);
2288 // int pthread_attr_getguardsize(const pthread_attr_t *restrict attr,
2289 // size_t *restrict guardsize);
2290 addToFunctionSummaryMap(
2291 {"pthread_attr_getstacksize", "pthread_attr_getguardsize"},
2292 Signature(ArgTypes{ConstPthread_attr_tPtrRestrictTy, SizePtrRestrictTy},
2293 RetType{IntTy}),
2294 Summary(NoEvalCall)
2295 .ArgConstraint(NotNull(ArgNo(0)))
2296 .ArgConstraint(NotNull(ArgNo(1))));
2297
2298 // int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize);
2299 // int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize);
2300 addToFunctionSummaryMap(
2301 {"pthread_attr_setstacksize", "pthread_attr_setguardsize"},
2302 Signature(ArgTypes{Pthread_attr_tPtrTy, SizeTy}, RetType{IntTy}),
2303 Summary(NoEvalCall)
2304 .ArgConstraint(NotNull(ArgNo(0)))
2305 .ArgConstraint(
2306 ArgumentCondition(1, WithinRange, Range(0, SizeMax))));
2307
2308 // int pthread_mutex_init(pthread_mutex_t *restrict mutex, const
2309 // pthread_mutexattr_t *restrict attr);
2310 addToFunctionSummaryMap(
2311 "pthread_mutex_init",
2312 Signature(ArgTypes{Pthread_mutex_tPtrRestrictTy,
2313 ConstPthread_mutexattr_tPtrRestrictTy},
2314 RetType{IntTy}),
2315 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2316
2317 // int pthread_mutex_destroy(pthread_mutex_t *mutex);
2318 // int pthread_mutex_lock(pthread_mutex_t *mutex);
2319 // int pthread_mutex_trylock(pthread_mutex_t *mutex);
2320 // int pthread_mutex_unlock(pthread_mutex_t *mutex);
2321 addToFunctionSummaryMap(
2322 {"pthread_mutex_destroy", "pthread_mutex_lock", "pthread_mutex_trylock",
2323 "pthread_mutex_unlock"},
2324 Signature(ArgTypes{Pthread_mutex_tPtrTy}, RetType{IntTy}),
2325 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2326 }
2327
2328 // Functions for testing.
2329 if (ChecksEnabled[CK_StdCLibraryFunctionsTesterChecker]) {
2330 addToFunctionSummaryMap(
2331 "__two_constrained_args",
2332 Signature(ArgTypes{IntTy, IntTy}, RetType{IntTy}),
2333 Summary(EvalCallAsPure)
2334 .ArgConstraint(ArgumentCondition(0U, WithinRange, SingleValue(1)))
2335 .ArgConstraint(ArgumentCondition(1U, WithinRange, SingleValue(1))));
2336 addToFunctionSummaryMap(
2337 "__arg_constrained_twice", Signature(ArgTypes{IntTy}, RetType{IntTy}),
2338 Summary(EvalCallAsPure)
2339 .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(1)))
2340 .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(2))));
2341 addToFunctionSummaryMap(
2342 "__defaultparam",
2343 Signature(ArgTypes{Irrelevant, IntTy}, RetType{IntTy}),
2344 Summary(EvalCallAsPure).ArgConstraint(NotNull(ArgNo(0))));
2345 addToFunctionSummaryMap(
2346 "__variadic",
2347 Signature(ArgTypes{VoidPtrTy, ConstCharPtrTy}, RetType{IntTy}),
2348 Summary(EvalCallAsPure)
2349 .ArgConstraint(NotNull(ArgNo(0)))
2350 .ArgConstraint(NotNull(ArgNo(1))));
2351 addToFunctionSummaryMap(
2352 "__buf_size_arg_constraint",
2353 Signature(ArgTypes{ConstVoidPtrTy, SizeTy}, RetType{IntTy}),
2354 Summary(EvalCallAsPure)
2355 .ArgConstraint(
2356 BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1))));
2357 addToFunctionSummaryMap(
2358 "__buf_size_arg_constraint_mul",
2359 Signature(ArgTypes{ConstVoidPtrTy, SizeTy, SizeTy}, RetType{IntTy}),
2360 Summary(EvalCallAsPure)
2361 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1),
2362 /*BufSizeMultiplier=*/ArgNo(2))));
2363 addToFunctionSummaryMap(
2364 "__buf_size_arg_constraint_concrete",
2365 Signature(ArgTypes{ConstVoidPtrTy}, RetType{IntTy}),
2366 Summary(EvalCallAsPure)
2367 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(0),
2368 /*BufSize=*/BVF.getValue(10, IntTy))));
2369 addToFunctionSummaryMap(
2370 {"__test_restrict_param_0", "__test_restrict_param_1",
2371 "__test_restrict_param_2"},
2372 Signature(ArgTypes{VoidPtrRestrictTy}, RetType{VoidTy}),
2373 Summary(EvalCallAsPure));
2374 }
2375}
2376
2377void ento::registerStdCLibraryFunctionsChecker(CheckerManager &mgr) {
2378 auto *Checker = mgr.registerChecker<StdLibraryFunctionsChecker>();
2379 Checker->DisplayLoadedSummaries =
2380 mgr.getAnalyzerOptions().getCheckerBooleanOption(
2381 Checker, "DisplayLoadedSummaries");
2382 Checker->ModelPOSIX =
2383 mgr.getAnalyzerOptions().getCheckerBooleanOption(Checker, "ModelPOSIX");
2384}
2385
2386bool ento::shouldRegisterStdCLibraryFunctionsChecker(
2387 const CheckerManager &mgr) {
2388 return true;
2389}
2390
2391#define REGISTER_CHECKER(name)void ento::registername(CheckerManager &mgr) { StdLibraryFunctionsChecker
*checker = mgr.getChecker<StdLibraryFunctionsChecker>(
); checker->ChecksEnabled[StdLibraryFunctionsChecker::CK_name
] = true; checker->CheckNames[StdLibraryFunctionsChecker::
CK_name] = mgr.getCurrentCheckerName(); } bool ento::shouldRegistername
(const CheckerManager &mgr) { return true; }
\
2392 void ento::register##name(CheckerManager &mgr) { \
2393 StdLibraryFunctionsChecker *checker = \
2394 mgr.getChecker<StdLibraryFunctionsChecker>(); \
2395 checker->ChecksEnabled[StdLibraryFunctionsChecker::CK_##name] = true; \
2396 checker->CheckNames[StdLibraryFunctionsChecker::CK_##name] = \
2397 mgr.getCurrentCheckerName(); \
2398 } \
2399 \
2400 bool ento::shouldRegister##name(const CheckerManager &mgr) { return true; }
2401
2402REGISTER_CHECKER(StdCLibraryFunctionArgsChecker)void ento::registerStdCLibraryFunctionArgsChecker(CheckerManager
&mgr) { StdLibraryFunctionsChecker *checker = mgr.getChecker
<StdLibraryFunctionsChecker>(); checker->ChecksEnabled
[StdLibraryFunctionsChecker::CK_StdCLibraryFunctionArgsChecker
] = true; checker->CheckNames[StdLibraryFunctionsChecker::
CK_StdCLibraryFunctionArgsChecker] = mgr.getCurrentCheckerName
(); } bool ento::shouldRegisterStdCLibraryFunctionArgsChecker
(const CheckerManager &mgr) { return true; }
2403REGISTER_CHECKER(StdCLibraryFunctionsTesterChecker)void ento::registerStdCLibraryFunctionsTesterChecker(CheckerManager
&mgr) { StdLibraryFunctionsChecker *checker = mgr.getChecker
<StdLibraryFunctionsChecker>(); checker->ChecksEnabled
[StdLibraryFunctionsChecker::CK_StdCLibraryFunctionsTesterChecker
] = true; checker->CheckNames[StdLibraryFunctionsChecker::
CK_StdCLibraryFunctionsTesterChecker] = mgr.getCurrentCheckerName
(); } bool ento::shouldRegisterStdCLibraryFunctionsTesterChecker
(const CheckerManager &mgr) { return true; }

/build/llvm-toolchain-snapshot-12~++20200926111128+c6c5629f2fb/llvm/include/llvm/ADT/Optional.h

1//===- Optional.h - Simple variant for passing optional values --*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file provides Optional, a template class modeled in the spirit of
10// OCaml's 'opt' variant. The idea is to strongly type whether or not
11// a value can be optional.
12//
13//===----------------------------------------------------------------------===//
14
15#ifndef LLVM_ADT_OPTIONAL_H
16#define LLVM_ADT_OPTIONAL_H
17
18#include "llvm/ADT/None.h"
19#include "llvm/Support/Compiler.h"
20#include "llvm/Support/type_traits.h"
21#include <cassert>
22#include <memory>
23#include <new>
24#include <utility>
25
26namespace llvm {
27
28class raw_ostream;
29
30namespace optional_detail {
31
32struct in_place_t {};
33
34/// Storage for any type.
35template <typename T, bool = is_trivially_copyable<T>::value>
36class OptionalStorage {
37 union {
38 char empty;
39 T value;
40 };
41 bool hasVal;
42
43public:
44 ~OptionalStorage() { reset(); }
45
46 constexpr OptionalStorage() noexcept : empty(), hasVal(false) {}
47
48 constexpr OptionalStorage(OptionalStorage const &other) : OptionalStorage() {
49 if (other.hasValue()) {
50 emplace(other.value);
51 }
52 }
53 constexpr OptionalStorage(OptionalStorage &&other) : OptionalStorage() {
54 if (other.hasValue()) {
55 emplace(std::move(other.value));
56 }
57 }
58
59 template <class... Args>
60 constexpr explicit OptionalStorage(in_place_t, Args &&... args)
61 : value(std::forward<Args>(args)...), hasVal(true) {}
62
63 void reset() noexcept {
64 if (hasVal) {
65 value.~T();
66 hasVal = false;
67 }
68 }
69
70 constexpr bool hasValue() const noexcept { return hasVal; }
4
Returning the value 1, which participates in a condition later
71
72 T &getValue() LLVM_LVALUE_FUNCTION& noexcept {
73 assert(hasVal)((hasVal) ? static_cast<void> (0) : __assert_fail ("hasVal"
, "/build/llvm-toolchain-snapshot-12~++20200926111128+c6c5629f2fb/llvm/include/llvm/ADT/Optional.h"
, 73, __PRETTY_FUNCTION__))
;
74 return value;
75 }
76 constexpr T const &getValue() const LLVM_LVALUE_FUNCTION& noexcept {
77 assert(hasVal)((hasVal) ? static_cast<void> (0) : __assert_fail ("hasVal"
, "/build/llvm-toolchain-snapshot-12~++20200926111128+c6c5629f2fb/llvm/include/llvm/ADT/Optional.h"
, 77, __PRETTY_FUNCTION__))
;
78 return value;
79 }
80#if LLVM_HAS_RVALUE_REFERENCE_THIS1
81 T &&getValue() && noexcept {
82 assert(hasVal)((hasVal) ? static_cast<void> (0) : __assert_fail ("hasVal"
, "/build/llvm-toolchain-snapshot-12~++20200926111128+c6c5629f2fb/llvm/include/llvm/ADT/Optional.h"
, 82, __PRETTY_FUNCTION__))
;
83 return std::move(value);
84 }
85#endif
86
87 template <class... Args> void emplace(Args &&... args) {
88 reset();
89 ::new ((void *)std::addressof(value)) T(std::forward<Args>(args)...);
90 hasVal = true;
91 }
92
93 OptionalStorage &operator=(T const &y) {
94 if (hasValue()) {
95 value = y;
96 } else {
97 ::new ((void *)std::addressof(value)) T(y);
98 hasVal = true;
99 }
100 return *this;
101 }
102 OptionalStorage &operator=(T &&y) {
103 if (hasValue()) {
104 value = std::move(y);
105 } else {
106 ::new ((void *)std::addressof(value)) T(std::move(y));
107 hasVal = true;
108 }
109 return *this;
110 }
111
112 OptionalStorage &operator=(OptionalStorage const &other) {
113 if (other.hasValue()) {
114 if (hasValue()) {
115 value = other.value;
116 } else {
117 ::new ((void *)std::addressof(value)) T(other.value);
118 hasVal = true;
119 }
120 } else {
121 reset();
122 }
123 return *this;
124 }
125
126 OptionalStorage &operator=(OptionalStorage &&other) {
127 if (other.hasValue()) {
128 if (hasValue()) {
129 value = std::move(other.value);
130 } else {
131 ::new ((void *)std::addressof(value)) T(std::move(other.value));
132 hasVal = true;
133 }
134 } else {
135 reset();
136 }
137 return *this;
138 }
139};
140
141template <typename T> class OptionalStorage<T, true> {
142 union {
143 char empty;
144 T value;
145 };
146 bool hasVal = false;
147
148public:
149 ~OptionalStorage() = default;
150
151 constexpr OptionalStorage() noexcept : empty{} {}
152
153 constexpr OptionalStorage(OptionalStorage const &other) = default;
154 constexpr OptionalStorage(OptionalStorage &&other) = default;
155
156 OptionalStorage &operator=(OptionalStorage const &other) = default;
157 OptionalStorage &operator=(OptionalStorage &&other) = default;
158
159 template <class... Args>
160 constexpr explicit OptionalStorage(in_place_t, Args &&... args)
161 : value(std::forward<Args>(args)...), hasVal(true) {}
162
163 void reset() noexcept {
164 if (hasVal) {
165 value.~T();
166 hasVal = false;
167 }
168 }
169
170 constexpr bool hasValue() const noexcept { return hasVal; }
171
172 T &getValue() LLVM_LVALUE_FUNCTION& noexcept {
173 assert(hasVal)((hasVal) ? static_cast<void> (0) : __assert_fail ("hasVal"
, "/build/llvm-toolchain-snapshot-12~++20200926111128+c6c5629f2fb/llvm/include/llvm/ADT/Optional.h"
, 173, __PRETTY_FUNCTION__))
;
174 return value;
175 }
176 constexpr T const &getValue() const LLVM_LVALUE_FUNCTION& noexcept {
177 assert(hasVal)((hasVal) ? static_cast<void> (0) : __assert_fail ("hasVal"
, "/build/llvm-toolchain-snapshot-12~++20200926111128+c6c5629f2fb/llvm/include/llvm/ADT/Optional.h"
, 177, __PRETTY_FUNCTION__))
;
178 return value;
179 }
180#if LLVM_HAS_RVALUE_REFERENCE_THIS1
181 T &&getValue() && noexcept {
182 assert(hasVal)((hasVal) ? static_cast<void> (0) : __assert_fail ("hasVal"
, "/build/llvm-toolchain-snapshot-12~++20200926111128+c6c5629f2fb/llvm/include/llvm/ADT/Optional.h"
, 182, __PRETTY_FUNCTION__))
;
183 return std::move(value);
184 }
185#endif
186
187 template <class... Args> void emplace(Args &&... args) {
188 reset();
189 ::new ((void *)std::addressof(value)) T(std::forward<Args>(args)...);
190 hasVal = true;
191 }
192
193 OptionalStorage &operator=(T const &y) {
194 if (hasValue()) {
195 value = y;
196 } else {
197 ::new ((void *)std::addressof(value)) T(y);
198 hasVal = true;
199 }
200 return *this;
201 }
202 OptionalStorage &operator=(T &&y) {
203 if (hasValue()) {
204 value = std::move(y);
205 } else {
206 ::new ((void *)std::addressof(value)) T(std::move(y));
207 hasVal = true;
208 }
209 return *this;
210 }
211};
212
213} // namespace optional_detail
214
215template <typename T> class Optional {
216 optional_detail::OptionalStorage<T> Storage;
217
218public:
219 using value_type = T;
220
221 constexpr Optional() {}
222 constexpr Optional(NoneType) {}
223
224 constexpr Optional(const T &y) : Storage(optional_detail::in_place_t{}, y) {}
225 constexpr Optional(const Optional &O) = default;
226
227 constexpr Optional(T &&y)
228 : Storage(optional_detail::in_place_t{}, std::move(y)) {}
229 constexpr Optional(Optional &&O) = default;
230
231 Optional &operator=(T &&y) {
232 Storage = std::move(y);
233 return *this;
234 }
235 Optional &operator=(Optional &&O) = default;
236
237 /// Create a new object by constructing it in place with the given arguments.
238 template <typename... ArgTypes> void emplace(ArgTypes &&... Args) {
239 Storage.emplace(std::forward<ArgTypes>(Args)...);
240 }
241
242 static constexpr Optional create(const T *y) {
243 return y ? Optional(*y) : Optional();
244 }
245
246 Optional &operator=(const T &y) {
247 Storage = y;
248 return *this;
249 }
250 Optional &operator=(const Optional &O) = default;
251
252 void reset() { Storage.reset(); }
253
254 constexpr const T *getPointer() const { return &Storage.getValue(); }
255 T *getPointer() { return &Storage.getValue(); }
256 constexpr const T &getValue() const LLVM_LVALUE_FUNCTION& {
257 return Storage.getValue();
258 }
259 T &getValue() LLVM_LVALUE_FUNCTION& { return Storage.getValue(); }
260
261 constexpr explicit operator bool() const { return hasValue(); }
2
Calling 'Optional::hasValue'
7
Returning from 'Optional::hasValue'
8
Returning the value 1, which participates in a condition later
262 constexpr bool hasValue() const { return Storage.hasValue(); }
3
Calling 'OptionalStorage::hasValue'
5
Returning from 'OptionalStorage::hasValue'
6
Returning the value 1, which participates in a condition later
263 constexpr const T *operator->() const { return getPointer(); }
264 T *operator->() { return getPointer(); }
265 constexpr const T &operator*() const LLVM_LVALUE_FUNCTION& {
266 return getValue();
267 }
268 T &operator*() LLVM_LVALUE_FUNCTION& { return getValue(); }
269
270 template <typename U>
271 constexpr T getValueOr(U &&value) const LLVM_LVALUE_FUNCTION& {
272 return hasValue() ? getValue() : std::forward<U>(value);
273 }
274
275 /// Apply a function to the value if present; otherwise return None.
276 template <class Function>
277 auto map(const Function &F) const LLVM_LVALUE_FUNCTION&
278 -> Optional<decltype(F(getValue()))> {
279 if (*this) return F(getValue());
280 return None;
281 }
282
283#if LLVM_HAS_RVALUE_REFERENCE_THIS1
284 T &&getValue() && { return std::move(Storage.getValue()); }
285 T &&operator*() && { return std::move(Storage.getValue()); }
286
287 template <typename U>
288 T getValueOr(U &&value) && {
289 return hasValue() ? std::move(getValue()) : std::forward<U>(value);
290 }
291
292 /// Apply a function to the value if present; otherwise return None.
293 template <class Function>
294 auto map(const Function &F) &&
295 -> Optional<decltype(F(std::move(*this).getValue()))> {
296 if (*this) return F(std::move(*this).getValue());
297 return None;
298 }
299#endif
300};
301
302template <typename T, typename U>
303constexpr bool operator==(const Optional<T> &X, const Optional<U> &Y) {
304 if (X && Y)
305 return *X == *Y;
306 return X.hasValue() == Y.hasValue();
307}
308
309template <typename T, typename U>
310constexpr bool operator!=(const Optional<T> &X, const Optional<U> &Y) {
311 return !(X == Y);
312}
313
314template <typename T, typename U>
315constexpr bool operator<(const Optional<T> &X, const Optional<U> &Y) {
316 if (X && Y)
317 return *X < *Y;
318 return X.hasValue() < Y.hasValue();
319}
320
321template <typename T, typename U>
322constexpr bool operator<=(const Optional<T> &X, const Optional<U> &Y) {
323 return !(Y < X);
324}
325
326template <typename T, typename U>
327constexpr bool operator>(const Optional<T> &X, const Optional<U> &Y) {
328 return Y < X;
329}
330
331template <typename T, typename U>
332constexpr bool operator>=(const Optional<T> &X, const Optional<U> &Y) {
333 return !(X < Y);
334}
335
336template <typename T>
337constexpr bool operator==(const Optional<T> &X, NoneType) {
338 return !X;
339}
340
341template <typename T>
342constexpr bool operator==(NoneType, const Optional<T> &X) {
343 return X == None;
344}
345
346template <typename T>
347constexpr bool operator!=(const Optional<T> &X, NoneType) {
348 return !(X == None);
349}
350
351template <typename T>
352constexpr bool operator!=(NoneType, const Optional<T> &X) {
353 return X != None;
354}
355
356template <typename T> constexpr bool operator<(const Optional<T> &X, NoneType) {
357 return false;
358}
359
360template <typename T> constexpr bool operator<(NoneType, const Optional<T> &X) {
361 return X.hasValue();
362}
363
364template <typename T>
365constexpr bool operator<=(const Optional<T> &X, NoneType) {
366 return !(None < X);
367}
368
369template <typename T>
370constexpr bool operator<=(NoneType, const Optional<T> &X) {
371 return !(X < None);
372}
373
374template <typename T> constexpr bool operator>(const Optional<T> &X, NoneType) {
375 return None < X;
376}
377
378template <typename T> constexpr bool operator>(NoneType, const Optional<T> &X) {
379 return X < None;
380}
381
382template <typename T>
383constexpr bool operator>=(const Optional<T> &X, NoneType) {
384 return None <= X;
385}
386
387template <typename T>
388constexpr bool operator>=(NoneType, const Optional<T> &X) {
389 return X <= None;
390}
391
392template <typename T>
393constexpr bool operator==(const Optional<T> &X, const T &Y) {
394 return X && *X == Y;
395}
396
397template <typename T>
398constexpr bool operator==(const T &X, const Optional<T> &Y) {
399 return Y && X == *Y;
400}
401
402template <typename T>
403constexpr bool operator!=(const Optional<T> &X, const T &Y) {
404 return !(X == Y);
405}
406
407template <typename T>
408constexpr bool operator!=(const T &X, const Optional<T> &Y) {
409 return !(X == Y);
410}
411
412template <typename T>
413constexpr bool operator<(const Optional<T> &X, const T &Y) {
414 return !X || *X < Y;
415}
416
417template <typename T>
418constexpr bool operator<(const T &X, const Optional<T> &Y) {
419 return Y && X < *Y;
420}
421
422template <typename T>
423constexpr bool operator<=(const Optional<T> &X, const T &Y) {
424 return !(Y < X);
425}
426
427template <typename T>
428constexpr bool operator<=(const T &X, const Optional<T> &Y) {
429 return !(Y < X);
430}
431
432template <typename T>
433constexpr bool operator>(const Optional<T> &X, const T &Y) {
434 return Y < X;
435}
436
437template <typename T>
438constexpr bool operator>(const T &X, const Optional<T> &Y) {
439 return Y < X;
440}
441
442template <typename T>
443constexpr bool operator>=(const Optional<T> &X, const T &Y) {
444 return !(X < Y);
445}
446
447template <typename T>
448constexpr bool operator>=(const T &X, const Optional<T> &Y) {
449 return !(X < Y);
450}
451
452raw_ostream &operator<<(raw_ostream &OS, NoneType);
453
454template <typename T, typename = decltype(std::declval<raw_ostream &>()
455 << std::declval<const T &>())>
456raw_ostream &operator<<(raw_ostream &OS, const Optional<T> &O) {
457 if (O)
458 OS << *O;
459 else
460 OS << None;
461 return OS;
462}
463
464} // end namespace llvm
465
466#endif // LLVM_ADT_OPTIONAL_H