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