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
44 // fread isalnum isgraph isxdigit
45 // fwrite isalpha islower read
46 // getc isascii isprint write
47 // getchar isblank ispunct
48 // getdelim iscntrl isspace
49 //
50 //===----------------------------------------------------------------------===//
51
52 #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
53 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
54 #include "clang/StaticAnalyzer/Core/Checker.h"
55 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
56 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
57 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
58 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h"
59 #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicSize.h"
60
61 using namespace clang;
62 using namespace clang::ento;
63
64 namespace {
65 class StdLibraryFunctionsChecker
66 : public Checker<check::PreCall, check::PostCall, eval::Call> {
67
68 class Summary;
69
70 /// Specify how much the analyzer engine should entrust modeling this function
71 /// to us. If he doesn't, he performs additional invalidations.
72 enum InvalidationKind { NoEvalCall, EvalCallAsPure };
73
74 // The universal integral type to use in value range descriptions.
75 // Unsigned to make sure overflows are well-defined.
76 typedef uint64_t RangeInt;
77
78 /// Normally, describes a single range constraint, eg. {{0, 1}, {3, 4}} is
79 /// a non-negative integer, which less than 5 and not equal to 2. For
80 /// `ComparesToArgument', holds information about how exactly to compare to
81 /// the argument.
82 typedef std::vector<std::pair<RangeInt, RangeInt>> IntRangeVector;
83
84 /// A reference to an argument or return value by its number.
85 /// ArgNo in CallExpr and CallEvent is defined as Unsigned, but
86 /// obviously uint32_t should be enough for all practical purposes.
87 typedef uint32_t ArgNo;
88 static const ArgNo Ret;
89
90 class ValueConstraint;
91
92 // Pointer to the ValueConstraint. We need a copyable, polymorphic and
93 // default initialize able type (vector needs that). A raw pointer was good,
94 // however, we cannot default initialize that. unique_ptr makes the Summary
95 // class non-copyable, therefore not an option. Releasing the copyability
96 // requirement would render the initialization of the Summary map infeasible.
97 using ValueConstraintPtr = std::shared_ptr<ValueConstraint>;
98
99 /// Polymorphic base class that represents a constraint on a given argument
100 /// (or return value) of a function. Derived classes implement different kind
101 /// of constraints, e.g range constraints or correlation between two
102 /// arguments.
103 class ValueConstraint {
104 public:
ValueConstraint(ArgNo ArgN)105 ValueConstraint(ArgNo ArgN) : ArgN(ArgN) {}
~ValueConstraint()106 virtual ~ValueConstraint() {}
107 /// Apply the effects of the constraint on the given program state. If null
108 /// is returned then the constraint is not feasible.
109 virtual ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
110 const Summary &Summary,
111 CheckerContext &C) const = 0;
negate() const112 virtual ValueConstraintPtr negate() const {
113 llvm_unreachable("Not implemented");
114 };
115
116 // Check whether the constraint is malformed or not. It is malformed if the
117 // specified argument has a mismatch with the given FunctionDecl (e.g. the
118 // arg number is out-of-range of the function's argument list).
checkValidity(const FunctionDecl * FD) const119 bool checkValidity(const FunctionDecl *FD) const {
120 const bool ValidArg = ArgN == Ret || ArgN < FD->getNumParams();
121 assert(ValidArg && "Arg out of range!");
122 if (!ValidArg)
123 return false;
124 // Subclasses may further refine the validation.
125 return checkSpecificValidity(FD);
126 }
getArgNo() const127 ArgNo getArgNo() const { return ArgN; }
128
129 protected:
130 ArgNo ArgN; // Argument to which we apply the constraint.
131
132 /// Do polymorphic sanity check on the constraint.
checkSpecificValidity(const FunctionDecl * FD) const133 virtual bool checkSpecificValidity(const FunctionDecl *FD) const {
134 return true;
135 }
136 };
137
138 /// Given a range, should the argument stay inside or outside this range?
139 enum RangeKind { OutOfRange, WithinRange };
140
141 /// Encapsulates a single range on a single symbol within a branch.
142 class RangeConstraint : public ValueConstraint {
143 RangeKind Kind; // Kind of range definition.
144 IntRangeVector Args; // Polymorphic arguments.
145
146 public:
RangeConstraint(ArgNo ArgN,RangeKind Kind,const IntRangeVector & Args)147 RangeConstraint(ArgNo ArgN, RangeKind Kind, const IntRangeVector &Args)
148 : ValueConstraint(ArgN), Kind(Kind), Args(Args) {}
149
getRanges() const150 const IntRangeVector &getRanges() const {
151 return Args;
152 }
153
154 private:
155 ProgramStateRef applyAsOutOfRange(ProgramStateRef State,
156 const CallEvent &Call,
157 const Summary &Summary) const;
158 ProgramStateRef applyAsWithinRange(ProgramStateRef State,
159 const CallEvent &Call,
160 const Summary &Summary) const;
161 public:
apply(ProgramStateRef State,const CallEvent & Call,const Summary & Summary,CheckerContext & C) const162 ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
163 const Summary &Summary,
164 CheckerContext &C) const override {
165 switch (Kind) {
166 case OutOfRange:
167 return applyAsOutOfRange(State, Call, Summary);
168 case WithinRange:
169 return applyAsWithinRange(State, Call, Summary);
170 }
171 llvm_unreachable("Unknown range kind!");
172 }
173
negate() const174 ValueConstraintPtr negate() const override {
175 RangeConstraint Tmp(*this);
176 switch (Kind) {
177 case OutOfRange:
178 Tmp.Kind = WithinRange;
179 break;
180 case WithinRange:
181 Tmp.Kind = OutOfRange;
182 break;
183 }
184 return std::make_shared<RangeConstraint>(Tmp);
185 }
186
checkSpecificValidity(const FunctionDecl * FD) const187 bool checkSpecificValidity(const FunctionDecl *FD) const override {
188 const bool ValidArg =
189 getArgType(FD, ArgN)->isIntegralType(FD->getASTContext());
190 assert(ValidArg &&
191 "This constraint should be applied on an integral type");
192 return ValidArg;
193 }
194 };
195
196 class ComparisonConstraint : public ValueConstraint {
197 BinaryOperator::Opcode Opcode;
198 ArgNo OtherArgN;
199
200 public:
ComparisonConstraint(ArgNo ArgN,BinaryOperator::Opcode Opcode,ArgNo OtherArgN)201 ComparisonConstraint(ArgNo ArgN, BinaryOperator::Opcode Opcode,
202 ArgNo OtherArgN)
203 : ValueConstraint(ArgN), Opcode(Opcode), OtherArgN(OtherArgN) {}
getOtherArgNo() const204 ArgNo getOtherArgNo() const { return OtherArgN; }
getOpcode() const205 BinaryOperator::Opcode getOpcode() const { return Opcode; }
206 ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
207 const Summary &Summary,
208 CheckerContext &C) const override;
209 };
210
211 class NotNullConstraint : public ValueConstraint {
212 using ValueConstraint::ValueConstraint;
213 // This variable has a role when we negate the constraint.
214 bool CannotBeNull = true;
215
216 public:
apply(ProgramStateRef State,const CallEvent & Call,const Summary & Summary,CheckerContext & C) const217 ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
218 const Summary &Summary,
219 CheckerContext &C) const override {
220 SVal V = getArgSVal(Call, getArgNo());
221 if (V.isUndef())
222 return State;
223
224 DefinedOrUnknownSVal L = V.castAs<DefinedOrUnknownSVal>();
225 if (!L.getAs<Loc>())
226 return State;
227
228 return State->assume(L, CannotBeNull);
229 }
230
negate() const231 ValueConstraintPtr negate() const override {
232 NotNullConstraint Tmp(*this);
233 Tmp.CannotBeNull = !this->CannotBeNull;
234 return std::make_shared<NotNullConstraint>(Tmp);
235 }
236
checkSpecificValidity(const FunctionDecl * FD) const237 bool checkSpecificValidity(const FunctionDecl *FD) const override {
238 const bool ValidArg = getArgType(FD, ArgN)->isPointerType();
239 assert(ValidArg &&
240 "This constraint should be applied only on a pointer type");
241 return ValidArg;
242 }
243 };
244
245 // Represents a buffer argument with an additional size argument.
246 // E.g. the first two arguments here:
247 // ctime_s(char *buffer, rsize_t bufsz, const time_t *time);
248 // Another example:
249 // size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
250 // // Here, ptr is the buffer, and its minimum size is `size * nmemb`.
251 class BufferSizeConstraint : public ValueConstraint {
252 // The argument which holds the size of the buffer.
253 ArgNo SizeArgN;
254 // The argument which is a multiplier to size. This is set in case of
255 // `fread` like functions where the size is computed as a multiplication of
256 // two arguments.
257 llvm::Optional<ArgNo> SizeMultiplierArgN;
258 // The operator we use in apply. This is negated in negate().
259 BinaryOperator::Opcode Op = BO_LE;
260
261 public:
BufferSizeConstraint(ArgNo Buffer,ArgNo BufSize)262 BufferSizeConstraint(ArgNo Buffer, ArgNo BufSize)
263 : ValueConstraint(Buffer), SizeArgN(BufSize) {}
264
BufferSizeConstraint(ArgNo Buffer,ArgNo BufSize,ArgNo BufSizeMultiplier)265 BufferSizeConstraint(ArgNo Buffer, ArgNo BufSize, ArgNo BufSizeMultiplier)
266 : ValueConstraint(Buffer), SizeArgN(BufSize),
267 SizeMultiplierArgN(BufSizeMultiplier) {}
268
apply(ProgramStateRef State,const CallEvent & Call,const Summary & Summary,CheckerContext & C) const269 ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
270 const Summary &Summary,
271 CheckerContext &C) const override {
272 SValBuilder &SvalBuilder = C.getSValBuilder();
273 // The buffer argument.
274 SVal BufV = getArgSVal(Call, getArgNo());
275 // The size argument.
276 SVal SizeV = getArgSVal(Call, SizeArgN);
277 // Multiply with another argument if given.
278 if (SizeMultiplierArgN) {
279 SVal SizeMulV = getArgSVal(Call, *SizeMultiplierArgN);
280 SizeV = SvalBuilder.evalBinOp(State, BO_Mul, SizeV, SizeMulV,
281 Summary.getArgType(SizeArgN));
282 }
283 // The dynamic size of the buffer argument, got from the analyzer engine.
284 SVal BufDynSize = getDynamicSizeWithOffset(State, BufV);
285
286 SVal Feasible = SvalBuilder.evalBinOp(State, Op, SizeV, BufDynSize,
287 SvalBuilder.getContext().BoolTy);
288 if (auto F = Feasible.getAs<DefinedOrUnknownSVal>())
289 return State->assume(*F, true);
290
291 // We can get here only if the size argument or the dynamic size is
292 // undefined. But the dynamic size should never be undefined, only
293 // unknown. So, here, the size of the argument is undefined, i.e. we
294 // cannot apply the constraint. Actually, other checkers like
295 // CallAndMessage should catch this situation earlier, because we call a
296 // function with an uninitialized argument.
297 llvm_unreachable("Size argument or the dynamic size is Undefined");
298 }
299
negate() const300 ValueConstraintPtr negate() const override {
301 BufferSizeConstraint Tmp(*this);
302 Tmp.Op = BinaryOperator::negateComparisonOp(Op);
303 return std::make_shared<BufferSizeConstraint>(Tmp);
304 }
305 };
306
307 /// The complete list of constraints that defines a single branch.
308 typedef std::vector<ValueConstraintPtr> ConstraintSet;
309
310 using ArgTypes = std::vector<QualType>;
311
312 // A placeholder type, we use it whenever we do not care about the concrete
313 // type in a Signature.
314 const QualType Irrelevant{};
isIrrelevant(QualType T)315 bool static isIrrelevant(QualType T) { return T.isNull(); }
316
317 // The signature of a function we want to describe with a summary. This is a
318 // concessive signature, meaning there may be irrelevant types in the
319 // signature which we do not check against a function with concrete types.
320 struct Signature {
321 const ArgTypes ArgTys;
322 const QualType RetTy;
Signature__anon1c9c4dea0111::StdLibraryFunctionsChecker::Signature323 Signature(ArgTypes ArgTys, QualType RetTy) : ArgTys(ArgTys), RetTy(RetTy) {
324 assertRetTypeSuitableForSignature(RetTy);
325 for (size_t I = 0, E = ArgTys.size(); I != E; ++I) {
326 QualType ArgTy = ArgTys[I];
327 assertArgTypeSuitableForSignature(ArgTy);
328 }
329 }
330 bool matches(const FunctionDecl *FD) const;
331
332 private:
assertArgTypeSuitableForSignature__anon1c9c4dea0111::StdLibraryFunctionsChecker::Signature333 static void assertArgTypeSuitableForSignature(QualType T) {
334 assert((T.isNull() || !T->isVoidType()) &&
335 "We should have no void types in the spec");
336 assert((T.isNull() || T.isCanonical()) &&
337 "We should only have canonical types in the spec");
338 }
assertRetTypeSuitableForSignature__anon1c9c4dea0111::StdLibraryFunctionsChecker::Signature339 static void assertRetTypeSuitableForSignature(QualType T) {
340 assert((T.isNull() || T.isCanonical()) &&
341 "We should only have canonical types in the spec");
342 }
343 };
344
getArgType(const FunctionDecl * FD,ArgNo ArgN)345 static QualType getArgType(const FunctionDecl *FD, ArgNo ArgN) {
346 assert(FD && "Function must be set");
347 QualType T = (ArgN == Ret)
348 ? FD->getReturnType().getCanonicalType()
349 : FD->getParamDecl(ArgN)->getType().getCanonicalType();
350 return T;
351 }
352
353 using Cases = std::vector<ConstraintSet>;
354
355 /// A summary includes information about
356 /// * function prototype (signature)
357 /// * approach to invalidation,
358 /// * a list of branches - a list of list of ranges -
359 /// A branch represents a path in the exploded graph of a function (which
360 /// is a tree). So, a branch is a series of assumptions. In other words,
361 /// branches represent split states and additional assumptions on top of
362 /// the splitting assumption.
363 /// For example, consider the branches in `isalpha(x)`
364 /// Branch 1)
365 /// x is in range ['A', 'Z'] or in ['a', 'z']
366 /// then the return value is not 0. (I.e. out-of-range [0, 0])
367 /// Branch 2)
368 /// x is out-of-range ['A', 'Z'] and out-of-range ['a', 'z']
369 /// then the return value is 0.
370 /// * a list of argument constraints, that must be true on every branch.
371 /// If these constraints are not satisfied that means a fatal error
372 /// usually resulting in undefined behaviour.
373 ///
374 /// Application of a summary:
375 /// The signature and argument constraints together contain information
376 /// about which functions are handled by the summary. The signature can use
377 /// "wildcards", i.e. Irrelevant types. Irrelevant type of a parameter in
378 /// a signature means that type is not compared to the type of the parameter
379 /// in the found FunctionDecl. Argument constraints may specify additional
380 /// rules for the given parameter's type, those rules are checked once the
381 /// signature is matched.
382 class Summary {
383 const Signature Sign;
384 const InvalidationKind InvalidationKd;
385 Cases CaseConstraints;
386 ConstraintSet ArgConstraints;
387
388 // The function to which the summary applies. This is set after lookup and
389 // match to the signature.
390 const FunctionDecl *FD = nullptr;
391
392 public:
Summary(ArgTypes ArgTys,QualType RetTy,InvalidationKind InvalidationKd)393 Summary(ArgTypes ArgTys, QualType RetTy, InvalidationKind InvalidationKd)
394 : Sign(ArgTys, RetTy), InvalidationKd(InvalidationKd) {}
395
Case(ConstraintSet && CS)396 Summary &Case(ConstraintSet&& CS) {
397 CaseConstraints.push_back(std::move(CS));
398 return *this;
399 }
ArgConstraint(ValueConstraintPtr VC)400 Summary &ArgConstraint(ValueConstraintPtr VC) {
401 ArgConstraints.push_back(VC);
402 return *this;
403 }
404
getInvalidationKd() const405 InvalidationKind getInvalidationKd() const { return InvalidationKd; }
getCaseConstraints() const406 const Cases &getCaseConstraints() const { return CaseConstraints; }
getArgConstraints() const407 const ConstraintSet &getArgConstraints() const { return ArgConstraints; }
408
getArgType(ArgNo ArgN) const409 QualType getArgType(ArgNo ArgN) const {
410 return StdLibraryFunctionsChecker::getArgType(FD, ArgN);
411 }
412
413 // Returns true if the summary should be applied to the given function.
414 // And if yes then store the function declaration.
matchesAndSet(const FunctionDecl * FD)415 bool matchesAndSet(const FunctionDecl *FD) {
416 bool Result = Sign.matches(FD) && validateByConstraints(FD);
417 if (Result) {
418 assert(!this->FD && "FD must not be set more than once");
419 this->FD = FD;
420 }
421 return Result;
422 }
423
424 private:
425 // Once we know the exact type of the function then do sanity check on all
426 // the given constraints.
validateByConstraints(const FunctionDecl * FD) const427 bool validateByConstraints(const FunctionDecl *FD) const {
428 for (const ConstraintSet &Case : CaseConstraints)
429 for (const ValueConstraintPtr &Constraint : Case)
430 if (!Constraint->checkValidity(FD))
431 return false;
432 for (const ValueConstraintPtr &Constraint : ArgConstraints)
433 if (!Constraint->checkValidity(FD))
434 return false;
435 return true;
436 }
437 };
438
439 // The map of all functions supported by the checker. It is initialized
440 // lazily, and it doesn't change after initialization.
441 using FunctionSummaryMapType = llvm::DenseMap<const FunctionDecl *, Summary>;
442 mutable FunctionSummaryMapType FunctionSummaryMap;
443
444 mutable std::unique_ptr<BugType> BT_InvalidArg;
445
getArgSVal(const CallEvent & Call,ArgNo ArgN)446 static SVal getArgSVal(const CallEvent &Call, ArgNo ArgN) {
447 return ArgN == Ret ? Call.getReturnValue() : Call.getArgSVal(ArgN);
448 }
449
450 public:
451 void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
452 void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
453 bool evalCall(const CallEvent &Call, CheckerContext &C) const;
454
455 enum CheckKind {
456 CK_StdCLibraryFunctionArgsChecker,
457 CK_StdCLibraryFunctionsTesterChecker,
458 CK_NumCheckKinds
459 };
460 DefaultBool ChecksEnabled[CK_NumCheckKinds];
461 CheckerNameRef CheckNames[CK_NumCheckKinds];
462
463 bool DisplayLoadedSummaries = false;
464 bool ModelPOSIX = false;
465
466 private:
467 Optional<Summary> findFunctionSummary(const FunctionDecl *FD,
468 CheckerContext &C) const;
469 Optional<Summary> findFunctionSummary(const CallEvent &Call,
470 CheckerContext &C) const;
471
472 void initFunctionSummaries(CheckerContext &C) const;
473
reportBug(const CallEvent & Call,ExplodedNode * N,CheckerContext & C) const474 void reportBug(const CallEvent &Call, ExplodedNode *N,
475 CheckerContext &C) const {
476 if (!ChecksEnabled[CK_StdCLibraryFunctionArgsChecker])
477 return;
478 // TODO Add detailed diagnostic.
479 StringRef Msg = "Function argument constraint is not satisfied";
480 if (!BT_InvalidArg)
481 BT_InvalidArg = std::make_unique<BugType>(
482 CheckNames[CK_StdCLibraryFunctionArgsChecker],
483 "Unsatisfied argument constraints", categories::LogicError);
484 auto R = std::make_unique<PathSensitiveBugReport>(*BT_InvalidArg, Msg, N);
485 bugreporter::trackExpressionValue(N, Call.getArgExpr(0), *R);
486 C.emitReport(std::move(R));
487 }
488 };
489
490 const StdLibraryFunctionsChecker::ArgNo StdLibraryFunctionsChecker::Ret =
491 std::numeric_limits<ArgNo>::max();
492
493 } // end of anonymous namespace
494
applyAsOutOfRange(ProgramStateRef State,const CallEvent & Call,const Summary & Summary) const495 ProgramStateRef StdLibraryFunctionsChecker::RangeConstraint::applyAsOutOfRange(
496 ProgramStateRef State, const CallEvent &Call,
497 const Summary &Summary) const {
498
499 ProgramStateManager &Mgr = State->getStateManager();
500 SValBuilder &SVB = Mgr.getSValBuilder();
501 BasicValueFactory &BVF = SVB.getBasicValueFactory();
502 ConstraintManager &CM = Mgr.getConstraintManager();
503 QualType T = Summary.getArgType(getArgNo());
504 SVal V = getArgSVal(Call, getArgNo());
505
506 if (auto N = V.getAs<NonLoc>()) {
507 const IntRangeVector &R = getRanges();
508 size_t E = R.size();
509 for (size_t I = 0; I != E; ++I) {
510 const llvm::APSInt &Min = BVF.getValue(R[I].first, T);
511 const llvm::APSInt &Max = BVF.getValue(R[I].second, T);
512 assert(Min <= Max);
513 State = CM.assumeInclusiveRange(State, *N, Min, Max, false);
514 if (!State)
515 break;
516 }
517 }
518
519 return State;
520 }
521
applyAsWithinRange(ProgramStateRef State,const CallEvent & Call,const Summary & Summary) const522 ProgramStateRef StdLibraryFunctionsChecker::RangeConstraint::applyAsWithinRange(
523 ProgramStateRef State, const CallEvent &Call,
524 const Summary &Summary) const {
525
526 ProgramStateManager &Mgr = State->getStateManager();
527 SValBuilder &SVB = Mgr.getSValBuilder();
528 BasicValueFactory &BVF = SVB.getBasicValueFactory();
529 ConstraintManager &CM = Mgr.getConstraintManager();
530 QualType T = Summary.getArgType(getArgNo());
531 SVal V = getArgSVal(Call, getArgNo());
532
533 // "WithinRange R" is treated as "outside [T_MIN, T_MAX] \ R".
534 // We cut off [T_MIN, min(R) - 1] and [max(R) + 1, T_MAX] if necessary,
535 // and then cut away all holes in R one by one.
536 //
537 // E.g. consider a range list R as [A, B] and [C, D]
538 // -------+--------+------------------+------------+----------->
539 // A B C D
540 // Then we assume that the value is not in [-inf, A - 1],
541 // then not in [D + 1, +inf], then not in [B + 1, C - 1]
542 if (auto N = V.getAs<NonLoc>()) {
543 const IntRangeVector &R = getRanges();
544 size_t E = R.size();
545
546 const llvm::APSInt &MinusInf = BVF.getMinValue(T);
547 const llvm::APSInt &PlusInf = BVF.getMaxValue(T);
548
549 const llvm::APSInt &Left = BVF.getValue(R[0].first - 1ULL, T);
550 if (Left != PlusInf) {
551 assert(MinusInf <= Left);
552 State = CM.assumeInclusiveRange(State, *N, MinusInf, Left, false);
553 if (!State)
554 return nullptr;
555 }
556
557 const llvm::APSInt &Right = BVF.getValue(R[E - 1].second + 1ULL, T);
558 if (Right != MinusInf) {
559 assert(Right <= PlusInf);
560 State = CM.assumeInclusiveRange(State, *N, Right, PlusInf, false);
561 if (!State)
562 return nullptr;
563 }
564
565 for (size_t I = 1; I != E; ++I) {
566 const llvm::APSInt &Min = BVF.getValue(R[I - 1].second + 1ULL, T);
567 const llvm::APSInt &Max = BVF.getValue(R[I].first - 1ULL, T);
568 if (Min <= Max) {
569 State = CM.assumeInclusiveRange(State, *N, Min, Max, false);
570 if (!State)
571 return nullptr;
572 }
573 }
574 }
575
576 return State;
577 }
578
apply(ProgramStateRef State,const CallEvent & Call,const Summary & Summary,CheckerContext & C) const579 ProgramStateRef StdLibraryFunctionsChecker::ComparisonConstraint::apply(
580 ProgramStateRef State, const CallEvent &Call, const Summary &Summary,
581 CheckerContext &C) const {
582
583 ProgramStateManager &Mgr = State->getStateManager();
584 SValBuilder &SVB = Mgr.getSValBuilder();
585 QualType CondT = SVB.getConditionType();
586 QualType T = Summary.getArgType(getArgNo());
587 SVal V = getArgSVal(Call, getArgNo());
588
589 BinaryOperator::Opcode Op = getOpcode();
590 ArgNo OtherArg = getOtherArgNo();
591 SVal OtherV = getArgSVal(Call, OtherArg);
592 QualType OtherT = Summary.getArgType(OtherArg);
593 // Note: we avoid integral promotion for comparison.
594 OtherV = SVB.evalCast(OtherV, T, OtherT);
595 if (auto CompV = SVB.evalBinOp(State, Op, V, OtherV, CondT)
596 .getAs<DefinedOrUnknownSVal>())
597 State = State->assume(*CompV, true);
598 return State;
599 }
600
checkPreCall(const CallEvent & Call,CheckerContext & C) const601 void StdLibraryFunctionsChecker::checkPreCall(const CallEvent &Call,
602 CheckerContext &C) const {
603 Optional<Summary> FoundSummary = findFunctionSummary(Call, C);
604 if (!FoundSummary)
605 return;
606
607 const Summary &Summary = *FoundSummary;
608 ProgramStateRef State = C.getState();
609
610 ProgramStateRef NewState = State;
611 for (const ValueConstraintPtr &Constraint : Summary.getArgConstraints()) {
612 ProgramStateRef SuccessSt = Constraint->apply(NewState, Call, Summary, C);
613 ProgramStateRef FailureSt =
614 Constraint->negate()->apply(NewState, Call, Summary, C);
615 // The argument constraint is not satisfied.
616 if (FailureSt && !SuccessSt) {
617 if (ExplodedNode *N = C.generateErrorNode(NewState))
618 reportBug(Call, N, C);
619 break;
620 } else {
621 // We will apply the constraint even if we cannot reason about the
622 // argument. This means both SuccessSt and FailureSt can be true. If we
623 // weren't applying the constraint that would mean that symbolic
624 // execution continues on a code whose behaviour is undefined.
625 assert(SuccessSt);
626 NewState = SuccessSt;
627 }
628 }
629 if (NewState && NewState != State)
630 C.addTransition(NewState);
631 }
632
checkPostCall(const CallEvent & Call,CheckerContext & C) const633 void StdLibraryFunctionsChecker::checkPostCall(const CallEvent &Call,
634 CheckerContext &C) const {
635 Optional<Summary> FoundSummary = findFunctionSummary(Call, C);
636 if (!FoundSummary)
637 return;
638
639 // Now apply the constraints.
640 const Summary &Summary = *FoundSummary;
641 ProgramStateRef State = C.getState();
642
643 // Apply case/branch specifications.
644 for (const ConstraintSet &Case : Summary.getCaseConstraints()) {
645 ProgramStateRef NewState = State;
646 for (const ValueConstraintPtr &Constraint : Case) {
647 NewState = Constraint->apply(NewState, Call, Summary, C);
648 if (!NewState)
649 break;
650 }
651
652 if (NewState && NewState != State)
653 C.addTransition(NewState);
654 }
655 }
656
evalCall(const CallEvent & Call,CheckerContext & C) const657 bool StdLibraryFunctionsChecker::evalCall(const CallEvent &Call,
658 CheckerContext &C) const {
659 Optional<Summary> FoundSummary = findFunctionSummary(Call, C);
660 if (!FoundSummary)
661 return false;
662
663 const Summary &Summary = *FoundSummary;
664 switch (Summary.getInvalidationKd()) {
665 case EvalCallAsPure: {
666 ProgramStateRef State = C.getState();
667 const LocationContext *LC = C.getLocationContext();
668 const auto *CE = cast_or_null<CallExpr>(Call.getOriginExpr());
669 SVal V = C.getSValBuilder().conjureSymbolVal(
670 CE, LC, CE->getType().getCanonicalType(), C.blockCount());
671 State = State->BindExpr(CE, LC, V);
672 C.addTransition(State);
673 return true;
674 }
675 case NoEvalCall:
676 // Summary tells us to avoid performing eval::Call. The function is possibly
677 // evaluated by another checker, or evaluated conservatively.
678 return false;
679 }
680 llvm_unreachable("Unknown invalidation kind!");
681 }
682
matches(const FunctionDecl * FD) const683 bool StdLibraryFunctionsChecker::Signature::matches(
684 const FunctionDecl *FD) const {
685 // Check number of arguments:
686 if (FD->param_size() != ArgTys.size())
687 return false;
688
689 // Check return type.
690 if (!isIrrelevant(RetTy))
691 if (RetTy != FD->getReturnType().getCanonicalType())
692 return false;
693
694 // Check argument types.
695 for (size_t I = 0, E = ArgTys.size(); I != E; ++I) {
696 QualType ArgTy = ArgTys[I];
697 if (isIrrelevant(ArgTy))
698 continue;
699 if (ArgTy != FD->getParamDecl(I)->getType().getCanonicalType())
700 return false;
701 }
702
703 return true;
704 }
705
706 Optional<StdLibraryFunctionsChecker::Summary>
findFunctionSummary(const FunctionDecl * FD,CheckerContext & C) const707 StdLibraryFunctionsChecker::findFunctionSummary(const FunctionDecl *FD,
708 CheckerContext &C) const {
709 if (!FD)
710 return None;
711
712 initFunctionSummaries(C);
713
714 auto FSMI = FunctionSummaryMap.find(FD->getCanonicalDecl());
715 if (FSMI == FunctionSummaryMap.end())
716 return None;
717 return FSMI->second;
718 }
719
720 Optional<StdLibraryFunctionsChecker::Summary>
findFunctionSummary(const CallEvent & Call,CheckerContext & C) const721 StdLibraryFunctionsChecker::findFunctionSummary(const CallEvent &Call,
722 CheckerContext &C) const {
723 const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
724 if (!FD)
725 return None;
726 return findFunctionSummary(FD, C);
727 }
728
lookupType(StringRef Name,const ASTContext & ACtx)729 static llvm::Optional<QualType> lookupType(StringRef Name,
730 const ASTContext &ACtx) {
731 IdentifierInfo &II = ACtx.Idents.get(Name);
732 auto LookupRes = ACtx.getTranslationUnitDecl()->lookup(&II);
733 if (LookupRes.size() == 0)
734 return None;
735
736 // Prioritze typedef declarations.
737 // This is needed in case of C struct typedefs. E.g.:
738 // typedef struct FILE FILE;
739 // In this case, we have a RecordDecl 'struct FILE' with the name 'FILE' and
740 // we have a TypedefDecl with the name 'FILE'.
741 for (Decl *D : LookupRes)
742 if (auto *TD = dyn_cast<TypedefNameDecl>(D))
743 return ACtx.getTypeDeclType(TD).getCanonicalType();
744
745 // Find the first TypeDecl.
746 // There maybe cases when a function has the same name as a struct.
747 // E.g. in POSIX: `struct stat` and the function `stat()`:
748 // int stat(const char *restrict path, struct stat *restrict buf);
749 for (Decl *D : LookupRes)
750 if (auto *TD = dyn_cast<TypeDecl>(D))
751 return ACtx.getTypeDeclType(TD).getCanonicalType();
752 return None;
753 }
754
initFunctionSummaries(CheckerContext & C) const755 void StdLibraryFunctionsChecker::initFunctionSummaries(
756 CheckerContext &C) const {
757 if (!FunctionSummaryMap.empty())
758 return;
759
760 SValBuilder &SVB = C.getSValBuilder();
761 BasicValueFactory &BVF = SVB.getBasicValueFactory();
762 const ASTContext &ACtx = BVF.getContext();
763
764 // These types are useful for writing specifications quickly,
765 // New specifications should probably introduce more types.
766 // Some types are hard to obtain from the AST, eg. "ssize_t".
767 // In such cases it should be possible to provide multiple variants
768 // of function summary for common cases (eg. ssize_t could be int or long
769 // or long long, so three summary variants would be enough).
770 // Of course, function variants are also useful for C++ overloads.
771 const QualType VoidTy = ACtx.VoidTy;
772 const QualType IntTy = ACtx.IntTy;
773 const QualType UnsignedIntTy = ACtx.UnsignedIntTy;
774 const QualType LongTy = ACtx.LongTy;
775 const QualType LongLongTy = ACtx.LongLongTy;
776 const QualType SizeTy = ACtx.getSizeType();
777
778 const QualType VoidPtrTy = ACtx.VoidPtrTy; // void *
779 const QualType IntPtrTy = ACtx.getPointerType(IntTy); // int *
780 const QualType UnsignedIntPtrTy =
781 ACtx.getPointerType(UnsignedIntTy); // unsigned int *
782 const QualType VoidPtrRestrictTy =
783 ACtx.getLangOpts().C99 ? ACtx.getRestrictType(VoidPtrTy) // void *restrict
784 : VoidPtrTy;
785 const QualType ConstVoidPtrTy =
786 ACtx.getPointerType(ACtx.VoidTy.withConst()); // const void *
787 const QualType CharPtrTy = ACtx.getPointerType(ACtx.CharTy); // char *
788 const QualType CharPtrRestrictTy =
789 ACtx.getLangOpts().C99 ? ACtx.getRestrictType(CharPtrTy) // char *restrict
790 : CharPtrTy;
791 const QualType ConstCharPtrTy =
792 ACtx.getPointerType(ACtx.CharTy.withConst()); // const char *
793 const QualType ConstCharPtrRestrictTy =
794 ACtx.getLangOpts().C99
795 ? ACtx.getRestrictType(ConstCharPtrTy) // const char *restrict
796 : ConstCharPtrTy;
797 const QualType Wchar_tPtrTy = ACtx.getPointerType(ACtx.WCharTy); // wchar_t *
798 const QualType ConstWchar_tPtrTy =
799 ACtx.getPointerType(ACtx.WCharTy.withConst()); // const wchar_t *
800 const QualType ConstVoidPtrRestrictTy =
801 ACtx.getLangOpts().C99
802 ? ACtx.getRestrictType(ConstVoidPtrTy) // const void *restrict
803 : ConstVoidPtrTy;
804
805 const RangeInt IntMax = BVF.getMaxValue(IntTy).getLimitedValue();
806 const RangeInt UnsignedIntMax =
807 BVF.getMaxValue(UnsignedIntTy).getLimitedValue();
808 const RangeInt LongMax = BVF.getMaxValue(LongTy).getLimitedValue();
809 const RangeInt LongLongMax = BVF.getMaxValue(LongLongTy).getLimitedValue();
810 const RangeInt SizeMax = BVF.getMaxValue(SizeTy).getLimitedValue();
811
812 // Set UCharRangeMax to min of int or uchar maximum value.
813 // The C standard states that the arguments of functions like isalpha must
814 // be representable as an unsigned char. Their type is 'int', so the max
815 // value of the argument should be min(UCharMax, IntMax). This just happen
816 // to be true for commonly used and well tested instruction set
817 // architectures, but not for others.
818 const RangeInt UCharRangeMax =
819 std::min(BVF.getMaxValue(ACtx.UnsignedCharTy).getLimitedValue(), IntMax);
820
821 // The platform dependent value of EOF.
822 // Try our best to parse this from the Preprocessor, otherwise fallback to -1.
823 const auto EOFv = [&C]() -> RangeInt {
824 if (const llvm::Optional<int> OptInt =
825 tryExpandAsInteger("EOF", C.getPreprocessor()))
826 return *OptInt;
827 return -1;
828 }();
829
830 // Auxiliary class to aid adding summaries to the summary map.
831 struct AddToFunctionSummaryMap {
832 const ASTContext &ACtx;
833 FunctionSummaryMapType ⤅
834 bool DisplayLoadedSummaries;
835 AddToFunctionSummaryMap(const ASTContext &ACtx, FunctionSummaryMapType &FSM,
836 bool DisplayLoadedSummaries)
837 : ACtx(ACtx), Map(FSM), DisplayLoadedSummaries(DisplayLoadedSummaries) {
838 }
839
840 // Add a summary to a FunctionDecl found by lookup. The lookup is performed
841 // by the given Name, and in the global scope. The summary will be attached
842 // to the found FunctionDecl only if the signatures match.
843 void operator()(StringRef Name, Summary S) {
844 IdentifierInfo &II = ACtx.Idents.get(Name);
845 auto LookupRes = ACtx.getTranslationUnitDecl()->lookup(&II);
846 if (LookupRes.size() == 0)
847 return;
848 for (Decl *D : LookupRes) {
849 if (auto *FD = dyn_cast<FunctionDecl>(D)) {
850 if (S.matchesAndSet(FD)) {
851 auto Res = Map.insert({FD->getCanonicalDecl(), S});
852 assert(Res.second && "Function already has a summary set!");
853 (void)Res;
854 if (DisplayLoadedSummaries) {
855 llvm::errs() << "Loaded summary for: ";
856 FD->print(llvm::errs());
857 llvm::errs() << "\n";
858 }
859 return;
860 }
861 }
862 }
863 }
864 // Add several summaries for the given name.
865 void operator()(StringRef Name, const std::vector<Summary> &Summaries) {
866 for (const Summary &S : Summaries)
867 operator()(Name, S);
868 }
869 } addToFunctionSummaryMap(ACtx, FunctionSummaryMap, DisplayLoadedSummaries);
870
871 // We are finally ready to define specifications for all supported functions.
872 //
873 // The signature needs to have the correct number of arguments.
874 // However, we insert `Irrelevant' when the type is insignificant.
875 //
876 // Argument ranges should always cover all variants. If return value
877 // is completely unknown, omit it from the respective range set.
878 //
879 // All types in the spec need to be canonical.
880 //
881 // Every item in the list of range sets represents a particular
882 // execution path the analyzer would need to explore once
883 // the call is modeled - a new program state is constructed
884 // for every range set, and each range line in the range set
885 // corresponds to a specific constraint within this state.
886 //
887 // Upon comparing to another argument, the other argument is casted
888 // to the current argument's type. This avoids proper promotion but
889 // seems useful. For example, read() receives size_t argument,
890 // and its return value, which is of type ssize_t, cannot be greater
891 // than this argument. If we made a promotion, and the size argument
892 // is equal to, say, 10, then we'd impose a range of [0, 10] on the
893 // return value, however the correct range is [-1, 10].
894 //
895 // Please update the list of functions in the header after editing!
896
897 // Below are helpers functions to create the summaries.
898 auto ArgumentCondition = [](ArgNo ArgN, RangeKind Kind,
899 IntRangeVector Ranges) {
900 return std::make_shared<RangeConstraint>(ArgN, Kind, Ranges);
901 };
902 auto BufferSize = [](auto... Args) {
903 return std::make_shared<BufferSizeConstraint>(Args...);
904 };
905 struct {
906 auto operator()(RangeKind Kind, IntRangeVector Ranges) {
907 return std::make_shared<RangeConstraint>(Ret, Kind, Ranges);
908 }
909 auto operator()(BinaryOperator::Opcode Op, ArgNo OtherArgN) {
910 return std::make_shared<ComparisonConstraint>(Ret, Op, OtherArgN);
911 }
912 } ReturnValueCondition;
913 auto Range = [](RangeInt b, RangeInt e) {
914 return IntRangeVector{std::pair<RangeInt, RangeInt>{b, e}};
915 };
916 auto SingleValue = [](RangeInt v) {
917 return IntRangeVector{std::pair<RangeInt, RangeInt>{v, v}};
918 };
919 auto LessThanOrEq = BO_LE;
920 auto NotNull = [&](ArgNo ArgN) {
921 return std::make_shared<NotNullConstraint>(ArgN);
922 };
923
924 Optional<QualType> FileTy = lookupType("FILE", ACtx);
925 Optional<QualType> FilePtrTy, FilePtrRestrictTy;
926 if (FileTy) {
927 // FILE *
928 FilePtrTy = ACtx.getPointerType(*FileTy);
929 // FILE *restrict
930 FilePtrRestrictTy =
931 ACtx.getLangOpts().C99 ? ACtx.getRestrictType(*FilePtrTy) : *FilePtrTy;
932 }
933
934 using RetType = QualType;
935 // Templates for summaries that are reused by many functions.
936 auto Getc = [&]() {
937 return Summary(ArgTypes{*FilePtrTy}, RetType{IntTy}, NoEvalCall)
938 .Case({ReturnValueCondition(WithinRange,
939 {{EOFv, EOFv}, {0, UCharRangeMax}})});
940 };
941 auto Read = [&](RetType R, RangeInt Max) {
942 return Summary(ArgTypes{Irrelevant, Irrelevant, SizeTy}, RetType{R},
943 NoEvalCall)
944 .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)),
945 ReturnValueCondition(WithinRange, Range(-1, Max))});
946 };
947 auto Fread = [&]() {
948 return Summary(
949 ArgTypes{VoidPtrRestrictTy, SizeTy, SizeTy, *FilePtrRestrictTy},
950 RetType{SizeTy}, NoEvalCall)
951 .Case({
952 ReturnValueCondition(LessThanOrEq, ArgNo(2)),
953 })
954 .ArgConstraint(NotNull(ArgNo(0)));
955 };
956 auto Fwrite = [&]() {
957 return Summary(ArgTypes{ConstVoidPtrRestrictTy, SizeTy, SizeTy,
958 *FilePtrRestrictTy},
959 RetType{SizeTy}, NoEvalCall)
960 .Case({
961 ReturnValueCondition(LessThanOrEq, ArgNo(2)),
962 })
963 .ArgConstraint(NotNull(ArgNo(0)));
964 };
965 auto Getline = [&](RetType R, RangeInt Max) {
966 return Summary(ArgTypes{Irrelevant, Irrelevant, Irrelevant}, RetType{R},
967 NoEvalCall)
968 .Case({ReturnValueCondition(WithinRange, {{-1, -1}, {1, Max}})});
969 };
970
971 // The isascii() family of functions.
972 // The behavior is undefined if the value of the argument is not
973 // representable as unsigned char or is not equal to EOF. See e.g. C99
974 // 7.4.1.2 The isalpha function (p: 181-182).
975 addToFunctionSummaryMap(
976 "isalnum",
977 Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
978 // Boils down to isupper() or islower() or isdigit().
979 .Case({ArgumentCondition(0U, WithinRange,
980 {{'0', '9'}, {'A', 'Z'}, {'a', 'z'}}),
981 ReturnValueCondition(OutOfRange, SingleValue(0))})
982 // The locale-specific range.
983 // No post-condition. We are completely unaware of
984 // locale-specific return values.
985 .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})})
986 .Case(
987 {ArgumentCondition(
988 0U, OutOfRange,
989 {{'0', '9'}, {'A', 'Z'}, {'a', 'z'}, {128, UCharRangeMax}}),
990 ReturnValueCondition(WithinRange, SingleValue(0))})
991 .ArgConstraint(ArgumentCondition(
992 0U, WithinRange, {{EOFv, EOFv}, {0, UCharRangeMax}})));
993 addToFunctionSummaryMap(
994 "isalpha",
995 Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
996 .Case({ArgumentCondition(0U, WithinRange, {{'A', 'Z'}, {'a', 'z'}}),
997 ReturnValueCondition(OutOfRange, SingleValue(0))})
998 // The locale-specific range.
999 .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})})
1000 .Case({ArgumentCondition(
1001 0U, OutOfRange,
1002 {{'A', 'Z'}, {'a', 'z'}, {128, UCharRangeMax}}),
1003 ReturnValueCondition(WithinRange, SingleValue(0))}));
1004 addToFunctionSummaryMap(
1005 "isascii",
1006 Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
1007 .Case({ArgumentCondition(0U, WithinRange, Range(0, 127)),
1008 ReturnValueCondition(OutOfRange, SingleValue(0))})
1009 .Case({ArgumentCondition(0U, OutOfRange, Range(0, 127)),
1010 ReturnValueCondition(WithinRange, SingleValue(0))}));
1011 addToFunctionSummaryMap(
1012 "isblank",
1013 Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
1014 .Case({ArgumentCondition(0U, WithinRange, {{'\t', '\t'}, {' ', ' '}}),
1015 ReturnValueCondition(OutOfRange, SingleValue(0))})
1016 .Case({ArgumentCondition(0U, OutOfRange, {{'\t', '\t'}, {' ', ' '}}),
1017 ReturnValueCondition(WithinRange, SingleValue(0))}));
1018 addToFunctionSummaryMap(
1019 "iscntrl",
1020 Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
1021 .Case({ArgumentCondition(0U, WithinRange, {{0, 32}, {127, 127}}),
1022 ReturnValueCondition(OutOfRange, SingleValue(0))})
1023 .Case({ArgumentCondition(0U, OutOfRange, {{0, 32}, {127, 127}}),
1024 ReturnValueCondition(WithinRange, SingleValue(0))}));
1025 addToFunctionSummaryMap(
1026 "isdigit",
1027 Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
1028 .Case({ArgumentCondition(0U, WithinRange, Range('0', '9')),
1029 ReturnValueCondition(OutOfRange, SingleValue(0))})
1030 .Case({ArgumentCondition(0U, OutOfRange, Range('0', '9')),
1031 ReturnValueCondition(WithinRange, SingleValue(0))}));
1032 addToFunctionSummaryMap(
1033 "isgraph",
1034 Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
1035 .Case({ArgumentCondition(0U, WithinRange, Range(33, 126)),
1036 ReturnValueCondition(OutOfRange, SingleValue(0))})
1037 .Case({ArgumentCondition(0U, OutOfRange, Range(33, 126)),
1038 ReturnValueCondition(WithinRange, SingleValue(0))}));
1039 addToFunctionSummaryMap(
1040 "islower",
1041 Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
1042 // Is certainly lowercase.
1043 .Case({ArgumentCondition(0U, WithinRange, Range('a', 'z')),
1044 ReturnValueCondition(OutOfRange, SingleValue(0))})
1045 // Is ascii but not lowercase.
1046 .Case({ArgumentCondition(0U, WithinRange, Range(0, 127)),
1047 ArgumentCondition(0U, OutOfRange, Range('a', 'z')),
1048 ReturnValueCondition(WithinRange, SingleValue(0))})
1049 // The locale-specific range.
1050 .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})})
1051 // Is not an unsigned char.
1052 .Case({ArgumentCondition(0U, OutOfRange, Range(0, UCharRangeMax)),
1053 ReturnValueCondition(WithinRange, SingleValue(0))}));
1054 addToFunctionSummaryMap(
1055 "isprint",
1056 Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
1057 .Case({ArgumentCondition(0U, WithinRange, Range(32, 126)),
1058 ReturnValueCondition(OutOfRange, SingleValue(0))})
1059 .Case({ArgumentCondition(0U, OutOfRange, Range(32, 126)),
1060 ReturnValueCondition(WithinRange, SingleValue(0))}));
1061 addToFunctionSummaryMap(
1062 "ispunct",
1063 Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
1064 .Case({ArgumentCondition(
1065 0U, WithinRange,
1066 {{'!', '/'}, {':', '@'}, {'[', '`'}, {'{', '~'}}),
1067 ReturnValueCondition(OutOfRange, SingleValue(0))})
1068 .Case({ArgumentCondition(
1069 0U, OutOfRange,
1070 {{'!', '/'}, {':', '@'}, {'[', '`'}, {'{', '~'}}),
1071 ReturnValueCondition(WithinRange, SingleValue(0))}));
1072 addToFunctionSummaryMap(
1073 "isspace",
1074 Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
1075 // Space, '\f', '\n', '\r', '\t', '\v'.
1076 .Case({ArgumentCondition(0U, WithinRange, {{9, 13}, {' ', ' '}}),
1077 ReturnValueCondition(OutOfRange, SingleValue(0))})
1078 // The locale-specific range.
1079 .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})})
1080 .Case({ArgumentCondition(0U, OutOfRange,
1081 {{9, 13}, {' ', ' '}, {128, UCharRangeMax}}),
1082 ReturnValueCondition(WithinRange, SingleValue(0))}));
1083 addToFunctionSummaryMap(
1084 "isupper",
1085 Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
1086 // Is certainly uppercase.
1087 .Case({ArgumentCondition(0U, WithinRange, Range('A', 'Z')),
1088 ReturnValueCondition(OutOfRange, SingleValue(0))})
1089 // The locale-specific range.
1090 .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})})
1091 // Other.
1092 .Case({ArgumentCondition(0U, OutOfRange,
1093 {{'A', 'Z'}, {128, UCharRangeMax}}),
1094 ReturnValueCondition(WithinRange, SingleValue(0))}));
1095 addToFunctionSummaryMap(
1096 "isxdigit",
1097 Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
1098 .Case({ArgumentCondition(0U, WithinRange,
1099 {{'0', '9'}, {'A', 'F'}, {'a', 'f'}}),
1100 ReturnValueCondition(OutOfRange, SingleValue(0))})
1101 .Case({ArgumentCondition(0U, OutOfRange,
1102 {{'0', '9'}, {'A', 'F'}, {'a', 'f'}}),
1103 ReturnValueCondition(WithinRange, SingleValue(0))}));
1104
1105 // The getc() family of functions that returns either a char or an EOF.
1106 if (FilePtrTy) {
1107 addToFunctionSummaryMap("getc", Getc());
1108 addToFunctionSummaryMap("fgetc", Getc());
1109 }
1110 addToFunctionSummaryMap(
1111 "getchar", Summary(ArgTypes{}, RetType{IntTy}, NoEvalCall)
1112 .Case({ReturnValueCondition(
1113 WithinRange, {{EOFv, EOFv}, {0, UCharRangeMax}})}));
1114
1115 // read()-like functions that never return more than buffer size.
1116 if (FilePtrRestrictTy) {
1117 addToFunctionSummaryMap("fread", Fread());
1118 addToFunctionSummaryMap("fwrite", Fwrite());
1119 }
1120
1121 // We are not sure how ssize_t is defined on every platform, so we
1122 // provide three variants that should cover common cases.
1123 // FIXME these are actually defined by POSIX and not by the C standard, we
1124 // should handle them together with the rest of the POSIX functions.
1125 addToFunctionSummaryMap("read", {Read(IntTy, IntMax), Read(LongTy, LongMax),
1126 Read(LongLongTy, LongLongMax)});
1127 addToFunctionSummaryMap("write", {Read(IntTy, IntMax), Read(LongTy, LongMax),
1128 Read(LongLongTy, LongLongMax)});
1129
1130 // getline()-like functions either fail or read at least the delimiter.
1131 // FIXME these are actually defined by POSIX and not by the C standard, we
1132 // should handle them together with the rest of the POSIX functions.
1133 addToFunctionSummaryMap("getline",
1134 {Getline(IntTy, IntMax), Getline(LongTy, LongMax),
1135 Getline(LongLongTy, LongLongMax)});
1136 addToFunctionSummaryMap("getdelim",
1137 {Getline(IntTy, IntMax), Getline(LongTy, LongMax),
1138 Getline(LongLongTy, LongLongMax)});
1139
1140 if (ModelPOSIX) {
1141
1142 // long a64l(const char *str64);
1143 addToFunctionSummaryMap(
1144 "a64l", Summary(ArgTypes{ConstCharPtrTy}, RetType{LongTy}, NoEvalCall)
1145 .ArgConstraint(NotNull(ArgNo(0))));
1146
1147 // char *l64a(long value);
1148 addToFunctionSummaryMap(
1149 "l64a", Summary(ArgTypes{LongTy}, RetType{CharPtrTy}, NoEvalCall)
1150 .ArgConstraint(
1151 ArgumentCondition(0, WithinRange, Range(0, LongMax))));
1152
1153 // int access(const char *pathname, int amode);
1154 addToFunctionSummaryMap("access", Summary(ArgTypes{ConstCharPtrTy, IntTy},
1155 RetType{IntTy}, NoEvalCall)
1156 .ArgConstraint(NotNull(ArgNo(0))));
1157
1158 // int faccessat(int dirfd, const char *pathname, int mode, int flags);
1159 addToFunctionSummaryMap(
1160 "faccessat", Summary(ArgTypes{IntTy, ConstCharPtrTy, IntTy, IntTy},
1161 RetType{IntTy}, NoEvalCall)
1162 .ArgConstraint(NotNull(ArgNo(1))));
1163
1164 // int dup(int fildes);
1165 addToFunctionSummaryMap(
1166 "dup", Summary(ArgTypes{IntTy}, RetType{IntTy}, NoEvalCall)
1167 .ArgConstraint(
1168 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
1169
1170 // int dup2(int fildes1, int filedes2);
1171 addToFunctionSummaryMap(
1172 "dup2",
1173 Summary(ArgTypes{IntTy, IntTy}, RetType{IntTy}, NoEvalCall)
1174 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
1175 .ArgConstraint(
1176 ArgumentCondition(1, WithinRange, Range(0, IntMax))));
1177
1178 // int fdatasync(int fildes);
1179 addToFunctionSummaryMap(
1180 "fdatasync", Summary(ArgTypes{IntTy}, RetType{IntTy}, NoEvalCall)
1181 .ArgConstraint(ArgumentCondition(0, WithinRange,
1182 Range(0, IntMax))));
1183
1184 // int fnmatch(const char *pattern, const char *string, int flags);
1185 addToFunctionSummaryMap(
1186 "fnmatch", Summary(ArgTypes{ConstCharPtrTy, ConstCharPtrTy, IntTy},
1187 RetType{IntTy}, EvalCallAsPure)
1188 .ArgConstraint(NotNull(ArgNo(0)))
1189 .ArgConstraint(NotNull(ArgNo(1))));
1190
1191 // int fsync(int fildes);
1192 addToFunctionSummaryMap(
1193 "fsync", Summary(ArgTypes{IntTy}, RetType{IntTy}, NoEvalCall)
1194 .ArgConstraint(
1195 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
1196
1197 Optional<QualType> Off_tTy = lookupType("off_t", ACtx);
1198
1199 if (Off_tTy)
1200 // int truncate(const char *path, off_t length);
1201 addToFunctionSummaryMap("truncate",
1202 Summary(ArgTypes{ConstCharPtrTy, *Off_tTy},
1203 RetType{IntTy}, NoEvalCall)
1204 .ArgConstraint(NotNull(ArgNo(0))));
1205
1206 // int symlink(const char *oldpath, const char *newpath);
1207 addToFunctionSummaryMap("symlink",
1208 Summary(ArgTypes{ConstCharPtrTy, ConstCharPtrTy},
1209 RetType{IntTy}, NoEvalCall)
1210 .ArgConstraint(NotNull(ArgNo(0)))
1211 .ArgConstraint(NotNull(ArgNo(1))));
1212
1213 // int symlinkat(const char *oldpath, int newdirfd, const char *newpath);
1214 addToFunctionSummaryMap(
1215 "symlinkat",
1216 Summary(ArgTypes{ConstCharPtrTy, IntTy, ConstCharPtrTy}, RetType{IntTy},
1217 NoEvalCall)
1218 .ArgConstraint(NotNull(ArgNo(0)))
1219 .ArgConstraint(ArgumentCondition(1, WithinRange, Range(0, IntMax)))
1220 .ArgConstraint(NotNull(ArgNo(2))));
1221
1222 if (Off_tTy)
1223 // int lockf(int fd, int cmd, off_t len);
1224 addToFunctionSummaryMap(
1225 "lockf",
1226 Summary(ArgTypes{IntTy, IntTy, *Off_tTy}, RetType{IntTy}, NoEvalCall)
1227 .ArgConstraint(
1228 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
1229
1230 Optional<QualType> Mode_tTy = lookupType("mode_t", ACtx);
1231
1232 if (Mode_tTy)
1233 // int creat(const char *pathname, mode_t mode);
1234 addToFunctionSummaryMap("creat",
1235 Summary(ArgTypes{ConstCharPtrTy, *Mode_tTy},
1236 RetType{IntTy}, NoEvalCall)
1237 .ArgConstraint(NotNull(ArgNo(0))));
1238
1239 // unsigned int sleep(unsigned int seconds);
1240 addToFunctionSummaryMap(
1241 "sleep",
1242 Summary(ArgTypes{UnsignedIntTy}, RetType{UnsignedIntTy}, NoEvalCall)
1243 .ArgConstraint(
1244 ArgumentCondition(0, WithinRange, Range(0, UnsignedIntMax))));
1245
1246 Optional<QualType> DirTy = lookupType("DIR", ACtx);
1247 Optional<QualType> DirPtrTy;
1248 if (DirTy)
1249 DirPtrTy = ACtx.getPointerType(*DirTy);
1250
1251 if (DirPtrTy)
1252 // int dirfd(DIR *dirp);
1253 addToFunctionSummaryMap(
1254 "dirfd", Summary(ArgTypes{*DirPtrTy}, RetType{IntTy}, NoEvalCall)
1255 .ArgConstraint(NotNull(ArgNo(0))));
1256
1257 // unsigned int alarm(unsigned int seconds);
1258 addToFunctionSummaryMap(
1259 "alarm",
1260 Summary(ArgTypes{UnsignedIntTy}, RetType{UnsignedIntTy}, NoEvalCall)
1261 .ArgConstraint(
1262 ArgumentCondition(0, WithinRange, Range(0, UnsignedIntMax))));
1263
1264 if (DirPtrTy)
1265 // int closedir(DIR *dir);
1266 addToFunctionSummaryMap(
1267 "closedir", Summary(ArgTypes{*DirPtrTy}, RetType{IntTy}, NoEvalCall)
1268 .ArgConstraint(NotNull(ArgNo(0))));
1269
1270 // char *strdup(const char *s);
1271 addToFunctionSummaryMap("strdup", Summary(ArgTypes{ConstCharPtrTy},
1272 RetType{CharPtrTy}, NoEvalCall)
1273 .ArgConstraint(NotNull(ArgNo(0))));
1274
1275 // char *strndup(const char *s, size_t n);
1276 addToFunctionSummaryMap(
1277 "strndup", Summary(ArgTypes{ConstCharPtrTy, SizeTy}, RetType{CharPtrTy},
1278 NoEvalCall)
1279 .ArgConstraint(NotNull(ArgNo(0)))
1280 .ArgConstraint(ArgumentCondition(1, WithinRange,
1281 Range(0, SizeMax))));
1282
1283 // wchar_t *wcsdup(const wchar_t *s);
1284 addToFunctionSummaryMap("wcsdup", Summary(ArgTypes{ConstWchar_tPtrTy},
1285 RetType{Wchar_tPtrTy}, NoEvalCall)
1286 .ArgConstraint(NotNull(ArgNo(0))));
1287
1288 // int mkstemp(char *template);
1289 addToFunctionSummaryMap(
1290 "mkstemp", Summary(ArgTypes{CharPtrTy}, RetType{IntTy}, NoEvalCall)
1291 .ArgConstraint(NotNull(ArgNo(0))));
1292
1293 // char *mkdtemp(char *template);
1294 addToFunctionSummaryMap(
1295 "mkdtemp", Summary(ArgTypes{CharPtrTy}, RetType{CharPtrTy}, NoEvalCall)
1296 .ArgConstraint(NotNull(ArgNo(0))));
1297
1298 // char *getcwd(char *buf, size_t size);
1299 addToFunctionSummaryMap(
1300 "getcwd",
1301 Summary(ArgTypes{CharPtrTy, SizeTy}, RetType{CharPtrTy}, NoEvalCall)
1302 .ArgConstraint(
1303 ArgumentCondition(1, WithinRange, Range(0, SizeMax))));
1304
1305 if (Mode_tTy) {
1306 // int mkdir(const char *pathname, mode_t mode);
1307 addToFunctionSummaryMap("mkdir",
1308 Summary(ArgTypes{ConstCharPtrTy, *Mode_tTy},
1309 RetType{IntTy}, NoEvalCall)
1310 .ArgConstraint(NotNull(ArgNo(0))));
1311
1312 // int mkdirat(int dirfd, const char *pathname, mode_t mode);
1313 addToFunctionSummaryMap(
1314 "mkdirat", Summary(ArgTypes{IntTy, ConstCharPtrTy, *Mode_tTy},
1315 RetType{IntTy}, NoEvalCall)
1316 .ArgConstraint(NotNull(ArgNo(1))));
1317 }
1318
1319 Optional<QualType> Dev_tTy = lookupType("dev_t", ACtx);
1320
1321 if (Mode_tTy && Dev_tTy) {
1322 // int mknod(const char *pathname, mode_t mode, dev_t dev);
1323 addToFunctionSummaryMap(
1324 "mknod", Summary(ArgTypes{ConstCharPtrTy, *Mode_tTy, *Dev_tTy},
1325 RetType{IntTy}, NoEvalCall)
1326 .ArgConstraint(NotNull(ArgNo(0))));
1327
1328 // int mknodat(int dirfd, const char *pathname, mode_t mode, dev_t dev);
1329 addToFunctionSummaryMap("mknodat", Summary(ArgTypes{IntTy, ConstCharPtrTy,
1330 *Mode_tTy, *Dev_tTy},
1331 RetType{IntTy}, NoEvalCall)
1332 .ArgConstraint(NotNull(ArgNo(1))));
1333 }
1334
1335 if (Mode_tTy) {
1336 // int chmod(const char *path, mode_t mode);
1337 addToFunctionSummaryMap("chmod",
1338 Summary(ArgTypes{ConstCharPtrTy, *Mode_tTy},
1339 RetType{IntTy}, NoEvalCall)
1340 .ArgConstraint(NotNull(ArgNo(0))));
1341
1342 // int fchmodat(int dirfd, const char *pathname, mode_t mode, int flags);
1343 addToFunctionSummaryMap(
1344 "fchmodat", Summary(ArgTypes{IntTy, ConstCharPtrTy, *Mode_tTy, IntTy},
1345 RetType{IntTy}, NoEvalCall)
1346 .ArgConstraint(ArgumentCondition(0, WithinRange,
1347 Range(0, IntMax)))
1348 .ArgConstraint(NotNull(ArgNo(1))));
1349
1350 // int fchmod(int fildes, mode_t mode);
1351 addToFunctionSummaryMap(
1352 "fchmod",
1353 Summary(ArgTypes{IntTy, *Mode_tTy}, RetType{IntTy}, NoEvalCall)
1354 .ArgConstraint(
1355 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
1356 }
1357
1358 Optional<QualType> Uid_tTy = lookupType("uid_t", ACtx);
1359 Optional<QualType> Gid_tTy = lookupType("gid_t", ACtx);
1360
1361 if (Uid_tTy && Gid_tTy) {
1362 // int fchownat(int dirfd, const char *pathname, uid_t owner, gid_t group,
1363 // int flags);
1364 addToFunctionSummaryMap(
1365 "fchownat",
1366 Summary(ArgTypes{IntTy, ConstCharPtrTy, *Uid_tTy, *Gid_tTy, IntTy},
1367 RetType{IntTy}, NoEvalCall)
1368 .ArgConstraint(
1369 ArgumentCondition(0, WithinRange, Range(0, IntMax)))
1370 .ArgConstraint(NotNull(ArgNo(1))));
1371
1372 // int chown(const char *path, uid_t owner, gid_t group);
1373 addToFunctionSummaryMap(
1374 "chown", Summary(ArgTypes{ConstCharPtrTy, *Uid_tTy, *Gid_tTy},
1375 RetType{IntTy}, NoEvalCall)
1376 .ArgConstraint(NotNull(ArgNo(0))));
1377
1378 // int lchown(const char *path, uid_t owner, gid_t group);
1379 addToFunctionSummaryMap(
1380 "lchown", Summary(ArgTypes{ConstCharPtrTy, *Uid_tTy, *Gid_tTy},
1381 RetType{IntTy}, NoEvalCall)
1382 .ArgConstraint(NotNull(ArgNo(0))));
1383
1384 // int fchown(int fildes, uid_t owner, gid_t group);
1385 addToFunctionSummaryMap(
1386 "fchown", Summary(ArgTypes{IntTy, *Uid_tTy, *Gid_tTy}, RetType{IntTy},
1387 NoEvalCall)
1388 .ArgConstraint(ArgumentCondition(0, WithinRange,
1389 Range(0, IntMax))));
1390 }
1391
1392 // int rmdir(const char *pathname);
1393 addToFunctionSummaryMap(
1394 "rmdir", Summary(ArgTypes{ConstCharPtrTy}, RetType{IntTy}, NoEvalCall)
1395 .ArgConstraint(NotNull(ArgNo(0))));
1396
1397 // int chdir(const char *path);
1398 addToFunctionSummaryMap(
1399 "chdir", Summary(ArgTypes{ConstCharPtrTy}, RetType{IntTy}, NoEvalCall)
1400 .ArgConstraint(NotNull(ArgNo(0))));
1401
1402 // int link(const char *oldpath, const char *newpath);
1403 addToFunctionSummaryMap("link",
1404 Summary(ArgTypes{ConstCharPtrTy, ConstCharPtrTy},
1405 RetType{IntTy}, NoEvalCall)
1406 .ArgConstraint(NotNull(ArgNo(0)))
1407 .ArgConstraint(NotNull(ArgNo(1))));
1408
1409 // int linkat(int fd1, const char *path1, int fd2, const char *path2,
1410 // int flag);
1411 addToFunctionSummaryMap(
1412 "linkat",
1413 Summary(ArgTypes{IntTy, ConstCharPtrTy, IntTy, ConstCharPtrTy, IntTy},
1414 RetType{IntTy}, NoEvalCall)
1415 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
1416 .ArgConstraint(NotNull(ArgNo(1)))
1417 .ArgConstraint(ArgumentCondition(2, WithinRange, Range(0, IntMax)))
1418 .ArgConstraint(NotNull(ArgNo(3))));
1419
1420 // int unlink(const char *pathname);
1421 addToFunctionSummaryMap(
1422 "unlink", Summary(ArgTypes{ConstCharPtrTy}, RetType{IntTy}, NoEvalCall)
1423 .ArgConstraint(NotNull(ArgNo(0))));
1424
1425 // int unlinkat(int fd, const char *path, int flag);
1426 addToFunctionSummaryMap(
1427 "unlinkat",
1428 Summary(ArgTypes{IntTy, ConstCharPtrTy, IntTy}, RetType{IntTy},
1429 NoEvalCall)
1430 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
1431 .ArgConstraint(NotNull(ArgNo(1))));
1432
1433 Optional<QualType> StructStatTy = lookupType("stat", ACtx);
1434 Optional<QualType> StructStatPtrTy, StructStatPtrRestrictTy;
1435 if (StructStatTy) {
1436 StructStatPtrTy = ACtx.getPointerType(*StructStatTy);
1437 StructStatPtrRestrictTy = ACtx.getLangOpts().C99
1438 ? ACtx.getRestrictType(*StructStatPtrTy)
1439 : *StructStatPtrTy;
1440 }
1441
1442 if (StructStatPtrTy)
1443 // int fstat(int fd, struct stat *statbuf);
1444 addToFunctionSummaryMap(
1445 "fstat",
1446 Summary(ArgTypes{IntTy, *StructStatPtrTy}, RetType{IntTy}, NoEvalCall)
1447 .ArgConstraint(
1448 ArgumentCondition(0, WithinRange, Range(0, IntMax)))
1449 .ArgConstraint(NotNull(ArgNo(1))));
1450
1451 if (StructStatPtrRestrictTy) {
1452 // int stat(const char *restrict path, struct stat *restrict buf);
1453 addToFunctionSummaryMap(
1454 "stat",
1455 Summary(ArgTypes{ConstCharPtrRestrictTy, *StructStatPtrRestrictTy},
1456 RetType{IntTy}, NoEvalCall)
1457 .ArgConstraint(NotNull(ArgNo(0)))
1458 .ArgConstraint(NotNull(ArgNo(1))));
1459
1460 // int lstat(const char *restrict path, struct stat *restrict buf);
1461 addToFunctionSummaryMap(
1462 "lstat",
1463 Summary(ArgTypes{ConstCharPtrRestrictTy, *StructStatPtrRestrictTy},
1464 RetType{IntTy}, NoEvalCall)
1465 .ArgConstraint(NotNull(ArgNo(0)))
1466 .ArgConstraint(NotNull(ArgNo(1))));
1467
1468 // int fstatat(int fd, const char *restrict path,
1469 // struct stat *restrict buf, int flag);
1470 addToFunctionSummaryMap(
1471 "fstatat", Summary(ArgTypes{IntTy, ConstCharPtrRestrictTy,
1472 *StructStatPtrRestrictTy, IntTy},
1473 RetType{IntTy}, NoEvalCall)
1474 .ArgConstraint(ArgumentCondition(0, WithinRange,
1475 Range(0, IntMax)))
1476 .ArgConstraint(NotNull(ArgNo(1)))
1477 .ArgConstraint(NotNull(ArgNo(2))));
1478 }
1479
1480 if (DirPtrTy) {
1481 // DIR *opendir(const char *name);
1482 addToFunctionSummaryMap("opendir", Summary(ArgTypes{ConstCharPtrTy},
1483 RetType{*DirPtrTy}, NoEvalCall)
1484 .ArgConstraint(NotNull(ArgNo(0))));
1485
1486 // DIR *fdopendir(int fd);
1487 addToFunctionSummaryMap(
1488 "fdopendir", Summary(ArgTypes{IntTy}, RetType{*DirPtrTy}, NoEvalCall)
1489 .ArgConstraint(ArgumentCondition(0, WithinRange,
1490 Range(0, IntMax))));
1491 }
1492
1493 // int isatty(int fildes);
1494 addToFunctionSummaryMap(
1495 "isatty", Summary(ArgTypes{IntTy}, RetType{IntTy}, NoEvalCall)
1496 .ArgConstraint(
1497 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
1498
1499 if (FilePtrTy) {
1500 // FILE *popen(const char *command, const char *type);
1501 addToFunctionSummaryMap("popen",
1502 Summary(ArgTypes{ConstCharPtrTy, ConstCharPtrTy},
1503 RetType{*FilePtrTy}, NoEvalCall)
1504 .ArgConstraint(NotNull(ArgNo(0)))
1505 .ArgConstraint(NotNull(ArgNo(1))));
1506
1507 // int pclose(FILE *stream);
1508 addToFunctionSummaryMap(
1509 "pclose", Summary(ArgTypes{*FilePtrTy}, RetType{IntTy}, NoEvalCall)
1510 .ArgConstraint(NotNull(ArgNo(0))));
1511 }
1512
1513 // int close(int fildes);
1514 addToFunctionSummaryMap(
1515 "close", Summary(ArgTypes{IntTy}, RetType{IntTy}, NoEvalCall)
1516 .ArgConstraint(
1517 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
1518
1519 // long fpathconf(int fildes, int name);
1520 addToFunctionSummaryMap(
1521 "fpathconf",
1522 Summary(ArgTypes{IntTy, IntTy}, RetType{LongTy}, NoEvalCall)
1523 .ArgConstraint(
1524 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
1525
1526 // long pathconf(const char *path, int name);
1527 addToFunctionSummaryMap("pathconf", Summary(ArgTypes{ConstCharPtrTy, IntTy},
1528 RetType{LongTy}, NoEvalCall)
1529 .ArgConstraint(NotNull(ArgNo(0))));
1530
1531 if (FilePtrTy)
1532 // FILE *fdopen(int fd, const char *mode);
1533 addToFunctionSummaryMap(
1534 "fdopen", Summary(ArgTypes{IntTy, ConstCharPtrTy},
1535 RetType{*FilePtrTy}, NoEvalCall)
1536 .ArgConstraint(
1537 ArgumentCondition(0, WithinRange, Range(0, IntMax)))
1538 .ArgConstraint(NotNull(ArgNo(1))));
1539
1540 if (DirPtrTy) {
1541 // void rewinddir(DIR *dir);
1542 addToFunctionSummaryMap(
1543 "rewinddir", Summary(ArgTypes{*DirPtrTy}, RetType{VoidTy}, NoEvalCall)
1544 .ArgConstraint(NotNull(ArgNo(0))));
1545
1546 // void seekdir(DIR *dirp, long loc);
1547 addToFunctionSummaryMap("seekdir", Summary(ArgTypes{*DirPtrTy, LongTy},
1548 RetType{VoidTy}, NoEvalCall)
1549 .ArgConstraint(NotNull(ArgNo(0))));
1550 }
1551
1552 // int rand_r(unsigned int *seedp);
1553 addToFunctionSummaryMap("rand_r", Summary(ArgTypes{UnsignedIntPtrTy},
1554 RetType{IntTy}, NoEvalCall)
1555 .ArgConstraint(NotNull(ArgNo(0))));
1556
1557 // int strcasecmp(const char *s1, const char *s2);
1558 addToFunctionSummaryMap("strcasecmp",
1559 Summary(ArgTypes{ConstCharPtrTy, ConstCharPtrTy},
1560 RetType{IntTy}, EvalCallAsPure)
1561 .ArgConstraint(NotNull(ArgNo(0)))
1562 .ArgConstraint(NotNull(ArgNo(1))));
1563
1564 // int strncasecmp(const char *s1, const char *s2, size_t n);
1565 addToFunctionSummaryMap(
1566 "strncasecmp", Summary(ArgTypes{ConstCharPtrTy, ConstCharPtrTy, SizeTy},
1567 RetType{IntTy}, EvalCallAsPure)
1568 .ArgConstraint(NotNull(ArgNo(0)))
1569 .ArgConstraint(NotNull(ArgNo(1)))
1570 .ArgConstraint(ArgumentCondition(
1571 2, WithinRange, Range(0, SizeMax))));
1572
1573 if (FilePtrTy && Off_tTy) {
1574
1575 // int fileno(FILE *stream);
1576 addToFunctionSummaryMap(
1577 "fileno", Summary(ArgTypes{*FilePtrTy}, RetType{IntTy}, NoEvalCall)
1578 .ArgConstraint(NotNull(ArgNo(0))));
1579
1580 // int fseeko(FILE *stream, off_t offset, int whence);
1581 addToFunctionSummaryMap("fseeko",
1582 Summary(ArgTypes{*FilePtrTy, *Off_tTy, IntTy},
1583 RetType{IntTy}, NoEvalCall)
1584 .ArgConstraint(NotNull(ArgNo(0))));
1585
1586 // off_t ftello(FILE *stream);
1587 addToFunctionSummaryMap(
1588 "ftello", Summary(ArgTypes{*FilePtrTy}, RetType{*Off_tTy}, NoEvalCall)
1589 .ArgConstraint(NotNull(ArgNo(0))));
1590 }
1591
1592 if (Off_tTy) {
1593 Optional<RangeInt> Off_tMax = BVF.getMaxValue(*Off_tTy).getLimitedValue();
1594
1595 // void *mmap(void *addr, size_t length, int prot, int flags, int fd,
1596 // off_t offset);
1597 addToFunctionSummaryMap(
1598 "mmap",
1599 Summary(ArgTypes{VoidPtrTy, SizeTy, IntTy, IntTy, IntTy, *Off_tTy},
1600 RetType{VoidPtrTy}, NoEvalCall)
1601 .ArgConstraint(
1602 ArgumentCondition(1, WithinRange, Range(1, SizeMax)))
1603 .ArgConstraint(
1604 ArgumentCondition(4, WithinRange, Range(0, *Off_tMax))));
1605 }
1606
1607 Optional<QualType> Off64_tTy = lookupType("off64_t", ACtx);
1608 Optional<RangeInt> Off64_tMax;
1609 if (Off64_tTy) {
1610 Off64_tMax = BVF.getMaxValue(*Off_tTy).getLimitedValue();
1611 // void *mmap64(void *addr, size_t length, int prot, int flags, int fd,
1612 // off64_t offset);
1613 addToFunctionSummaryMap(
1614 "mmap64",
1615 Summary(ArgTypes{VoidPtrTy, SizeTy, IntTy, IntTy, IntTy, *Off64_tTy},
1616 RetType{VoidPtrTy}, NoEvalCall)
1617 .ArgConstraint(
1618 ArgumentCondition(1, WithinRange, Range(1, SizeMax)))
1619 .ArgConstraint(
1620 ArgumentCondition(4, WithinRange, Range(0, *Off64_tMax))));
1621 }
1622
1623 // int pipe(int fildes[2]);
1624 addToFunctionSummaryMap(
1625 "pipe", Summary(ArgTypes{IntPtrTy}, RetType{IntTy}, NoEvalCall)
1626 .ArgConstraint(NotNull(ArgNo(0))));
1627
1628 if (Off_tTy)
1629 // off_t lseek(int fildes, off_t offset, int whence);
1630 addToFunctionSummaryMap(
1631 "lseek", Summary(ArgTypes{IntTy, *Off_tTy, IntTy}, RetType{*Off_tTy},
1632 NoEvalCall)
1633 .ArgConstraint(ArgumentCondition(0, WithinRange,
1634 Range(0, IntMax))));
1635
1636 Optional<QualType> Ssize_tTy = lookupType("ssize_t", ACtx);
1637
1638 if (Ssize_tTy) {
1639 // ssize_t readlink(const char *restrict path, char *restrict buf,
1640 // size_t bufsize);
1641 addToFunctionSummaryMap(
1642 "readlink",
1643 Summary(ArgTypes{ConstCharPtrRestrictTy, CharPtrRestrictTy, SizeTy},
1644 RetType{*Ssize_tTy}, NoEvalCall)
1645 .ArgConstraint(NotNull(ArgNo(0)))
1646 .ArgConstraint(NotNull(ArgNo(1)))
1647 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
1648 /*BufSize=*/ArgNo(2)))
1649 .ArgConstraint(
1650 ArgumentCondition(2, WithinRange, Range(0, SizeMax))));
1651
1652 // ssize_t readlinkat(int fd, const char *restrict path,
1653 // char *restrict buf, size_t bufsize);
1654 addToFunctionSummaryMap(
1655 "readlinkat", Summary(ArgTypes{IntTy, ConstCharPtrRestrictTy,
1656 CharPtrRestrictTy, SizeTy},
1657 RetType{*Ssize_tTy}, NoEvalCall)
1658 .ArgConstraint(ArgumentCondition(0, WithinRange,
1659 Range(0, IntMax)))
1660 .ArgConstraint(NotNull(ArgNo(1)))
1661 .ArgConstraint(NotNull(ArgNo(2)))
1662 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(2),
1663 /*BufSize=*/ArgNo(3)))
1664 .ArgConstraint(ArgumentCondition(
1665 3, WithinRange, Range(0, SizeMax))));
1666 }
1667
1668 // int renameat(int olddirfd, const char *oldpath, int newdirfd, const char
1669 // *newpath);
1670 addToFunctionSummaryMap("renameat", Summary(ArgTypes{IntTy, ConstCharPtrTy,
1671 IntTy, ConstCharPtrTy},
1672 RetType{IntTy}, NoEvalCall)
1673 .ArgConstraint(NotNull(ArgNo(1)))
1674 .ArgConstraint(NotNull(ArgNo(3))));
1675
1676 // char *realpath(const char *restrict file_name,
1677 // char *restrict resolved_name);
1678 addToFunctionSummaryMap(
1679 "realpath", Summary(ArgTypes{ConstCharPtrRestrictTy, CharPtrRestrictTy},
1680 RetType{CharPtrTy}, NoEvalCall)
1681 .ArgConstraint(NotNull(ArgNo(0))));
1682
1683 QualType CharPtrConstPtr = ACtx.getPointerType(CharPtrTy.withConst());
1684
1685 // int execv(const char *path, char *const argv[]);
1686 addToFunctionSummaryMap("execv",
1687 Summary(ArgTypes{ConstCharPtrTy, CharPtrConstPtr},
1688 RetType{IntTy}, NoEvalCall)
1689 .ArgConstraint(NotNull(ArgNo(0))));
1690
1691 // int execvp(const char *file, char *const argv[]);
1692 addToFunctionSummaryMap("execvp",
1693 Summary(ArgTypes{ConstCharPtrTy, CharPtrConstPtr},
1694 RetType{IntTy}, NoEvalCall)
1695 .ArgConstraint(NotNull(ArgNo(0))));
1696
1697 // int getopt(int argc, char * const argv[], const char *optstring);
1698 addToFunctionSummaryMap(
1699 "getopt",
1700 Summary(ArgTypes{IntTy, CharPtrConstPtr, ConstCharPtrTy},
1701 RetType{IntTy}, NoEvalCall)
1702 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
1703 .ArgConstraint(NotNull(ArgNo(1)))
1704 .ArgConstraint(NotNull(ArgNo(2))));
1705 }
1706
1707 // Functions for testing.
1708 if (ChecksEnabled[CK_StdCLibraryFunctionsTesterChecker]) {
1709 addToFunctionSummaryMap(
1710 "__two_constrained_args",
1711 Summary(ArgTypes{IntTy, IntTy}, RetType{IntTy}, EvalCallAsPure)
1712 .ArgConstraint(ArgumentCondition(0U, WithinRange, SingleValue(1)))
1713 .ArgConstraint(ArgumentCondition(1U, WithinRange, SingleValue(1))));
1714 addToFunctionSummaryMap(
1715 "__arg_constrained_twice",
1716 Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
1717 .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(1)))
1718 .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(2))));
1719 addToFunctionSummaryMap(
1720 "__defaultparam",
1721 Summary(ArgTypes{Irrelevant, IntTy}, RetType{IntTy}, EvalCallAsPure)
1722 .ArgConstraint(NotNull(ArgNo(0))));
1723 addToFunctionSummaryMap("__variadic",
1724 Summary(ArgTypes{VoidPtrTy, ConstCharPtrTy},
1725 RetType{IntTy}, EvalCallAsPure)
1726 .ArgConstraint(NotNull(ArgNo(0)))
1727 .ArgConstraint(NotNull(ArgNo(1))));
1728 addToFunctionSummaryMap(
1729 "__buf_size_arg_constraint",
1730 Summary(ArgTypes{ConstVoidPtrTy, SizeTy}, RetType{IntTy},
1731 EvalCallAsPure)
1732 .ArgConstraint(
1733 BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1))));
1734 addToFunctionSummaryMap(
1735 "__buf_size_arg_constraint_mul",
1736 Summary(ArgTypes{ConstVoidPtrTy, SizeTy, SizeTy}, RetType{IntTy},
1737 EvalCallAsPure)
1738 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1),
1739 /*BufSizeMultiplier=*/ArgNo(2))));
1740 }
1741 }
1742
registerStdCLibraryFunctionsChecker(CheckerManager & mgr)1743 void ento::registerStdCLibraryFunctionsChecker(CheckerManager &mgr) {
1744 auto *Checker = mgr.registerChecker<StdLibraryFunctionsChecker>();
1745 Checker->DisplayLoadedSummaries =
1746 mgr.getAnalyzerOptions().getCheckerBooleanOption(
1747 Checker, "DisplayLoadedSummaries");
1748 Checker->ModelPOSIX =
1749 mgr.getAnalyzerOptions().getCheckerBooleanOption(Checker, "ModelPOSIX");
1750 }
1751
shouldRegisterStdCLibraryFunctionsChecker(const CheckerManager & mgr)1752 bool ento::shouldRegisterStdCLibraryFunctionsChecker(const CheckerManager &mgr) {
1753 return true;
1754 }
1755
1756 #define REGISTER_CHECKER(name) \
1757 void ento::register##name(CheckerManager &mgr) { \
1758 StdLibraryFunctionsChecker *checker = \
1759 mgr.getChecker<StdLibraryFunctionsChecker>(); \
1760 checker->ChecksEnabled[StdLibraryFunctionsChecker::CK_##name] = true; \
1761 checker->CheckNames[StdLibraryFunctionsChecker::CK_##name] = \
1762 mgr.getCurrentCheckerName(); \
1763 } \
1764 \
1765 bool ento::shouldRegister##name(const CheckerManager &mgr) { return true; }
1766
1767 REGISTER_CHECKER(StdCLibraryFunctionArgsChecker)
1768 REGISTER_CHECKER(StdCLibraryFunctionsTesterChecker)
1769