Bug Summary

File:clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
Warning:line 766, 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~++20200917111122+b03c2b8395b/build-llvm/tools/clang/lib/StaticAnalyzer/Checkers -I /build/llvm-toolchain-snapshot-12~++20200917111122+b03c2b8395b/clang/lib/StaticAnalyzer/Checkers -I /build/llvm-toolchain-snapshot-12~++20200917111122+b03c2b8395b/clang/include -I /build/llvm-toolchain-snapshot-12~++20200917111122+b03c2b8395b/build-llvm/tools/clang/include -I /build/llvm-toolchain-snapshot-12~++20200917111122+b03c2b8395b/build-llvm/include -I /build/llvm-toolchain-snapshot-12~++20200917111122+b03c2b8395b/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~++20200917111122+b03c2b8395b/build-llvm/tools/clang/lib/StaticAnalyzer/Checkers -fdebug-prefix-map=/build/llvm-toolchain-snapshot-12~++20200917111122+b03c2b8395b=. -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-17-195756-12974-1 -x c++ /build/llvm-toolchain-snapshot-12~++20200917111122+b03c2b8395b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp

/build/llvm-toolchain-snapshot-12~++20200917111122+b03c2b8395b/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~++20200917111122+b03c2b8395b/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~++20200917111122+b03c2b8395b/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~++20200917111122+b03c2b8395b/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~++20200917111122+b03c2b8395b/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~++20200917111122+b03c2b8395b/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~++20200917111122+b03c2b8395b/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~++20200917111122+b03c2b8395b/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~++20200917111122+b03c2b8395b/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~++20200917111122+b03c2b8395b/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~++20200917111122+b03c2b8395b/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~++20200917111122+b03c2b8395b/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~++20200917111122+b03c2b8395b/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~++20200917111122+b03c2b8395b/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~++20200917111122+b03c2b8395b/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~++20200917111122+b03c2b8395b/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~++20200917111122+b03c2b8395b/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~++20200917111122+b03c2b8395b/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~++20200917111122+b03c2b8395b/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~++20200917111122+b03c2b8395b/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 // FIXME Probably the Signature should not be part of the Summary,
446 // We can remove once all overload of addToFunctionSummaryMap requires the
447 // Signature explicitly given.
448 Optional<Signature> Sign;
449 const InvalidationKind InvalidationKd;
450 Cases CaseConstraints;
451 ConstraintSet ArgConstraints;
452
453 // The function to which the summary applies. This is set after lookup and
454 // match to the signature.
455 const FunctionDecl *FD = nullptr;
456
457 public:
458 Summary(ArgTypes ArgTys, RetType RetTy, InvalidationKind InvalidationKd)
459 : Sign(Signature(ArgTys, RetTy)), InvalidationKd(InvalidationKd) {}
460
461 Summary(InvalidationKind InvalidationKd) : InvalidationKd(InvalidationKd) {}
462
463 // FIXME Remove, once all overload of addToFunctionSummaryMap requires the
464 // Signature explicitly given.
465 Summary &setSignature(const Signature &S) {
466 Sign = S;
467 return *this;
468 }
469
470 Summary &Case(ConstraintSet &&CS) {
471 CaseConstraints.push_back(std::move(CS));
472 return *this;
473 }
474 Summary &ArgConstraint(ValueConstraintPtr VC) {
475 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~++20200917111122+b03c2b8395b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp"
, 476, __PRETTY_FUNCTION__))
476 "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~++20200917111122+b03c2b8395b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp"
, 476, __PRETTY_FUNCTION__))
;
477 ArgConstraints.push_back(VC);
478 return *this;
479 }
480
481 InvalidationKind getInvalidationKd() const { return InvalidationKd; }
482 const Cases &getCaseConstraints() const { return CaseConstraints; }
483 const ConstraintSet &getArgConstraints() const { return ArgConstraints; }
484
485 QualType getArgType(ArgNo ArgN) const {
486 return StdLibraryFunctionsChecker::getArgType(FD, ArgN);
487 }
488
489 // Returns true if the summary should be applied to the given function.
490 // And if yes then store the function declaration.
491 bool matchesAndSet(const FunctionDecl *FD) {
492 assert(Sign &&((Sign && "Signature must be set before comparing to a FunctionDecl"
) ? static_cast<void> (0) : __assert_fail ("Sign && \"Signature must be set before comparing to a FunctionDecl\""
, "/build/llvm-toolchain-snapshot-12~++20200917111122+b03c2b8395b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp"
, 493, __PRETTY_FUNCTION__))
493 "Signature must be set before comparing to a FunctionDecl")((Sign && "Signature must be set before comparing to a FunctionDecl"
) ? static_cast<void> (0) : __assert_fail ("Sign && \"Signature must be set before comparing to a FunctionDecl\""
, "/build/llvm-toolchain-snapshot-12~++20200917111122+b03c2b8395b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp"
, 493, __PRETTY_FUNCTION__))
;
494 bool Result = Sign->matches(FD) && validateByConstraints(FD);
495 if (Result) {
496 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~++20200917111122+b03c2b8395b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp"
, 496, __PRETTY_FUNCTION__))
;
497 this->FD = FD;
498 }
499 return Result;
500 }
501
502 // FIXME Remove, once all overload of addToFunctionSummaryMap requires the
503 // Signature explicitly given.
504 bool hasInvalidSignature() {
505 assert(Sign && "Signature must be set before this query")((Sign && "Signature must be set before this query") ?
static_cast<void> (0) : __assert_fail ("Sign && \"Signature must be set before this query\""
, "/build/llvm-toolchain-snapshot-12~++20200917111122+b03c2b8395b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp"
, 505, __PRETTY_FUNCTION__))
;
506 return Sign->isInvalid();
507 }
508
509 private:
510 // Once we know the exact type of the function then do sanity check on all
511 // the given constraints.
512 bool validateByConstraints(const FunctionDecl *FD) const {
513 for (const ConstraintSet &Case : CaseConstraints)
514 for (const ValueConstraintPtr &Constraint : Case)
515 if (!Constraint->checkValidity(FD))
516 return false;
517 for (const ValueConstraintPtr &Constraint : ArgConstraints)
518 if (!Constraint->checkValidity(FD))
519 return false;
520 return true;
521 }
522 };
523
524 // The map of all functions supported by the checker. It is initialized
525 // lazily, and it doesn't change after initialization.
526 using FunctionSummaryMapType = llvm::DenseMap<const FunctionDecl *, Summary>;
527 mutable FunctionSummaryMapType FunctionSummaryMap;
528
529 mutable std::unique_ptr<BugType> BT_InvalidArg;
530
531 static SVal getArgSVal(const CallEvent &Call, ArgNo ArgN) {
532 return ArgN == Ret ? Call.getReturnValue() : Call.getArgSVal(ArgN);
533 }
534
535public:
536 void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
537 void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
538 bool evalCall(const CallEvent &Call, CheckerContext &C) const;
539
540 enum CheckKind {
541 CK_StdCLibraryFunctionArgsChecker,
542 CK_StdCLibraryFunctionsTesterChecker,
543 CK_NumCheckKinds
544 };
545 DefaultBool ChecksEnabled[CK_NumCheckKinds];
546 CheckerNameRef CheckNames[CK_NumCheckKinds];
547
548 bool DisplayLoadedSummaries = false;
549 bool ModelPOSIX = false;
550
551private:
552 Optional<Summary> findFunctionSummary(const FunctionDecl *FD,
553 CheckerContext &C) const;
554 Optional<Summary> findFunctionSummary(const CallEvent &Call,
555 CheckerContext &C) const;
556
557 void initFunctionSummaries(CheckerContext &C) const;
558
559 void reportBug(const CallEvent &Call, ExplodedNode *N,
560 const ValueConstraint *VC, CheckerContext &C) const {
561 if (!ChecksEnabled[CK_StdCLibraryFunctionArgsChecker])
562 return;
563 // TODO Add more detailed diagnostic.
564 std::string Msg =
565 (Twine("Function argument constraint is not satisfied, constraint: ") +
566 VC->getName().data() + ", ArgN: " + Twine(VC->getArgNo()))
567 .str();
568 if (!BT_InvalidArg)
569 BT_InvalidArg = std::make_unique<BugType>(
570 CheckNames[CK_StdCLibraryFunctionArgsChecker],
571 "Unsatisfied argument constraints", categories::LogicError);
572 auto R = std::make_unique<PathSensitiveBugReport>(*BT_InvalidArg, Msg, N);
573 bugreporter::trackExpressionValue(N, Call.getArgExpr(VC->getArgNo()), *R);
574
575 // Highlight the range of the argument that was violated.
576 R->addRange(Call.getArgSourceRange(VC->getArgNo()));
577
578 C.emitReport(std::move(R));
579 }
580};
581
582const StdLibraryFunctionsChecker::ArgNo StdLibraryFunctionsChecker::Ret =
583 std::numeric_limits<ArgNo>::max();
584
585} // end of anonymous namespace
586
587ProgramStateRef StdLibraryFunctionsChecker::RangeConstraint::applyAsOutOfRange(
588 ProgramStateRef State, const CallEvent &Call,
589 const Summary &Summary) const {
590 if (Ranges.empty())
591 return State;
592
593 ProgramStateManager &Mgr = State->getStateManager();
594 SValBuilder &SVB = Mgr.getSValBuilder();
595 BasicValueFactory &BVF = SVB.getBasicValueFactory();
596 ConstraintManager &CM = Mgr.getConstraintManager();
597 QualType T = Summary.getArgType(getArgNo());
598 SVal V = getArgSVal(Call, getArgNo());
599
600 if (auto N = V.getAs<NonLoc>()) {
601 const IntRangeVector &R = getRanges();
602 size_t E = R.size();
603 for (size_t I = 0; I != E; ++I) {
604 const llvm::APSInt &Min = BVF.getValue(R[I].first, T);
605 const llvm::APSInt &Max = BVF.getValue(R[I].second, T);
606 assert(Min <= Max)((Min <= Max) ? static_cast<void> (0) : __assert_fail
("Min <= Max", "/build/llvm-toolchain-snapshot-12~++20200917111122+b03c2b8395b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp"
, 606, __PRETTY_FUNCTION__))
;
607 State = CM.assumeInclusiveRange(State, *N, Min, Max, false);
608 if (!State)
609 break;
610 }
611 }
612
613 return State;
614}
615
616ProgramStateRef StdLibraryFunctionsChecker::RangeConstraint::applyAsWithinRange(
617 ProgramStateRef State, const CallEvent &Call,
618 const Summary &Summary) const {
619 if (Ranges.empty())
620 return State;
621
622 ProgramStateManager &Mgr = State->getStateManager();
623 SValBuilder &SVB = Mgr.getSValBuilder();
624 BasicValueFactory &BVF = SVB.getBasicValueFactory();
625 ConstraintManager &CM = Mgr.getConstraintManager();
626 QualType T = Summary.getArgType(getArgNo());
627 SVal V = getArgSVal(Call, getArgNo());
628
629 // "WithinRange R" is treated as "outside [T_MIN, T_MAX] \ R".
630 // We cut off [T_MIN, min(R) - 1] and [max(R) + 1, T_MAX] if necessary,
631 // and then cut away all holes in R one by one.
632 //
633 // E.g. consider a range list R as [A, B] and [C, D]
634 // -------+--------+------------------+------------+----------->
635 // A B C D
636 // Then we assume that the value is not in [-inf, A - 1],
637 // then not in [D + 1, +inf], then not in [B + 1, C - 1]
638 if (auto N = V.getAs<NonLoc>()) {
639 const IntRangeVector &R = getRanges();
640 size_t E = R.size();
641
642 const llvm::APSInt &MinusInf = BVF.getMinValue(T);
643 const llvm::APSInt &PlusInf = BVF.getMaxValue(T);
644
645 const llvm::APSInt &Left = BVF.getValue(R[0].first - 1ULL, T);
646 if (Left != PlusInf) {
647 assert(MinusInf <= Left)((MinusInf <= Left) ? static_cast<void> (0) : __assert_fail
("MinusInf <= Left", "/build/llvm-toolchain-snapshot-12~++20200917111122+b03c2b8395b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp"
, 647, __PRETTY_FUNCTION__))
;
648 State = CM.assumeInclusiveRange(State, *N, MinusInf, Left, false);
649 if (!State)
650 return nullptr;
651 }
652
653 const llvm::APSInt &Right = BVF.getValue(R[E - 1].second + 1ULL, T);
654 if (Right != MinusInf) {
655 assert(Right <= PlusInf)((Right <= PlusInf) ? static_cast<void> (0) : __assert_fail
("Right <= PlusInf", "/build/llvm-toolchain-snapshot-12~++20200917111122+b03c2b8395b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp"
, 655, __PRETTY_FUNCTION__))
;
656 State = CM.assumeInclusiveRange(State, *N, Right, PlusInf, false);
657 if (!State)
658 return nullptr;
659 }
660
661 for (size_t I = 1; I != E; ++I) {
662 const llvm::APSInt &Min = BVF.getValue(R[I - 1].second + 1ULL, T);
663 const llvm::APSInt &Max = BVF.getValue(R[I].first - 1ULL, T);
664 if (Min <= Max) {
665 State = CM.assumeInclusiveRange(State, *N, Min, Max, false);
666 if (!State)
667 return nullptr;
668 }
669 }
670 }
671
672 return State;
673}
674
675ProgramStateRef StdLibraryFunctionsChecker::ComparisonConstraint::apply(
676 ProgramStateRef State, const CallEvent &Call, const Summary &Summary,
677 CheckerContext &C) const {
678
679 ProgramStateManager &Mgr = State->getStateManager();
680 SValBuilder &SVB = Mgr.getSValBuilder();
681 QualType CondT = SVB.getConditionType();
682 QualType T = Summary.getArgType(getArgNo());
683 SVal V = getArgSVal(Call, getArgNo());
684
685 BinaryOperator::Opcode Op = getOpcode();
686 ArgNo OtherArg = getOtherArgNo();
687 SVal OtherV = getArgSVal(Call, OtherArg);
688 QualType OtherT = Summary.getArgType(OtherArg);
689 // Note: we avoid integral promotion for comparison.
690 OtherV = SVB.evalCast(OtherV, T, OtherT);
691 if (auto CompV = SVB.evalBinOp(State, Op, V, OtherV, CondT)
692 .getAs<DefinedOrUnknownSVal>())
693 State = State->assume(*CompV, true);
694 return State;
695}
696
697void StdLibraryFunctionsChecker::checkPreCall(const CallEvent &Call,
698 CheckerContext &C) const {
699 Optional<Summary> FoundSummary = findFunctionSummary(Call, C);
700 if (!FoundSummary)
701 return;
702
703 const Summary &Summary = *FoundSummary;
704 ProgramStateRef State = C.getState();
705
706 ProgramStateRef NewState = State;
707 for (const ValueConstraintPtr &Constraint : Summary.getArgConstraints()) {
708 ProgramStateRef SuccessSt = Constraint->apply(NewState, Call, Summary, C);
709 ProgramStateRef FailureSt =
710 Constraint->negate()->apply(NewState, Call, Summary, C);
711 // The argument constraint is not satisfied.
712 if (FailureSt && !SuccessSt) {
713 if (ExplodedNode *N = C.generateErrorNode(NewState))
714 reportBug(Call, N, Constraint.get(), C);
715 break;
716 } else {
717 // We will apply the constraint even if we cannot reason about the
718 // argument. This means both SuccessSt and FailureSt can be true. If we
719 // weren't applying the constraint that would mean that symbolic
720 // execution continues on a code whose behaviour is undefined.
721 assert(SuccessSt)((SuccessSt) ? static_cast<void> (0) : __assert_fail ("SuccessSt"
, "/build/llvm-toolchain-snapshot-12~++20200917111122+b03c2b8395b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp"
, 721, __PRETTY_FUNCTION__))
;
722 NewState = SuccessSt;
723 }
724 }
725 if (NewState && NewState != State)
726 C.addTransition(NewState);
727}
728
729void StdLibraryFunctionsChecker::checkPostCall(const CallEvent &Call,
730 CheckerContext &C) const {
731 Optional<Summary> FoundSummary = findFunctionSummary(Call, C);
732 if (!FoundSummary)
733 return;
734
735 // Now apply the constraints.
736 const Summary &Summary = *FoundSummary;
737 ProgramStateRef State = C.getState();
738
739 // Apply case/branch specifications.
740 for (const ConstraintSet &Case : Summary.getCaseConstraints()) {
741 ProgramStateRef NewState = State;
742 for (const ValueConstraintPtr &Constraint : Case) {
743 NewState = Constraint->apply(NewState, Call, Summary, C);
744 if (!NewState)
745 break;
746 }
747
748 if (NewState && NewState != State)
749 C.addTransition(NewState);
750 }
751}
752
753bool StdLibraryFunctionsChecker::evalCall(const CallEvent &Call,
754 CheckerContext &C) const {
755 Optional<Summary> FoundSummary = findFunctionSummary(Call, C);
756 if (!FoundSummary)
1
Calling 'Optional::operator bool'
9
Returning from 'Optional::operator bool'
10
Taking false branch
757 return false;
758
759 const Summary &Summary = *FoundSummary;
760 switch (Summary.getInvalidationKd()) {
11
Control jumps to 'case EvalCallAsPure:' at line 761
761 case EvalCallAsPure: {
762 ProgramStateRef State = C.getState();
763 const LocationContext *LC = C.getLocationContext();
764 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
765 SVal V = C.getSValBuilder().conjureSymbolVal(
766 CE, LC, CE->getType().getCanonicalType(), C.blockCount());
14
Called C++ object pointer is null
767 State = State->BindExpr(CE, LC, V);
768 C.addTransition(State);
769 return true;
770 }
771 case NoEvalCall:
772 // Summary tells us to avoid performing eval::Call. The function is possibly
773 // evaluated by another checker, or evaluated conservatively.
774 return false;
775 }
776 llvm_unreachable("Unknown invalidation kind!")::llvm::llvm_unreachable_internal("Unknown invalidation kind!"
, "/build/llvm-toolchain-snapshot-12~++20200917111122+b03c2b8395b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp"
, 776)
;
777}
778
779bool StdLibraryFunctionsChecker::Signature::matches(
780 const FunctionDecl *FD) const {
781 assert(!isInvalid())((!isInvalid()) ? static_cast<void> (0) : __assert_fail
("!isInvalid()", "/build/llvm-toolchain-snapshot-12~++20200917111122+b03c2b8395b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp"
, 781, __PRETTY_FUNCTION__))
;
782 // Check the number of arguments.
783 if (FD->param_size() != ArgTys.size())
784 return false;
785
786 // The "restrict" keyword is illegal in C++, however, many libc
787 // implementations use the "__restrict" compiler intrinsic in functions
788 // prototypes. The "__restrict" keyword qualifies a type as a restricted type
789 // even in C++.
790 // In case of any non-C99 languages, we don't want to match based on the
791 // restrict qualifier because we cannot know if the given libc implementation
792 // qualifies the paramter type or not.
793 auto RemoveRestrict = [&FD](QualType T) {
794 if (!FD->getASTContext().getLangOpts().C99)
795 T.removeLocalRestrict();
796 return T;
797 };
798
799 // Check the return type.
800 if (!isIrrelevant(RetTy)) {
801 QualType FDRetTy = RemoveRestrict(FD->getReturnType().getCanonicalType());
802 if (RetTy != FDRetTy)
803 return false;
804 }
805
806 // Check the argument types.
807 for (size_t I = 0, E = ArgTys.size(); I != E; ++I) {
808 QualType ArgTy = ArgTys[I];
809 if (isIrrelevant(ArgTy))
810 continue;
811 QualType FDArgTy =
812 RemoveRestrict(FD->getParamDecl(I)->getType().getCanonicalType());
813 if (ArgTy != FDArgTy)
814 return false;
815 }
816
817 return true;
818}
819
820Optional<StdLibraryFunctionsChecker::Summary>
821StdLibraryFunctionsChecker::findFunctionSummary(const FunctionDecl *FD,
822 CheckerContext &C) const {
823 if (!FD)
824 return None;
825
826 initFunctionSummaries(C);
827
828 auto FSMI = FunctionSummaryMap.find(FD->getCanonicalDecl());
829 if (FSMI == FunctionSummaryMap.end())
830 return None;
831 return FSMI->second;
832}
833
834Optional<StdLibraryFunctionsChecker::Summary>
835StdLibraryFunctionsChecker::findFunctionSummary(const CallEvent &Call,
836 CheckerContext &C) const {
837 const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
838 if (!FD)
839 return None;
840 return findFunctionSummary(FD, C);
841}
842
843void StdLibraryFunctionsChecker::initFunctionSummaries(
844 CheckerContext &C) const {
845 if (!FunctionSummaryMap.empty())
846 return;
847
848 SValBuilder &SVB = C.getSValBuilder();
849 BasicValueFactory &BVF = SVB.getBasicValueFactory();
850 const ASTContext &ACtx = BVF.getContext();
851
852 // Helper class to lookup a type by its name.
853 class LookupType {
854 const ASTContext &ACtx;
855
856 public:
857 LookupType(const ASTContext &ACtx) : ACtx(ACtx) {}
858
859 // Find the type. If not found then the optional is not set.
860 llvm::Optional<QualType> operator()(StringRef Name) {
861 IdentifierInfo &II = ACtx.Idents.get(Name);
862 auto LookupRes = ACtx.getTranslationUnitDecl()->lookup(&II);
863 if (LookupRes.size() == 0)
864 return None;
865
866 // Prioritze typedef declarations.
867 // This is needed in case of C struct typedefs. E.g.:
868 // typedef struct FILE FILE;
869 // In this case, we have a RecordDecl 'struct FILE' with the name 'FILE'
870 // and we have a TypedefDecl with the name 'FILE'.
871 for (Decl *D : LookupRes)
872 if (auto *TD = dyn_cast<TypedefNameDecl>(D))
873 return ACtx.getTypeDeclType(TD).getCanonicalType();
874
875 // Find the first TypeDecl.
876 // There maybe cases when a function has the same name as a struct.
877 // E.g. in POSIX: `struct stat` and the function `stat()`:
878 // int stat(const char *restrict path, struct stat *restrict buf);
879 for (Decl *D : LookupRes)
880 if (auto *TD = dyn_cast<TypeDecl>(D))
881 return ACtx.getTypeDeclType(TD).getCanonicalType();
882 return None;
883 }
884 } lookupTy(ACtx);
885
886 // Below are auxiliary classes to handle optional types that we get as a
887 // result of the lookup.
888 class GetRestrictTy {
889 const ASTContext &ACtx;
890
891 public:
892 GetRestrictTy(const ASTContext &ACtx) : ACtx(ACtx) {}
893 QualType operator()(QualType Ty) {
894 return ACtx.getLangOpts().C99 ? ACtx.getRestrictType(Ty) : Ty;
895 }
896 Optional<QualType> operator()(Optional<QualType> Ty) {
897 if (Ty)
898 return operator()(*Ty);
899 return None;
900 }
901 } getRestrictTy(ACtx);
902 class GetPointerTy {
903 const ASTContext &ACtx;
904
905 public:
906 GetPointerTy(const ASTContext &ACtx) : ACtx(ACtx) {}
907 QualType operator()(QualType Ty) { return ACtx.getPointerType(Ty); }
908 Optional<QualType> operator()(Optional<QualType> Ty) {
909 if (Ty)
910 return operator()(*Ty);
911 return None;
912 }
913 } getPointerTy(ACtx);
914 class {
915 public:
916 Optional<QualType> operator()(Optional<QualType> Ty) {
917 return Ty ? Optional<QualType>(Ty->withConst()) : None;
918 }
919 QualType operator()(QualType Ty) { return Ty.withConst(); }
920 } getConstTy;
921 class GetMaxValue {
922 BasicValueFactory &BVF;
923
924 public:
925 GetMaxValue(BasicValueFactory &BVF) : BVF(BVF) {}
926 Optional<RangeInt> operator()(QualType Ty) {
927 return BVF.getMaxValue(Ty).getLimitedValue();
928 }
929 Optional<RangeInt> operator()(Optional<QualType> Ty) {
930 if (Ty) {
931 return operator()(*Ty);
932 }
933 return None;
934 }
935 } getMaxValue(BVF);
936
937 // These types are useful for writing specifications quickly,
938 // New specifications should probably introduce more types.
939 // Some types are hard to obtain from the AST, eg. "ssize_t".
940 // In such cases it should be possible to provide multiple variants
941 // of function summary for common cases (eg. ssize_t could be int or long
942 // or long long, so three summary variants would be enough).
943 // Of course, function variants are also useful for C++ overloads.
944 const QualType VoidTy = ACtx.VoidTy;
945 const QualType CharTy = ACtx.CharTy;
946 const QualType WCharTy = ACtx.WCharTy;
947 const QualType IntTy = ACtx.IntTy;
948 const QualType UnsignedIntTy = ACtx.UnsignedIntTy;
949 const QualType LongTy = ACtx.LongTy;
950 const QualType LongLongTy = ACtx.LongLongTy;
951 const QualType SizeTy = ACtx.getSizeType();
952
953 const QualType VoidPtrTy = getPointerTy(VoidTy); // void *
954 const QualType IntPtrTy = getPointerTy(IntTy); // int *
955 const QualType UnsignedIntPtrTy =
956 getPointerTy(UnsignedIntTy); // unsigned int *
957 const QualType VoidPtrRestrictTy = getRestrictTy(VoidPtrTy);
958 const QualType ConstVoidPtrTy =
959 getPointerTy(getConstTy(VoidTy)); // const void *
960 const QualType CharPtrTy = getPointerTy(CharTy); // char *
961 const QualType CharPtrRestrictTy = getRestrictTy(CharPtrTy);
962 const QualType ConstCharPtrTy =
963 getPointerTy(getConstTy(CharTy)); // const char *
964 const QualType ConstCharPtrRestrictTy = getRestrictTy(ConstCharPtrTy);
965 const QualType Wchar_tPtrTy = getPointerTy(WCharTy); // wchar_t *
966 const QualType ConstWchar_tPtrTy =
967 getPointerTy(getConstTy(WCharTy)); // const wchar_t *
968 const QualType ConstVoidPtrRestrictTy = getRestrictTy(ConstVoidPtrTy);
969 const QualType SizePtrTy = getPointerTy(SizeTy);
970 const QualType SizePtrRestrictTy = getRestrictTy(SizePtrTy);
971
972 const RangeInt IntMax = BVF.getMaxValue(IntTy).getLimitedValue();
973 const RangeInt UnsignedIntMax =
974 BVF.getMaxValue(UnsignedIntTy).getLimitedValue();
975 const RangeInt LongMax = BVF.getMaxValue(LongTy).getLimitedValue();
976 const RangeInt LongLongMax = BVF.getMaxValue(LongLongTy).getLimitedValue();
977 const RangeInt SizeMax = BVF.getMaxValue(SizeTy).getLimitedValue();
978
979 // Set UCharRangeMax to min of int or uchar maximum value.
980 // The C standard states that the arguments of functions like isalpha must
981 // be representable as an unsigned char. Their type is 'int', so the max
982 // value of the argument should be min(UCharMax, IntMax). This just happen
983 // to be true for commonly used and well tested instruction set
984 // architectures, but not for others.
985 const RangeInt UCharRangeMax =
986 std::min(BVF.getMaxValue(ACtx.UnsignedCharTy).getLimitedValue(), IntMax);
987
988 // The platform dependent value of EOF.
989 // Try our best to parse this from the Preprocessor, otherwise fallback to -1.
990 const auto EOFv = [&C]() -> RangeInt {
991 if (const llvm::Optional<int> OptInt =
992 tryExpandAsInteger("EOF", C.getPreprocessor()))
993 return *OptInt;
994 return -1;
995 }();
996
997 // Auxiliary class to aid adding summaries to the summary map.
998 struct AddToFunctionSummaryMap {
999 const ASTContext &ACtx;
1000 FunctionSummaryMapType &Map;
1001 bool DisplayLoadedSummaries;
1002 AddToFunctionSummaryMap(const ASTContext &ACtx, FunctionSummaryMapType &FSM,
1003 bool DisplayLoadedSummaries)
1004 : ACtx(ACtx), Map(FSM), DisplayLoadedSummaries(DisplayLoadedSummaries) {
1005 }
1006
1007 // Add a summary to a FunctionDecl found by lookup. The lookup is performed
1008 // by the given Name, and in the global scope. The summary will be attached
1009 // to the found FunctionDecl only if the signatures match.
1010 //
1011 // Returns true if the summary has been added, false otherwise.
1012 // FIXME remove all overloads without the explicit Signature parameter.
1013 bool operator()(StringRef Name, Summary S) {
1014 if (S.hasInvalidSignature())
1015 return false;
1016 IdentifierInfo &II = ACtx.Idents.get(Name);
1017 auto LookupRes = ACtx.getTranslationUnitDecl()->lookup(&II);
1018 if (LookupRes.size() == 0)
1019 return false;
1020 for (Decl *D : LookupRes) {
1021 if (auto *FD = dyn_cast<FunctionDecl>(D)) {
1022 if (S.matchesAndSet(FD)) {
1023 auto Res = Map.insert({FD->getCanonicalDecl(), S});
1024 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~++20200917111122+b03c2b8395b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp"
, 1024, __PRETTY_FUNCTION__))
;
1025 (void)Res;
1026 if (DisplayLoadedSummaries) {
1027 llvm::errs() << "Loaded summary for: ";
1028 FD->print(llvm::errs());
1029 llvm::errs() << "\n";
1030 }
1031 return true;
1032 }
1033 }
1034 }
1035 return false;
1036 }
1037 // Add the summary with the Signature explicitly given.
1038 bool operator()(StringRef Name, Signature Sign, Summary Sum) {
1039 return operator()(Name, Sum.setSignature(Sign));
1040 }
1041 // Add several summaries for the given name.
1042 void operator()(StringRef Name, const std::vector<Summary> &Summaries) {
1043 for (const Summary &S : Summaries)
1044 operator()(Name, S);
1045 }
1046 // Add the same summary for different names with the Signature explicitly
1047 // given.
1048 void operator()(std::vector<StringRef> Names, Signature Sign, Summary Sum) {
1049 for (StringRef Name : Names)
1050 operator()(Name, Sign, Sum);
1051 }
1052 } addToFunctionSummaryMap(ACtx, FunctionSummaryMap, DisplayLoadedSummaries);
1053
1054 // Below are helpers functions to create the summaries.
1055 auto ArgumentCondition = [](ArgNo ArgN, RangeKind Kind,
1056 IntRangeVector Ranges) {
1057 return std::make_shared<RangeConstraint>(ArgN, Kind, Ranges);
1058 };
1059 auto BufferSize = [](auto... Args) {
1060 return std::make_shared<BufferSizeConstraint>(Args...);
1061 };
1062 struct {
1063 auto operator()(RangeKind Kind, IntRangeVector Ranges) {
1064 return std::make_shared<RangeConstraint>(Ret, Kind, Ranges);
1065 }
1066 auto operator()(BinaryOperator::Opcode Op, ArgNo OtherArgN) {
1067 return std::make_shared<ComparisonConstraint>(Ret, Op, OtherArgN);
1068 }
1069 } ReturnValueCondition;
1070 struct {
1071 auto operator()(RangeInt b, RangeInt e) {
1072 return IntRangeVector{std::pair<RangeInt, RangeInt>{b, e}};
1073 }
1074 auto operator()(RangeInt b, Optional<RangeInt> e) {
1075 if (e)
1076 return IntRangeVector{std::pair<RangeInt, RangeInt>{b, *e}};
1077 return IntRangeVector{};
1078 }
1079 } Range;
1080 auto SingleValue = [](RangeInt v) {
1081 return IntRangeVector{std::pair<RangeInt, RangeInt>{v, v}};
1082 };
1083 auto LessThanOrEq = BO_LE;
1084 auto NotNull = [&](ArgNo ArgN) {
1085 return std::make_shared<NotNullConstraint>(ArgN);
1086 };
1087
1088 Optional<QualType> FileTy = lookupTy("FILE");
1089 Optional<QualType> FilePtrTy = getPointerTy(FileTy);
1090 Optional<QualType> FilePtrRestrictTy = getRestrictTy(FilePtrTy);
1091
1092 // Templates for summaries that are reused by many functions.
1093 auto Read = [&](RetType R, RangeInt Max) {
1094 return Summary(ArgTypes{Irrelevant, Irrelevant, SizeTy}, RetType{R},
1095 NoEvalCall)
1096 .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)),
1097 ReturnValueCondition(WithinRange, Range(-1, Max))});
1098 };
1099 auto Getline = [&](RetType R, RangeInt Max) {
1100 return Summary(ArgTypes{Irrelevant, Irrelevant, Irrelevant}, RetType{R},
1101 NoEvalCall)
1102 .Case({ReturnValueCondition(WithinRange, {{-1, -1}, {1, Max}})});
1103 };
1104
1105 // We are finally ready to define specifications for all supported functions.
1106 //
1107 // Argument ranges should always cover all variants. If return value
1108 // is completely unknown, omit it from the respective range set.
1109 //
1110 // Every item in the list of range sets represents a particular
1111 // execution path the analyzer would need to explore once
1112 // the call is modeled - a new program state is constructed
1113 // for every range set, and each range line in the range set
1114 // corresponds to a specific constraint within this state.
1115
1116 // The isascii() family of functions.
1117 // The behavior is undefined if the value of the argument is not
1118 // representable as unsigned char or is not equal to EOF. See e.g. C99
1119 // 7.4.1.2 The isalpha function (p: 181-182).
1120 addToFunctionSummaryMap(
1121 "isalnum",
1122 Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
1123 // Boils down to isupper() or islower() or isdigit().
1124 .Case({ArgumentCondition(0U, WithinRange,
1125 {{'0', '9'}, {'A', 'Z'}, {'a', 'z'}}),
1126 ReturnValueCondition(OutOfRange, SingleValue(0))})
1127 // The locale-specific range.
1128 // No post-condition. We are completely unaware of
1129 // locale-specific return values.
1130 .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})})
1131 .Case(
1132 {ArgumentCondition(
1133 0U, OutOfRange,
1134 {{'0', '9'}, {'A', 'Z'}, {'a', 'z'}, {128, UCharRangeMax}}),
1135 ReturnValueCondition(WithinRange, SingleValue(0))})
1136 .ArgConstraint(ArgumentCondition(
1137 0U, WithinRange, {{EOFv, EOFv}, {0, UCharRangeMax}})));
1138 addToFunctionSummaryMap(
1139 "isalpha",
1140 Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
1141 .Case({ArgumentCondition(0U, WithinRange, {{'A', 'Z'}, {'a', 'z'}}),
1142 ReturnValueCondition(OutOfRange, SingleValue(0))})
1143 // The locale-specific range.
1144 .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})})
1145 .Case({ArgumentCondition(
1146 0U, OutOfRange,
1147 {{'A', 'Z'}, {'a', 'z'}, {128, UCharRangeMax}}),
1148 ReturnValueCondition(WithinRange, SingleValue(0))}));
1149 addToFunctionSummaryMap(
1150 "isascii",
1151 Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
1152 .Case({ArgumentCondition(0U, WithinRange, Range(0, 127)),
1153 ReturnValueCondition(OutOfRange, SingleValue(0))})
1154 .Case({ArgumentCondition(0U, OutOfRange, Range(0, 127)),
1155 ReturnValueCondition(WithinRange, SingleValue(0))}));
1156 addToFunctionSummaryMap(
1157 "isblank",
1158 Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
1159 .Case({ArgumentCondition(0U, WithinRange, {{'\t', '\t'}, {' ', ' '}}),
1160 ReturnValueCondition(OutOfRange, SingleValue(0))})
1161 .Case({ArgumentCondition(0U, OutOfRange, {{'\t', '\t'}, {' ', ' '}}),
1162 ReturnValueCondition(WithinRange, SingleValue(0))}));
1163 addToFunctionSummaryMap(
1164 "iscntrl",
1165 Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
1166 .Case({ArgumentCondition(0U, WithinRange, {{0, 32}, {127, 127}}),
1167 ReturnValueCondition(OutOfRange, SingleValue(0))})
1168 .Case({ArgumentCondition(0U, OutOfRange, {{0, 32}, {127, 127}}),
1169 ReturnValueCondition(WithinRange, SingleValue(0))}));
1170 addToFunctionSummaryMap(
1171 "isdigit",
1172 Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
1173 .Case({ArgumentCondition(0U, WithinRange, Range('0', '9')),
1174 ReturnValueCondition(OutOfRange, SingleValue(0))})
1175 .Case({ArgumentCondition(0U, OutOfRange, Range('0', '9')),
1176 ReturnValueCondition(WithinRange, SingleValue(0))}));
1177 addToFunctionSummaryMap(
1178 "isgraph",
1179 Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
1180 .Case({ArgumentCondition(0U, WithinRange, Range(33, 126)),
1181 ReturnValueCondition(OutOfRange, SingleValue(0))})
1182 .Case({ArgumentCondition(0U, OutOfRange, Range(33, 126)),
1183 ReturnValueCondition(WithinRange, SingleValue(0))}));
1184 addToFunctionSummaryMap(
1185 "islower",
1186 Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
1187 // Is certainly lowercase.
1188 .Case({ArgumentCondition(0U, WithinRange, Range('a', 'z')),
1189 ReturnValueCondition(OutOfRange, SingleValue(0))})
1190 // Is ascii but not lowercase.
1191 .Case({ArgumentCondition(0U, WithinRange, Range(0, 127)),
1192 ArgumentCondition(0U, OutOfRange, Range('a', 'z')),
1193 ReturnValueCondition(WithinRange, SingleValue(0))})
1194 // The locale-specific range.
1195 .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})})
1196 // Is not an unsigned char.
1197 .Case({ArgumentCondition(0U, OutOfRange, Range(0, UCharRangeMax)),
1198 ReturnValueCondition(WithinRange, SingleValue(0))}));
1199 addToFunctionSummaryMap(
1200 "isprint",
1201 Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
1202 .Case({ArgumentCondition(0U, WithinRange, Range(32, 126)),
1203 ReturnValueCondition(OutOfRange, SingleValue(0))})
1204 .Case({ArgumentCondition(0U, OutOfRange, Range(32, 126)),
1205 ReturnValueCondition(WithinRange, SingleValue(0))}));
1206 addToFunctionSummaryMap(
1207 "ispunct",
1208 Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
1209 .Case({ArgumentCondition(
1210 0U, WithinRange,
1211 {{'!', '/'}, {':', '@'}, {'[', '`'}, {'{', '~'}}),
1212 ReturnValueCondition(OutOfRange, SingleValue(0))})
1213 .Case({ArgumentCondition(
1214 0U, OutOfRange,
1215 {{'!', '/'}, {':', '@'}, {'[', '`'}, {'{', '~'}}),
1216 ReturnValueCondition(WithinRange, SingleValue(0))}));
1217 addToFunctionSummaryMap(
1218 "isspace",
1219 Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
1220 // Space, '\f', '\n', '\r', '\t', '\v'.
1221 .Case({ArgumentCondition(0U, WithinRange, {{9, 13}, {' ', ' '}}),
1222 ReturnValueCondition(OutOfRange, SingleValue(0))})
1223 // The locale-specific range.
1224 .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})})
1225 .Case({ArgumentCondition(0U, OutOfRange,
1226 {{9, 13}, {' ', ' '}, {128, UCharRangeMax}}),
1227 ReturnValueCondition(WithinRange, SingleValue(0))}));
1228 addToFunctionSummaryMap(
1229 "isupper",
1230 Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
1231 // Is certainly uppercase.
1232 .Case({ArgumentCondition(0U, WithinRange, Range('A', 'Z')),
1233 ReturnValueCondition(OutOfRange, SingleValue(0))})
1234 // The locale-specific range.
1235 .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})})
1236 // Other.
1237 .Case({ArgumentCondition(0U, OutOfRange,
1238 {{'A', 'Z'}, {128, UCharRangeMax}}),
1239 ReturnValueCondition(WithinRange, SingleValue(0))}));
1240 addToFunctionSummaryMap(
1241 "isxdigit",
1242 Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
1243 .Case({ArgumentCondition(0U, WithinRange,
1244 {{'0', '9'}, {'A', 'F'}, {'a', 'f'}}),
1245 ReturnValueCondition(OutOfRange, SingleValue(0))})
1246 .Case({ArgumentCondition(0U, OutOfRange,
1247 {{'0', '9'}, {'A', 'F'}, {'a', 'f'}}),
1248 ReturnValueCondition(WithinRange, SingleValue(0))}));
1249 addToFunctionSummaryMap(
1250 "toupper", Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
1251 .ArgConstraint(ArgumentCondition(
1252 0U, WithinRange, {{EOFv, EOFv}, {0, UCharRangeMax}})));
1253 addToFunctionSummaryMap(
1254 "tolower", Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
1255 .ArgConstraint(ArgumentCondition(
1256 0U, WithinRange, {{EOFv, EOFv}, {0, UCharRangeMax}})));
1257 addToFunctionSummaryMap(
1258 "toascii", Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
1259 .ArgConstraint(ArgumentCondition(
1260 0U, WithinRange, {{EOFv, EOFv}, {0, UCharRangeMax}})));
1261
1262 // The getc() family of functions that returns either a char or an EOF.
1263 addToFunctionSummaryMap(
1264 {"getc", "fgetc"}, Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
1265 Summary(NoEvalCall)
1266 .Case({ReturnValueCondition(WithinRange,
1267 {{EOFv, EOFv}, {0, UCharRangeMax}})}));
1268 addToFunctionSummaryMap(
1269 "getchar", Summary(ArgTypes{}, RetType{IntTy}, NoEvalCall)
1270 .Case({ReturnValueCondition(
1271 WithinRange, {{EOFv, EOFv}, {0, UCharRangeMax}})}));
1272
1273 // read()-like functions that never return more than buffer size.
1274 auto FreadSummary =
1275 Summary(NoEvalCall)
1276 .Case({
1277 ReturnValueCondition(LessThanOrEq, ArgNo(2)),
1278 })
1279 .ArgConstraint(NotNull(ArgNo(0)))
1280 .ArgConstraint(NotNull(ArgNo(3)))
1281 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1),
1282 /*BufSizeMultiplier=*/ArgNo(2)));
1283
1284 // size_t fread(void *restrict ptr, size_t size, size_t nitems,
1285 // FILE *restrict stream);
1286 addToFunctionSummaryMap(
1287 "fread",
1288 Signature(ArgTypes{VoidPtrRestrictTy, SizeTy, SizeTy, FilePtrRestrictTy},
1289 RetType{SizeTy}),
1290 FreadSummary);
1291 // size_t fwrite(const void *restrict ptr, size_t size, size_t nitems,
1292 // FILE *restrict stream);
1293 addToFunctionSummaryMap("fwrite",
1294 Signature(ArgTypes{ConstVoidPtrRestrictTy, SizeTy,
1295 SizeTy, FilePtrRestrictTy},
1296 RetType{SizeTy}),
1297 FreadSummary);
1298
1299 // We are not sure how ssize_t is defined on every platform, so we
1300 // provide three variants that should cover common cases.
1301 // FIXME Use lookupTy("ssize_t") instead of the `Read` lambda.
1302 // FIXME these are actually defined by POSIX and not by the C standard, we
1303 // should handle them together with the rest of the POSIX functions.
1304 addToFunctionSummaryMap("read", {Read(IntTy, IntMax), Read(LongTy, LongMax),
1305 Read(LongLongTy, LongLongMax)});
1306 addToFunctionSummaryMap("write", {Read(IntTy, IntMax), Read(LongTy, LongMax),
1307 Read(LongLongTy, LongLongMax)});
1308
1309 // getline()-like functions either fail or read at least the delimiter.
1310 // FIXME Use lookupTy("ssize_t") instead of the `Getline` lambda.
1311 // FIXME these are actually defined by POSIX and not by the C standard, we
1312 // should handle them together with the rest of the POSIX functions.
1313 addToFunctionSummaryMap("getline",
1314 {Getline(IntTy, IntMax), Getline(LongTy, LongMax),
1315 Getline(LongLongTy, LongLongMax)});
1316 // FIXME getdelim's signature is different than getline's!
1317 addToFunctionSummaryMap("getdelim",
1318 {Getline(IntTy, IntMax), Getline(LongTy, LongMax),
1319 Getline(LongLongTy, LongLongMax)});
1320
1321 if (ModelPOSIX) {
1322
1323 // long a64l(const char *str64);
1324 addToFunctionSummaryMap(
1325 "a64l", Summary(ArgTypes{ConstCharPtrTy}, RetType{LongTy}, NoEvalCall)
1326 .ArgConstraint(NotNull(ArgNo(0))));
1327
1328 // char *l64a(long value);
1329 addToFunctionSummaryMap(
1330 "l64a", Summary(ArgTypes{LongTy}, RetType{CharPtrTy}, NoEvalCall)
1331 .ArgConstraint(
1332 ArgumentCondition(0, WithinRange, Range(0, LongMax))));
1333
1334 // int access(const char *pathname, int amode);
1335 addToFunctionSummaryMap("access", Summary(ArgTypes{ConstCharPtrTy, IntTy},
1336 RetType{IntTy}, NoEvalCall)
1337 .ArgConstraint(NotNull(ArgNo(0))));
1338
1339 // int faccessat(int dirfd, const char *pathname, int mode, int flags);
1340 addToFunctionSummaryMap(
1341 "faccessat", Summary(ArgTypes{IntTy, ConstCharPtrTy, IntTy, IntTy},
1342 RetType{IntTy}, NoEvalCall)
1343 .ArgConstraint(NotNull(ArgNo(1))));
1344
1345 // int dup(int fildes);
1346 addToFunctionSummaryMap(
1347 "dup", Summary(ArgTypes{IntTy}, RetType{IntTy}, NoEvalCall)
1348 .ArgConstraint(
1349 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
1350
1351 // int dup2(int fildes1, int filedes2);
1352 addToFunctionSummaryMap(
1353 "dup2",
1354 Summary(ArgTypes{IntTy, IntTy}, RetType{IntTy}, NoEvalCall)
1355 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
1356 .ArgConstraint(
1357 ArgumentCondition(1, WithinRange, Range(0, IntMax))));
1358
1359 // int fdatasync(int fildes);
1360 addToFunctionSummaryMap(
1361 "fdatasync", Summary(ArgTypes{IntTy}, RetType{IntTy}, NoEvalCall)
1362 .ArgConstraint(ArgumentCondition(0, WithinRange,
1363 Range(0, IntMax))));
1364
1365 // int fnmatch(const char *pattern, const char *string, int flags);
1366 addToFunctionSummaryMap(
1367 "fnmatch", Summary(ArgTypes{ConstCharPtrTy, ConstCharPtrTy, IntTy},
1368 RetType{IntTy}, EvalCallAsPure)
1369 .ArgConstraint(NotNull(ArgNo(0)))
1370 .ArgConstraint(NotNull(ArgNo(1))));
1371
1372 // int fsync(int fildes);
1373 addToFunctionSummaryMap(
1374 "fsync", Summary(ArgTypes{IntTy}, RetType{IntTy}, NoEvalCall)
1375 .ArgConstraint(
1376 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
1377
1378 Optional<QualType> Off_tTy = lookupTy("off_t");
1379
1380 // int truncate(const char *path, off_t length);
1381 addToFunctionSummaryMap(
1382 "truncate",
1383 Summary(ArgTypes{ConstCharPtrTy, Off_tTy}, RetType{IntTy}, NoEvalCall)
1384 .ArgConstraint(NotNull(ArgNo(0))));
1385
1386 // int symlink(const char *oldpath, const char *newpath);
1387 addToFunctionSummaryMap("symlink",
1388 Summary(ArgTypes{ConstCharPtrTy, ConstCharPtrTy},
1389 RetType{IntTy}, NoEvalCall)
1390 .ArgConstraint(NotNull(ArgNo(0)))
1391 .ArgConstraint(NotNull(ArgNo(1))));
1392
1393 // int symlinkat(const char *oldpath, int newdirfd, const char *newpath);
1394 addToFunctionSummaryMap(
1395 "symlinkat",
1396 Summary(ArgTypes{ConstCharPtrTy, IntTy, ConstCharPtrTy}, RetType{IntTy},
1397 NoEvalCall)
1398 .ArgConstraint(NotNull(ArgNo(0)))
1399 .ArgConstraint(ArgumentCondition(1, WithinRange, Range(0, IntMax)))
1400 .ArgConstraint(NotNull(ArgNo(2))));
1401
1402 // int lockf(int fd, int cmd, off_t len);
1403 addToFunctionSummaryMap(
1404 "lockf",
1405 Summary(ArgTypes{IntTy, IntTy, Off_tTy}, RetType{IntTy}, NoEvalCall)
1406 .ArgConstraint(
1407 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
1408
1409 Optional<QualType> Mode_tTy = lookupTy("mode_t");
1410
1411 // int creat(const char *pathname, mode_t mode);
1412 addToFunctionSummaryMap("creat", Summary(ArgTypes{ConstCharPtrTy, Mode_tTy},
1413 RetType{IntTy}, NoEvalCall)
1414 .ArgConstraint(NotNull(ArgNo(0))));
1415
1416 // unsigned int sleep(unsigned int seconds);
1417 addToFunctionSummaryMap(
1418 "sleep",
1419 Summary(ArgTypes{UnsignedIntTy}, RetType{UnsignedIntTy}, NoEvalCall)
1420 .ArgConstraint(
1421 ArgumentCondition(0, WithinRange, Range(0, UnsignedIntMax))));
1422
1423 Optional<QualType> DirTy = lookupTy("DIR");
1424 Optional<QualType> DirPtrTy = getPointerTy(DirTy);
1425
1426 // int dirfd(DIR *dirp);
1427 addToFunctionSummaryMap(
1428 "dirfd", Summary(ArgTypes{DirPtrTy}, RetType{IntTy}, NoEvalCall)
1429 .ArgConstraint(NotNull(ArgNo(0))));
1430
1431 // unsigned int alarm(unsigned int seconds);
1432 addToFunctionSummaryMap(
1433 "alarm",
1434 Summary(ArgTypes{UnsignedIntTy}, RetType{UnsignedIntTy}, NoEvalCall)
1435 .ArgConstraint(
1436 ArgumentCondition(0, WithinRange, Range(0, UnsignedIntMax))));
1437
1438 // int closedir(DIR *dir);
1439 addToFunctionSummaryMap(
1440 "closedir", Summary(ArgTypes{DirPtrTy}, RetType{IntTy}, NoEvalCall)
1441 .ArgConstraint(NotNull(ArgNo(0))));
1442
1443 // char *strdup(const char *s);
1444 addToFunctionSummaryMap("strdup", Summary(ArgTypes{ConstCharPtrTy},
1445 RetType{CharPtrTy}, NoEvalCall)
1446 .ArgConstraint(NotNull(ArgNo(0))));
1447
1448 // char *strndup(const char *s, size_t n);
1449 addToFunctionSummaryMap(
1450 "strndup", Summary(ArgTypes{ConstCharPtrTy, SizeTy}, RetType{CharPtrTy},
1451 NoEvalCall)
1452 .ArgConstraint(NotNull(ArgNo(0)))
1453 .ArgConstraint(ArgumentCondition(1, WithinRange,
1454 Range(0, SizeMax))));
1455
1456 // wchar_t *wcsdup(const wchar_t *s);
1457 addToFunctionSummaryMap("wcsdup", Summary(ArgTypes{ConstWchar_tPtrTy},
1458 RetType{Wchar_tPtrTy}, NoEvalCall)
1459 .ArgConstraint(NotNull(ArgNo(0))));
1460
1461 // int mkstemp(char *template);
1462 addToFunctionSummaryMap(
1463 "mkstemp", Summary(ArgTypes{CharPtrTy}, RetType{IntTy}, NoEvalCall)
1464 .ArgConstraint(NotNull(ArgNo(0))));
1465
1466 // char *mkdtemp(char *template);
1467 addToFunctionSummaryMap(
1468 "mkdtemp", Summary(ArgTypes{CharPtrTy}, RetType{CharPtrTy}, NoEvalCall)
1469 .ArgConstraint(NotNull(ArgNo(0))));
1470
1471 // char *getcwd(char *buf, size_t size);
1472 addToFunctionSummaryMap(
1473 "getcwd",
1474 Summary(ArgTypes{CharPtrTy, SizeTy}, RetType{CharPtrTy}, NoEvalCall)
1475 .ArgConstraint(
1476 ArgumentCondition(1, WithinRange, Range(0, SizeMax))));
1477
1478 // int mkdir(const char *pathname, mode_t mode);
1479 addToFunctionSummaryMap("mkdir", Summary(ArgTypes{ConstCharPtrTy, Mode_tTy},
1480 RetType{IntTy}, NoEvalCall)
1481 .ArgConstraint(NotNull(ArgNo(0))));
1482
1483 // int mkdirat(int dirfd, const char *pathname, mode_t mode);
1484 addToFunctionSummaryMap("mkdirat",
1485 Summary(ArgTypes{IntTy, ConstCharPtrTy, Mode_tTy},
1486 RetType{IntTy}, NoEvalCall)
1487 .ArgConstraint(NotNull(ArgNo(1))));
1488
1489 Optional<QualType> Dev_tTy = lookupTy("dev_t");
1490
1491 // int mknod(const char *pathname, mode_t mode, dev_t dev);
1492 addToFunctionSummaryMap("mknod",
1493 Summary(ArgTypes{ConstCharPtrTy, Mode_tTy, Dev_tTy},
1494 RetType{IntTy}, NoEvalCall)
1495 .ArgConstraint(NotNull(ArgNo(0))));
1496
1497 // int mknodat(int dirfd, const char *pathname, mode_t mode, dev_t dev);
1498 addToFunctionSummaryMap(
1499 "mknodat", Summary(ArgTypes{IntTy, ConstCharPtrTy, Mode_tTy, Dev_tTy},
1500 RetType{IntTy}, NoEvalCall)
1501 .ArgConstraint(NotNull(ArgNo(1))));
1502
1503 // int chmod(const char *path, mode_t mode);
1504 addToFunctionSummaryMap("chmod", Summary(ArgTypes{ConstCharPtrTy, Mode_tTy},
1505 RetType{IntTy}, NoEvalCall)
1506 .ArgConstraint(NotNull(ArgNo(0))));
1507
1508 // int fchmodat(int dirfd, const char *pathname, mode_t mode, int flags);
1509 addToFunctionSummaryMap(
1510 "fchmodat",
1511 Summary(ArgTypes{IntTy, ConstCharPtrTy, Mode_tTy, IntTy},
1512 RetType{IntTy}, NoEvalCall)
1513 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
1514 .ArgConstraint(NotNull(ArgNo(1))));
1515
1516 // int fchmod(int fildes, mode_t mode);
1517 addToFunctionSummaryMap(
1518 "fchmod", Summary(ArgTypes{IntTy, Mode_tTy}, RetType{IntTy}, NoEvalCall)
1519 .ArgConstraint(
1520 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
1521
1522 Optional<QualType> Uid_tTy = lookupTy("uid_t");
1523 Optional<QualType> Gid_tTy = lookupTy("gid_t");
1524
1525 // int fchownat(int dirfd, const char *pathname, uid_t owner, gid_t group,
1526 // int flags);
1527 addToFunctionSummaryMap(
1528 "fchownat",
1529 Summary(ArgTypes{IntTy, ConstCharPtrTy, Uid_tTy, Gid_tTy, IntTy},
1530 RetType{IntTy}, NoEvalCall)
1531 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
1532 .ArgConstraint(NotNull(ArgNo(1))));
1533
1534 // int chown(const char *path, uid_t owner, gid_t group);
1535 addToFunctionSummaryMap("chown",
1536 Summary(ArgTypes{ConstCharPtrTy, Uid_tTy, Gid_tTy},
1537 RetType{IntTy}, NoEvalCall)
1538 .ArgConstraint(NotNull(ArgNo(0))));
1539
1540 // int lchown(const char *path, uid_t owner, gid_t group);
1541 addToFunctionSummaryMap("lchown",
1542 Summary(ArgTypes{ConstCharPtrTy, Uid_tTy, Gid_tTy},
1543 RetType{IntTy}, NoEvalCall)
1544 .ArgConstraint(NotNull(ArgNo(0))));
1545
1546 // int fchown(int fildes, uid_t owner, gid_t group);
1547 addToFunctionSummaryMap(
1548 "fchown",
1549 Summary(ArgTypes{IntTy, Uid_tTy, Gid_tTy}, RetType{IntTy}, NoEvalCall)
1550 .ArgConstraint(
1551 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
1552
1553 // int rmdir(const char *pathname);
1554 addToFunctionSummaryMap(
1555 "rmdir", Summary(ArgTypes{ConstCharPtrTy}, RetType{IntTy}, NoEvalCall)
1556 .ArgConstraint(NotNull(ArgNo(0))));
1557
1558 // int chdir(const char *path);
1559 addToFunctionSummaryMap(
1560 "chdir", Summary(ArgTypes{ConstCharPtrTy}, RetType{IntTy}, NoEvalCall)
1561 .ArgConstraint(NotNull(ArgNo(0))));
1562
1563 // int link(const char *oldpath, const char *newpath);
1564 addToFunctionSummaryMap("link",
1565 Summary(ArgTypes{ConstCharPtrTy, ConstCharPtrTy},
1566 RetType{IntTy}, 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 Summary(ArgTypes{IntTy, ConstCharPtrTy, IntTy, ConstCharPtrTy, IntTy},
1575 RetType{IntTy}, NoEvalCall)
1576 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
1577 .ArgConstraint(NotNull(ArgNo(1)))
1578 .ArgConstraint(ArgumentCondition(2, WithinRange, Range(0, IntMax)))
1579 .ArgConstraint(NotNull(ArgNo(3))));
1580
1581 // int unlink(const char *pathname);
1582 addToFunctionSummaryMap(
1583 "unlink", Summary(ArgTypes{ConstCharPtrTy}, RetType{IntTy}, NoEvalCall)
1584 .ArgConstraint(NotNull(ArgNo(0))));
1585
1586 // int unlinkat(int fd, const char *path, int flag);
1587 addToFunctionSummaryMap(
1588 "unlinkat",
1589 Summary(ArgTypes{IntTy, ConstCharPtrTy, IntTy}, RetType{IntTy},
1590 NoEvalCall)
1591 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
1592 .ArgConstraint(NotNull(ArgNo(1))));
1593
1594 Optional<QualType> StructStatTy = lookupTy("stat");
1595 Optional<QualType> StructStatPtrTy = getPointerTy(StructStatTy);
1596 Optional<QualType> StructStatPtrRestrictTy = getRestrictTy(StructStatPtrTy);
1597
1598 // int fstat(int fd, struct stat *statbuf);
1599 addToFunctionSummaryMap(
1600 "fstat",
1601 Summary(ArgTypes{IntTy, StructStatPtrTy}, RetType{IntTy}, NoEvalCall)
1602 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
1603 .ArgConstraint(NotNull(ArgNo(1))));
1604
1605 // int stat(const char *restrict path, struct stat *restrict buf);
1606 addToFunctionSummaryMap("stat", Summary(ArgTypes{ConstCharPtrRestrictTy,
1607 StructStatPtrRestrictTy},
1608 RetType{IntTy}, NoEvalCall)
1609 .ArgConstraint(NotNull(ArgNo(0)))
1610 .ArgConstraint(NotNull(ArgNo(1))));
1611
1612 // int lstat(const char *restrict path, struct stat *restrict buf);
1613 addToFunctionSummaryMap("lstat", Summary(ArgTypes{ConstCharPtrRestrictTy,
1614 StructStatPtrRestrictTy},
1615 RetType{IntTy}, NoEvalCall)
1616 .ArgConstraint(NotNull(ArgNo(0)))
1617 .ArgConstraint(NotNull(ArgNo(1))));
1618
1619 // int fstatat(int fd, const char *restrict path,
1620 // struct stat *restrict buf, int flag);
1621 addToFunctionSummaryMap(
1622 "fstatat",
1623 Summary(ArgTypes{IntTy, ConstCharPtrRestrictTy, StructStatPtrRestrictTy,
1624 IntTy},
1625 RetType{IntTy}, NoEvalCall)
1626 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
1627 .ArgConstraint(NotNull(ArgNo(1)))
1628 .ArgConstraint(NotNull(ArgNo(2))));
1629
1630 // DIR *opendir(const char *name);
1631 addToFunctionSummaryMap("opendir", Summary(ArgTypes{ConstCharPtrTy},
1632 RetType{DirPtrTy}, NoEvalCall)
1633 .ArgConstraint(NotNull(ArgNo(0))));
1634
1635 // DIR *fdopendir(int fd);
1636 addToFunctionSummaryMap(
1637 "fdopendir", Summary(ArgTypes{IntTy}, RetType{DirPtrTy}, NoEvalCall)
1638 .ArgConstraint(ArgumentCondition(0, WithinRange,
1639 Range(0, IntMax))));
1640
1641 // int isatty(int fildes);
1642 addToFunctionSummaryMap(
1643 "isatty", Summary(ArgTypes{IntTy}, RetType{IntTy}, NoEvalCall)
1644 .ArgConstraint(
1645 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
1646
1647 // FILE *popen(const char *command, const char *type);
1648 addToFunctionSummaryMap("popen",
1649 Summary(ArgTypes{ConstCharPtrTy, ConstCharPtrTy},
1650 RetType{FilePtrTy}, NoEvalCall)
1651 .ArgConstraint(NotNull(ArgNo(0)))
1652 .ArgConstraint(NotNull(ArgNo(1))));
1653
1654 // int pclose(FILE *stream);
1655 addToFunctionSummaryMap(
1656 "pclose", Summary(ArgTypes{FilePtrTy}, RetType{IntTy}, NoEvalCall)
1657 .ArgConstraint(NotNull(ArgNo(0))));
1658
1659 // int close(int fildes);
1660 addToFunctionSummaryMap(
1661 "close", Summary(ArgTypes{IntTy}, RetType{IntTy}, NoEvalCall)
1662 .ArgConstraint(
1663 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
1664
1665 // long fpathconf(int fildes, int name);
1666 addToFunctionSummaryMap(
1667 "fpathconf",
1668 Summary(ArgTypes{IntTy, IntTy}, RetType{LongTy}, NoEvalCall)
1669 .ArgConstraint(
1670 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
1671
1672 // long pathconf(const char *path, int name);
1673 addToFunctionSummaryMap("pathconf", Summary(ArgTypes{ConstCharPtrTy, IntTy},
1674 RetType{LongTy}, NoEvalCall)
1675 .ArgConstraint(NotNull(ArgNo(0))));
1676
1677 // FILE *fdopen(int fd, const char *mode);
1678 addToFunctionSummaryMap(
1679 "fdopen",
1680 Summary(ArgTypes{IntTy, ConstCharPtrTy}, RetType{FilePtrTy}, NoEvalCall)
1681 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
1682 .ArgConstraint(NotNull(ArgNo(1))));
1683
1684 // void rewinddir(DIR *dir);
1685 addToFunctionSummaryMap(
1686 "rewinddir", Summary(ArgTypes{DirPtrTy}, RetType{VoidTy}, NoEvalCall)
1687 .ArgConstraint(NotNull(ArgNo(0))));
1688
1689 // void seekdir(DIR *dirp, long loc);
1690 addToFunctionSummaryMap("seekdir", Summary(ArgTypes{DirPtrTy, LongTy},
1691 RetType{VoidTy}, NoEvalCall)
1692 .ArgConstraint(NotNull(ArgNo(0))));
1693
1694 // int rand_r(unsigned int *seedp);
1695 addToFunctionSummaryMap("rand_r", Summary(ArgTypes{UnsignedIntPtrTy},
1696 RetType{IntTy}, NoEvalCall)
1697 .ArgConstraint(NotNull(ArgNo(0))));
1698
1699 // int fileno(FILE *stream);
1700 addToFunctionSummaryMap(
1701 "fileno", Summary(ArgTypes{FilePtrTy}, RetType{IntTy}, NoEvalCall)
1702 .ArgConstraint(NotNull(ArgNo(0))));
1703
1704 // int fseeko(FILE *stream, off_t offset, int whence);
1705 addToFunctionSummaryMap(
1706 "fseeko",
1707 Summary(ArgTypes{FilePtrTy, Off_tTy, IntTy}, RetType{IntTy}, NoEvalCall)
1708 .ArgConstraint(NotNull(ArgNo(0))));
1709
1710 // off_t ftello(FILE *stream);
1711 addToFunctionSummaryMap(
1712 "ftello", Summary(ArgTypes{FilePtrTy}, RetType{Off_tTy}, NoEvalCall)
1713 .ArgConstraint(NotNull(ArgNo(0))));
1714
1715 Optional<RangeInt> Off_tMax = getMaxValue(Off_tTy);
1716 // void *mmap(void *addr, size_t length, int prot, int flags, int fd,
1717 // off_t offset);
1718 addToFunctionSummaryMap(
1719 "mmap",
1720 Summary(ArgTypes{VoidPtrTy, SizeTy, IntTy, IntTy, IntTy, Off_tTy},
1721 RetType{VoidPtrTy}, NoEvalCall)
1722 .ArgConstraint(ArgumentCondition(1, WithinRange, Range(1, SizeMax)))
1723 .ArgConstraint(
1724 ArgumentCondition(4, WithinRange, Range(0, Off_tMax))));
1725
1726 Optional<QualType> Off64_tTy = lookupTy("off64_t");
1727 Optional<RangeInt> Off64_tMax = getMaxValue(Off_tTy);
1728 // void *mmap64(void *addr, size_t length, int prot, int flags, int fd,
1729 // off64_t offset);
1730 addToFunctionSummaryMap(
1731 "mmap64",
1732 Summary(ArgTypes{VoidPtrTy, SizeTy, IntTy, IntTy, IntTy, Off64_tTy},
1733 RetType{VoidPtrTy}, NoEvalCall)
1734 .ArgConstraint(ArgumentCondition(1, WithinRange, Range(1, SizeMax)))
1735 .ArgConstraint(
1736 ArgumentCondition(4, WithinRange, Range(0, Off64_tMax))));
1737
1738 // int pipe(int fildes[2]);
1739 addToFunctionSummaryMap(
1740 "pipe", Summary(ArgTypes{IntPtrTy}, RetType{IntTy}, NoEvalCall)
1741 .ArgConstraint(NotNull(ArgNo(0))));
1742
1743 // off_t lseek(int fildes, off_t offset, int whence);
1744 addToFunctionSummaryMap(
1745 "lseek",
1746 Summary(ArgTypes{IntTy, Off_tTy, IntTy}, RetType{Off_tTy}, NoEvalCall)
1747 .ArgConstraint(
1748 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
1749
1750 Optional<QualType> Ssize_tTy = lookupTy("ssize_t");
1751
1752 // ssize_t readlink(const char *restrict path, char *restrict buf,
1753 // size_t bufsize);
1754 addToFunctionSummaryMap(
1755 "readlink",
1756 Summary(ArgTypes{ConstCharPtrRestrictTy, CharPtrRestrictTy, SizeTy},
1757 RetType{Ssize_tTy}, NoEvalCall)
1758 .ArgConstraint(NotNull(ArgNo(0)))
1759 .ArgConstraint(NotNull(ArgNo(1)))
1760 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
1761 /*BufSize=*/ArgNo(2)))
1762 .ArgConstraint(
1763 ArgumentCondition(2, WithinRange, Range(0, SizeMax))));
1764
1765 // ssize_t readlinkat(int fd, const char *restrict path,
1766 // char *restrict buf, size_t bufsize);
1767 addToFunctionSummaryMap(
1768 "readlinkat",
1769 Summary(
1770 ArgTypes{IntTy, ConstCharPtrRestrictTy, CharPtrRestrictTy, SizeTy},
1771 RetType{Ssize_tTy}, NoEvalCall)
1772 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
1773 .ArgConstraint(NotNull(ArgNo(1)))
1774 .ArgConstraint(NotNull(ArgNo(2)))
1775 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(2),
1776 /*BufSize=*/ArgNo(3)))
1777 .ArgConstraint(
1778 ArgumentCondition(3, WithinRange, Range(0, SizeMax))));
1779
1780 // int renameat(int olddirfd, const char *oldpath, int newdirfd, const char
1781 // *newpath);
1782 addToFunctionSummaryMap("renameat", Summary(ArgTypes{IntTy, ConstCharPtrTy,
1783 IntTy, ConstCharPtrTy},
1784 RetType{IntTy}, NoEvalCall)
1785 .ArgConstraint(NotNull(ArgNo(1)))
1786 .ArgConstraint(NotNull(ArgNo(3))));
1787
1788 // char *realpath(const char *restrict file_name,
1789 // char *restrict resolved_name);
1790 addToFunctionSummaryMap(
1791 "realpath", Summary(ArgTypes{ConstCharPtrRestrictTy, CharPtrRestrictTy},
1792 RetType{CharPtrTy}, NoEvalCall)
1793 .ArgConstraint(NotNull(ArgNo(0))));
1794
1795 QualType CharPtrConstPtr = getPointerTy(getConstTy(CharPtrTy));
1796
1797 // int execv(const char *path, char *const argv[]);
1798 addToFunctionSummaryMap("execv",
1799 Summary(ArgTypes{ConstCharPtrTy, CharPtrConstPtr},
1800 RetType{IntTy}, NoEvalCall)
1801 .ArgConstraint(NotNull(ArgNo(0))));
1802
1803 // int execvp(const char *file, char *const argv[]);
1804 addToFunctionSummaryMap("execvp",
1805 Summary(ArgTypes{ConstCharPtrTy, CharPtrConstPtr},
1806 RetType{IntTy}, NoEvalCall)
1807 .ArgConstraint(NotNull(ArgNo(0))));
1808
1809 // int getopt(int argc, char * const argv[], const char *optstring);
1810 addToFunctionSummaryMap(
1811 "getopt",
1812 Summary(ArgTypes{IntTy, CharPtrConstPtr, ConstCharPtrTy},
1813 RetType{IntTy}, NoEvalCall)
1814 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
1815 .ArgConstraint(NotNull(ArgNo(1)))
1816 .ArgConstraint(NotNull(ArgNo(2))));
1817
1818 Optional<QualType> StructSockaddrTy = lookupTy("sockaddr");
1819 Optional<QualType> StructSockaddrPtrTy = getPointerTy(StructSockaddrTy);
1820 Optional<QualType> ConstStructSockaddrPtrTy =
1821 getPointerTy(getConstTy(StructSockaddrTy));
1822 Optional<QualType> StructSockaddrPtrRestrictTy =
1823 getRestrictTy(StructSockaddrPtrTy);
1824 Optional<QualType> ConstStructSockaddrPtrRestrictTy =
1825 getRestrictTy(ConstStructSockaddrPtrTy);
1826 Optional<QualType> Socklen_tTy = lookupTy("socklen_t");
1827 Optional<QualType> Socklen_tPtrTy = getPointerTy(Socklen_tTy);
1828 Optional<QualType> Socklen_tPtrRestrictTy = getRestrictTy(Socklen_tPtrTy);
1829 Optional<RangeInt> Socklen_tMax = getMaxValue(Socklen_tTy);
1830
1831 // In 'socket.h' of some libc implementations with C99, sockaddr parameter
1832 // is a transparent union of the underlying sockaddr_ family of pointers
1833 // instead of being a pointer to struct sockaddr. In these cases, the
1834 // standardized signature will not match, thus we try to match with another
1835 // signature that has the joker Irrelevant type. We also remove those
1836 // constraints which require pointer types for the sockaddr param.
1837 auto Accept =
1838 Summary(NoEvalCall)
1839 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)));
1840 if (!addToFunctionSummaryMap(
1841 "accept",
1842 // int accept(int socket, struct sockaddr *restrict address,
1843 // socklen_t *restrict address_len);
1844 Signature(ArgTypes{IntTy, StructSockaddrPtrRestrictTy,
1845 Socklen_tPtrRestrictTy},
1846 RetType{IntTy}),
1847 Accept))
1848 addToFunctionSummaryMap(
1849 "accept",
1850 Signature(ArgTypes{IntTy, Irrelevant, Socklen_tPtrRestrictTy},
1851 RetType{IntTy}),
1852 Accept);
1853
1854 // int bind(int socket, const struct sockaddr *address, socklen_t
1855 // address_len);
1856 if (!addToFunctionSummaryMap(
1857 "bind",
1858 Summary(ArgTypes{IntTy, ConstStructSockaddrPtrTy, Socklen_tTy},
1859 RetType{IntTy}, NoEvalCall)
1860 .ArgConstraint(
1861 ArgumentCondition(0, WithinRange, Range(0, IntMax)))
1862 .ArgConstraint(NotNull(ArgNo(1)))
1863 .ArgConstraint(
1864 BufferSize(/*Buffer=*/ArgNo(1), /*BufSize=*/ArgNo(2)))
1865 .ArgConstraint(
1866 ArgumentCondition(2, WithinRange, Range(0, Socklen_tMax)))))
1867 // Do not add constraints on sockaddr.
1868 addToFunctionSummaryMap(
1869 "bind", Summary(ArgTypes{IntTy, Irrelevant, Socklen_tTy},
1870 RetType{IntTy}, NoEvalCall)
1871 .ArgConstraint(
1872 ArgumentCondition(0, WithinRange, Range(0, IntMax)))
1873 .ArgConstraint(ArgumentCondition(
1874 2, WithinRange, Range(0, Socklen_tMax))));
1875
1876 // int getpeername(int socket, struct sockaddr *restrict address,
1877 // socklen_t *restrict address_len);
1878 if (!addToFunctionSummaryMap(
1879 "getpeername", Summary(ArgTypes{IntTy, StructSockaddrPtrRestrictTy,
1880 Socklen_tPtrRestrictTy},
1881 RetType{IntTy}, NoEvalCall)
1882 .ArgConstraint(ArgumentCondition(
1883 0, WithinRange, Range(0, IntMax)))
1884 .ArgConstraint(NotNull(ArgNo(1)))
1885 .ArgConstraint(NotNull(ArgNo(2)))))
1886 addToFunctionSummaryMap(
1887 "getpeername",
1888 Summary(ArgTypes{IntTy, Irrelevant, Socklen_tPtrRestrictTy},
1889 RetType{IntTy}, NoEvalCall)
1890 .ArgConstraint(
1891 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
1892
1893 // int getsockname(int socket, struct sockaddr *restrict address,
1894 // socklen_t *restrict address_len);
1895 if (!addToFunctionSummaryMap(
1896 "getsockname", Summary(ArgTypes{IntTy, StructSockaddrPtrRestrictTy,
1897 Socklen_tPtrRestrictTy},
1898 RetType{IntTy}, NoEvalCall)
1899 .ArgConstraint(ArgumentCondition(
1900 0, WithinRange, Range(0, IntMax)))
1901 .ArgConstraint(NotNull(ArgNo(1)))
1902 .ArgConstraint(NotNull(ArgNo(2)))))
1903 addToFunctionSummaryMap(
1904 "getsockname",
1905 Summary(ArgTypes{IntTy, Irrelevant, Socklen_tPtrRestrictTy},
1906 RetType{IntTy}, NoEvalCall)
1907 .ArgConstraint(
1908 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
1909
1910 // int connect(int socket, const struct sockaddr *address, socklen_t
1911 // address_len);
1912 if (!addToFunctionSummaryMap(
1913 "connect",
1914 Summary(ArgTypes{IntTy, ConstStructSockaddrPtrTy, Socklen_tTy},
1915 RetType{IntTy}, NoEvalCall)
1916 .ArgConstraint(
1917 ArgumentCondition(0, WithinRange, Range(0, IntMax)))
1918 .ArgConstraint(NotNull(ArgNo(1)))))
1919 addToFunctionSummaryMap(
1920 "connect", Summary(ArgTypes{IntTy, Irrelevant, Socklen_tTy},
1921 RetType{IntTy}, NoEvalCall)
1922 .ArgConstraint(ArgumentCondition(0, WithinRange,
1923 Range(0, IntMax))));
1924
1925 auto Recvfrom =
1926 Summary(NoEvalCall)
1927 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
1928 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
1929 /*BufSize=*/ArgNo(2)));
1930 if (!addToFunctionSummaryMap(
1931 "recvfrom",
1932 // ssize_t recvfrom(int socket, void *restrict buffer,
1933 // size_t length,
1934 // int flags, struct sockaddr *restrict address,
1935 // socklen_t *restrict address_len);
1936 Signature(ArgTypes{IntTy, VoidPtrRestrictTy, SizeTy, IntTy,
1937 StructSockaddrPtrRestrictTy,
1938 Socklen_tPtrRestrictTy},
1939 RetType{Ssize_tTy}),
1940 Recvfrom))
1941 addToFunctionSummaryMap(
1942 "recvfrom",
1943 Signature(ArgTypes{IntTy, VoidPtrRestrictTy, SizeTy, IntTy,
1944 Irrelevant, Socklen_tPtrRestrictTy},
1945 RetType{Ssize_tTy}),
1946 Recvfrom);
1947
1948 auto Sendto =
1949 Summary(NoEvalCall)
1950 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
1951 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
1952 /*BufSize=*/ArgNo(2)));
1953 if (!addToFunctionSummaryMap(
1954 "sendto",
1955 // ssize_t sendto(int socket, const void *message, size_t length,
1956 // int flags, const struct sockaddr *dest_addr,
1957 // socklen_t dest_len);
1958 Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTy, IntTy,
1959 ConstStructSockaddrPtrTy, Socklen_tTy},
1960 RetType{Ssize_tTy}),
1961 Sendto))
1962 addToFunctionSummaryMap(
1963 "sendto",
1964 Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTy, IntTy, Irrelevant,
1965 Socklen_tTy},
1966 RetType{Ssize_tTy}),
1967 Sendto);
1968
1969 // int listen(int sockfd, int backlog);
1970 addToFunctionSummaryMap(
1971 "listen", Summary(ArgTypes{IntTy, IntTy}, RetType{IntTy}, NoEvalCall)
1972 .ArgConstraint(
1973 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
1974
1975 // ssize_t recv(int sockfd, void *buf, size_t len, int flags);
1976 addToFunctionSummaryMap(
1977 "recv",
1978 Summary(ArgTypes{IntTy, VoidPtrTy, SizeTy, IntTy}, RetType{Ssize_tTy},
1979 NoEvalCall)
1980 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
1981 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
1982 /*BufSize=*/ArgNo(2))));
1983
1984 Optional<QualType> StructMsghdrTy = lookupTy("msghdr");
1985 Optional<QualType> StructMsghdrPtrTy = getPointerTy(StructMsghdrTy);
1986 Optional<QualType> ConstStructMsghdrPtrTy =
1987 getPointerTy(getConstTy(StructMsghdrTy));
1988
1989 // ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);
1990 addToFunctionSummaryMap(
1991 "recvmsg", Summary(ArgTypes{IntTy, StructMsghdrPtrTy, IntTy},
1992 RetType{Ssize_tTy}, NoEvalCall)
1993 .ArgConstraint(ArgumentCondition(0, WithinRange,
1994 Range(0, IntMax))));
1995
1996 // ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
1997 addToFunctionSummaryMap(
1998 "sendmsg", Summary(ArgTypes{IntTy, ConstStructMsghdrPtrTy, IntTy},
1999 RetType{Ssize_tTy}, NoEvalCall)
2000 .ArgConstraint(ArgumentCondition(0, WithinRange,
2001 Range(0, IntMax))));
2002
2003 // int setsockopt(int socket, int level, int option_name,
2004 // const void *option_value, socklen_t option_len);
2005 addToFunctionSummaryMap(
2006 "setsockopt",
2007 Summary(ArgTypes{IntTy, IntTy, IntTy, ConstVoidPtrTy, Socklen_tTy},
2008 RetType{IntTy}, NoEvalCall)
2009 .ArgConstraint(NotNull(ArgNo(3)))
2010 .ArgConstraint(
2011 BufferSize(/*Buffer=*/ArgNo(3), /*BufSize=*/ArgNo(4)))
2012 .ArgConstraint(
2013 ArgumentCondition(4, WithinRange, Range(0, Socklen_tMax))));
2014
2015 // int getsockopt(int socket, int level, int option_name,
2016 // void *restrict option_value,
2017 // socklen_t *restrict option_len);
2018 addToFunctionSummaryMap(
2019 "getsockopt", Summary(ArgTypes{IntTy, IntTy, IntTy, VoidPtrRestrictTy,
2020 Socklen_tPtrRestrictTy},
2021 RetType{IntTy}, NoEvalCall)
2022 .ArgConstraint(NotNull(ArgNo(3)))
2023 .ArgConstraint(NotNull(ArgNo(4))));
2024
2025 // ssize_t send(int sockfd, const void *buf, size_t len, int flags);
2026 addToFunctionSummaryMap(
2027 "send",
2028 Summary(ArgTypes{IntTy, ConstVoidPtrTy, SizeTy, IntTy},
2029 RetType{Ssize_tTy}, NoEvalCall)
2030 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
2031 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
2032 /*BufSize=*/ArgNo(2))));
2033
2034 // int socketpair(int domain, int type, int protocol, int sv[2]);
2035 addToFunctionSummaryMap("socketpair",
2036 Summary(ArgTypes{IntTy, IntTy, IntTy, IntPtrTy},
2037 RetType{IntTy}, NoEvalCall)
2038 .ArgConstraint(NotNull(ArgNo(3))));
2039
2040 // int getnameinfo(const struct sockaddr *restrict sa, socklen_t salen,
2041 // char *restrict node, socklen_t nodelen,
2042 // char *restrict service,
2043 // socklen_t servicelen, int flags);
2044 //
2045 // This is defined in netdb.h. And contrary to 'socket.h', the sockaddr
2046 // parameter is never handled as a transparent union in netdb.h
2047 addToFunctionSummaryMap(
2048 "getnameinfo",
2049 Summary(ArgTypes{ConstStructSockaddrPtrRestrictTy, Socklen_tTy,
2050 CharPtrRestrictTy, Socklen_tTy, CharPtrRestrictTy,
2051 Socklen_tTy, IntTy},
2052 RetType{IntTy}, NoEvalCall)
2053 .ArgConstraint(
2054 BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1)))
2055 .ArgConstraint(
2056 ArgumentCondition(1, WithinRange, Range(0, Socklen_tMax)))
2057 .ArgConstraint(
2058 BufferSize(/*Buffer=*/ArgNo(2), /*BufSize=*/ArgNo(3)))
2059 .ArgConstraint(
2060 ArgumentCondition(3, WithinRange, Range(0, Socklen_tMax)))
2061 .ArgConstraint(
2062 BufferSize(/*Buffer=*/ArgNo(4), /*BufSize=*/ArgNo(5)))
2063 .ArgConstraint(
2064 ArgumentCondition(5, WithinRange, Range(0, Socklen_tMax))));
2065
2066 Optional<QualType> StructUtimbufTy = lookupTy("utimbuf");
2067 Optional<QualType> StructUtimbufPtrTy = getPointerTy(StructUtimbufTy);
2068
2069 // int utime(const char *filename, struct utimbuf *buf);
2070 addToFunctionSummaryMap(
2071 "utime", Summary(ArgTypes{ConstCharPtrTy, StructUtimbufPtrTy},
2072 RetType{IntTy}, NoEvalCall)
2073 .ArgConstraint(NotNull(ArgNo(0))));
2074
2075 Optional<QualType> StructTimespecTy = lookupTy("timespec");
2076 Optional<QualType> StructTimespecPtrTy = getPointerTy(StructTimespecTy);
2077 Optional<QualType> ConstStructTimespecPtrTy =
2078 getPointerTy(getConstTy(StructTimespecTy));
2079
2080 // int futimens(int fd, const struct timespec times[2]);
2081 addToFunctionSummaryMap(
2082 "futimens", Summary(ArgTypes{IntTy, ConstStructTimespecPtrTy},
2083 RetType{IntTy}, NoEvalCall)
2084 .ArgConstraint(ArgumentCondition(0, WithinRange,
2085 Range(0, IntMax))));
2086
2087 // int utimensat(int dirfd, const char *pathname,
2088 // const struct timespec times[2], int flags);
2089 addToFunctionSummaryMap("utimensat",
2090 Summary(ArgTypes{IntTy, ConstCharPtrTy,
2091 ConstStructTimespecPtrTy, IntTy},
2092 RetType{IntTy}, NoEvalCall)
2093 .ArgConstraint(NotNull(ArgNo(1))));
2094
2095 Optional<QualType> StructTimevalTy = lookupTy("timeval");
2096 Optional<QualType> ConstStructTimevalPtrTy =
2097 getPointerTy(getConstTy(StructTimevalTy));
2098
2099 // int utimes(const char *filename, const struct timeval times[2]);
2100 addToFunctionSummaryMap(
2101 "utimes", Summary(ArgTypes{ConstCharPtrTy, ConstStructTimevalPtrTy},
2102 RetType{IntTy}, NoEvalCall)
2103 .ArgConstraint(NotNull(ArgNo(0))));
2104
2105 // int nanosleep(const struct timespec *rqtp, struct timespec *rmtp);
2106 addToFunctionSummaryMap(
2107 "nanosleep",
2108 Summary(ArgTypes{ConstStructTimespecPtrTy, StructTimespecPtrTy},
2109 RetType{IntTy}, NoEvalCall)
2110 .ArgConstraint(NotNull(ArgNo(0))));
2111
2112 Optional<QualType> Time_tTy = lookupTy("time_t");
2113 Optional<QualType> ConstTime_tPtrTy = getPointerTy(getConstTy(Time_tTy));
2114 Optional<QualType> ConstTime_tPtrRestrictTy =
2115 getRestrictTy(ConstTime_tPtrTy);
2116
2117 Optional<QualType> StructTmTy = lookupTy("tm");
2118 Optional<QualType> StructTmPtrTy = getPointerTy(StructTmTy);
2119 Optional<QualType> StructTmPtrRestrictTy = getRestrictTy(StructTmPtrTy);
2120 Optional<QualType> ConstStructTmPtrTy =
2121 getPointerTy(getConstTy(StructTmTy));
2122 Optional<QualType> ConstStructTmPtrRestrictTy =
2123 getRestrictTy(ConstStructTmPtrTy);
2124
2125 // struct tm * localtime(const time_t *tp);
2126 addToFunctionSummaryMap(
2127 "localtime",
2128 Summary(ArgTypes{ConstTime_tPtrTy}, RetType{StructTmPtrTy}, NoEvalCall)
2129 .ArgConstraint(NotNull(ArgNo(0))));
2130
2131 // struct tm *localtime_r(const time_t *restrict timer,
2132 // struct tm *restrict result);
2133 addToFunctionSummaryMap(
2134 "localtime_r",
2135 Summary(ArgTypes{ConstTime_tPtrRestrictTy, StructTmPtrRestrictTy},
2136 RetType{StructTmPtrTy}, NoEvalCall)
2137 .ArgConstraint(NotNull(ArgNo(0)))
2138 .ArgConstraint(NotNull(ArgNo(1))));
2139
2140 // char *asctime_r(const struct tm *restrict tm, char *restrict buf);
2141 addToFunctionSummaryMap(
2142 "asctime_r",
2143 Summary(ArgTypes{ConstStructTmPtrRestrictTy, CharPtrRestrictTy},
2144 RetType{CharPtrTy}, NoEvalCall)
2145 .ArgConstraint(NotNull(ArgNo(0)))
2146 .ArgConstraint(NotNull(ArgNo(1)))
2147 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
2148 /*MinBufSize=*/BVF.getValue(26, IntTy))));
2149
2150 // char *ctime_r(const time_t *timep, char *buf);
2151 addToFunctionSummaryMap("ctime_r",
2152 Summary(ArgTypes{ConstTime_tPtrTy, CharPtrTy},
2153 RetType{CharPtrTy}, NoEvalCall)
2154 .ArgConstraint(NotNull(ArgNo(0)))
2155 .ArgConstraint(NotNull(ArgNo(1)))
2156 .ArgConstraint(BufferSize(
2157 /*Buffer=*/ArgNo(1),
2158 /*MinBufSize=*/BVF.getValue(26, IntTy))));
2159
2160 // struct tm *gmtime_r(const time_t *restrict timer,
2161 // struct tm *restrict result);
2162 addToFunctionSummaryMap(
2163 "gmtime_r",
2164 Summary(ArgTypes{ConstTime_tPtrRestrictTy, StructTmPtrRestrictTy},
2165 RetType{StructTmPtrTy}, NoEvalCall)
2166 .ArgConstraint(NotNull(ArgNo(0)))
2167 .ArgConstraint(NotNull(ArgNo(1))));
2168
2169 // struct tm * gmtime(const time_t *tp);
2170 addToFunctionSummaryMap(
2171 "gmtime",
2172 Summary(ArgTypes{ConstTime_tPtrTy}, RetType{StructTmPtrTy}, NoEvalCall)
2173 .ArgConstraint(NotNull(ArgNo(0))));
2174
2175 Optional<QualType> Clockid_tTy = lookupTy("clockid_t");
2176
2177 // int clock_gettime(clockid_t clock_id, struct timespec *tp);
2178 addToFunctionSummaryMap("clock_gettime",
2179 Summary(ArgTypes{Clockid_tTy, StructTimespecPtrTy},
2180 RetType{IntTy}, NoEvalCall)
2181 .ArgConstraint(NotNull(ArgNo(1))));
2182
2183 Optional<QualType> StructItimervalTy = lookupTy("itimerval");
2184 Optional<QualType> StructItimervalPtrTy = getPointerTy(StructItimervalTy);
2185
2186 // int getitimer(int which, struct itimerval *curr_value);
2187 addToFunctionSummaryMap("getitimer",
2188 Summary(ArgTypes{IntTy, StructItimervalPtrTy},
2189 RetType{IntTy}, NoEvalCall)
2190 .ArgConstraint(NotNull(ArgNo(1))));
2191
2192 Optional<QualType> Pthread_cond_tTy = lookupTy("pthread_cond_t");
2193 Optional<QualType> Pthread_cond_tPtrTy = getPointerTy(Pthread_cond_tTy);
2194 Optional<QualType> Pthread_tTy = lookupTy("pthread_t");
2195 Optional<QualType> Pthread_tPtrTy = getPointerTy(Pthread_tTy);
2196 Optional<QualType> Pthread_tPtrRestrictTy = getRestrictTy(Pthread_tPtrTy);
2197 Optional<QualType> Pthread_mutex_tTy = lookupTy("pthread_mutex_t");
2198 Optional<QualType> Pthread_mutex_tPtrTy = getPointerTy(Pthread_mutex_tTy);
2199 Optional<QualType> Pthread_mutex_tPtrRestrictTy =
2200 getRestrictTy(Pthread_mutex_tPtrTy);
2201 Optional<QualType> Pthread_attr_tTy = lookupTy("pthread_attr_t");
2202 Optional<QualType> Pthread_attr_tPtrTy = getPointerTy(Pthread_attr_tTy);
2203 Optional<QualType> ConstPthread_attr_tPtrTy =
2204 getPointerTy(getConstTy(Pthread_attr_tTy));
2205 Optional<QualType> ConstPthread_attr_tPtrRestrictTy =
2206 getRestrictTy(ConstPthread_attr_tPtrTy);
2207 Optional<QualType> Pthread_mutexattr_tTy = lookupTy("pthread_mutexattr_t");
2208 Optional<QualType> ConstPthread_mutexattr_tPtrTy =
2209 getPointerTy(getConstTy(Pthread_mutexattr_tTy));
2210 Optional<QualType> ConstPthread_mutexattr_tPtrRestrictTy =
2211 getRestrictTy(ConstPthread_mutexattr_tPtrTy);
2212
2213 QualType PthreadStartRoutineTy = getPointerTy(
2214 ACtx.getFunctionType(/*ResultTy=*/VoidPtrTy, /*Args=*/VoidPtrTy,
2215 FunctionProtoType::ExtProtoInfo()));
2216
2217 // int pthread_cond_signal(pthread_cond_t *cond);
2218 // int pthread_cond_broadcast(pthread_cond_t *cond);
2219 addToFunctionSummaryMap(
2220 {"pthread_cond_signal", "pthread_cond_broadcast"},
2221 Signature(ArgTypes{Pthread_cond_tPtrTy}, RetType{IntTy}),
2222 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2223
2224 // int pthread_create(pthread_t *restrict thread,
2225 // const pthread_attr_t *restrict attr,
2226 // void *(*start_routine)(void*), void *restrict arg);
2227 addToFunctionSummaryMap(
2228 "pthread_create",
2229 Signature(ArgTypes{Pthread_tPtrRestrictTy,
2230 ConstPthread_attr_tPtrRestrictTy,
2231 PthreadStartRoutineTy, VoidPtrRestrictTy},
2232 RetType{IntTy}),
2233 Summary(NoEvalCall)
2234 .ArgConstraint(NotNull(ArgNo(0)))
2235 .ArgConstraint(NotNull(ArgNo(2))));
2236
2237 // int pthread_attr_destroy(pthread_attr_t *attr);
2238 // int pthread_attr_init(pthread_attr_t *attr);
2239 addToFunctionSummaryMap(
2240 {"pthread_attr_destroy", "pthread_attr_init"},
2241 Signature(ArgTypes{Pthread_attr_tPtrTy}, RetType{IntTy}),
2242 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2243
2244 // int pthread_attr_getstacksize(const pthread_attr_t *restrict attr,
2245 // size_t *restrict stacksize);
2246 // int pthread_attr_getguardsize(const pthread_attr_t *restrict attr,
2247 // size_t *restrict guardsize);
2248 addToFunctionSummaryMap(
2249 {"pthread_attr_getstacksize", "pthread_attr_getguardsize"},
2250 Signature(ArgTypes{ConstPthread_attr_tPtrRestrictTy, SizePtrRestrictTy},
2251 RetType{IntTy}),
2252 Summary(NoEvalCall)
2253 .ArgConstraint(NotNull(ArgNo(0)))
2254 .ArgConstraint(NotNull(ArgNo(1))));
2255
2256 // int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize);
2257 // int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize);
2258 addToFunctionSummaryMap(
2259 {"pthread_attr_setstacksize", "pthread_attr_setguardsize"},
2260 Signature(ArgTypes{Pthread_attr_tPtrTy, SizeTy}, RetType{IntTy}),
2261 Summary(NoEvalCall)
2262 .ArgConstraint(NotNull(ArgNo(0)))
2263 .ArgConstraint(
2264 ArgumentCondition(1, WithinRange, Range(0, SizeMax))));
2265
2266 // int pthread_mutex_init(pthread_mutex_t *restrict mutex, const
2267 // pthread_mutexattr_t *restrict attr);
2268 addToFunctionSummaryMap(
2269 "pthread_mutex_init",
2270 Signature(ArgTypes{Pthread_mutex_tPtrRestrictTy,
2271 ConstPthread_mutexattr_tPtrRestrictTy},
2272 RetType{IntTy}),
2273 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2274
2275 // int pthread_mutex_destroy(pthread_mutex_t *mutex);
2276 // int pthread_mutex_lock(pthread_mutex_t *mutex);
2277 // int pthread_mutex_trylock(pthread_mutex_t *mutex);
2278 // int pthread_mutex_unlock(pthread_mutex_t *mutex);
2279 addToFunctionSummaryMap(
2280 {"pthread_mutex_destroy", "pthread_mutex_lock", "pthread_mutex_trylock",
2281 "pthread_mutex_unlock"},
2282 Signature(ArgTypes{Pthread_mutex_tPtrTy}, RetType{IntTy}),
2283 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2284 }
2285
2286 // Functions for testing.
2287 if (ChecksEnabled[CK_StdCLibraryFunctionsTesterChecker]) {
2288 addToFunctionSummaryMap(
2289 "__two_constrained_args",
2290 Summary(ArgTypes{IntTy, IntTy}, RetType{IntTy}, EvalCallAsPure)
2291 .ArgConstraint(ArgumentCondition(0U, WithinRange, SingleValue(1)))
2292 .ArgConstraint(ArgumentCondition(1U, WithinRange, SingleValue(1))));
2293 addToFunctionSummaryMap(
2294 "__arg_constrained_twice",
2295 Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
2296 .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(1)))
2297 .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(2))));
2298 addToFunctionSummaryMap(
2299 "__defaultparam",
2300 Summary(ArgTypes{Irrelevant, IntTy}, RetType{IntTy}, EvalCallAsPure)
2301 .ArgConstraint(NotNull(ArgNo(0))));
2302 addToFunctionSummaryMap("__variadic",
2303 Summary(ArgTypes{VoidPtrTy, ConstCharPtrTy},
2304 RetType{IntTy}, EvalCallAsPure)
2305 .ArgConstraint(NotNull(ArgNo(0)))
2306 .ArgConstraint(NotNull(ArgNo(1))));
2307 addToFunctionSummaryMap(
2308 "__buf_size_arg_constraint",
2309 Summary(ArgTypes{ConstVoidPtrTy, SizeTy}, RetType{IntTy},
2310 EvalCallAsPure)
2311 .ArgConstraint(
2312 BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1))));
2313 addToFunctionSummaryMap(
2314 "__buf_size_arg_constraint_mul",
2315 Summary(ArgTypes{ConstVoidPtrTy, SizeTy, SizeTy}, RetType{IntTy},
2316 EvalCallAsPure)
2317 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1),
2318 /*BufSizeMultiplier=*/ArgNo(2))));
2319 addToFunctionSummaryMap(
2320 "__buf_size_arg_constraint_concrete",
2321 Summary(ArgTypes{ConstVoidPtrTy}, RetType{IntTy}, EvalCallAsPure)
2322 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(0),
2323 /*BufSize=*/BVF.getValue(10, IntTy))));
2324 addToFunctionSummaryMap(
2325 {"__test_restrict_param_0", "__test_restrict_param_1",
2326 "__test_restrict_param_2"},
2327 Signature(ArgTypes{VoidPtrRestrictTy}, RetType{VoidTy}),
2328 Summary(EvalCallAsPure));
2329 }
2330}
2331
2332void ento::registerStdCLibraryFunctionsChecker(CheckerManager &mgr) {
2333 auto *Checker = mgr.registerChecker<StdLibraryFunctionsChecker>();
2334 Checker->DisplayLoadedSummaries =
2335 mgr.getAnalyzerOptions().getCheckerBooleanOption(
2336 Checker, "DisplayLoadedSummaries");
2337 Checker->ModelPOSIX =
2338 mgr.getAnalyzerOptions().getCheckerBooleanOption(Checker, "ModelPOSIX");
2339}
2340
2341bool ento::shouldRegisterStdCLibraryFunctionsChecker(
2342 const CheckerManager &mgr) {
2343 return true;
2344}
2345
2346#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; }
\
2347 void ento::register##name(CheckerManager &mgr) { \
2348 StdLibraryFunctionsChecker *checker = \
2349 mgr.getChecker<StdLibraryFunctionsChecker>(); \
2350 checker->ChecksEnabled[StdLibraryFunctionsChecker::CK_##name] = true; \
2351 checker->CheckNames[StdLibraryFunctionsChecker::CK_##name] = \
2352 mgr.getCurrentCheckerName(); \
2353 } \
2354 \
2355 bool ento::shouldRegister##name(const CheckerManager &mgr) { return true; }
2356
2357REGISTER_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; }
2358REGISTER_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~++20200917111122+b03c2b8395b/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~++20200917111122+b03c2b8395b/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~++20200917111122+b03c2b8395b/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~++20200917111122+b03c2b8395b/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~++20200917111122+b03c2b8395b/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~++20200917111122+b03c2b8395b/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~++20200917111122+b03c2b8395b/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