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