clang 24.0.0git
StdLibraryFunctionsChecker.cpp
Go to the documentation of this file.
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 effects), 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"
53#include "llvm/ADT/STLExtras.h"
54#include "llvm/ADT/SmallString.h"
55#include "llvm/ADT/StringExtras.h"
56#include "llvm/Support/FormatVariadic.h"
57
58#include <optional>
59#include <string>
60
61using namespace clang;
62using namespace clang::ento;
63
64namespace {
65class StdLibraryFunctionsChecker
66 : public Checker<check::PreCall, check::PostCall, eval::Call> {
67
68 class Summary;
69
70 /// Specify how much the analyzer engine should entrust modeling this function
71 /// to us.
72 enum InvalidationKind {
73 /// No \c eval::Call for the function, it can be modeled elsewhere.
74 /// This checker checks only pre and post conditions.
75 NoEvalCall,
76 /// The function is modeled completely in this checker.
77 EvalCallAsPure
78 };
79
80 /// Given a range, should the argument stay inside or outside this range?
81 enum RangeKind { OutOfRange, WithinRange };
82
83 static RangeKind negateKind(RangeKind K) {
84 switch (K) {
85 case OutOfRange:
86 return WithinRange;
87 case WithinRange:
88 return OutOfRange;
89 }
90 llvm_unreachable("Unknown range kind");
91 }
92
93 /// The universal integral type to use in value range descriptions.
94 /// Unsigned to make sure overflows are well-defined.
95 typedef uint64_t RangeInt;
96
97 /// Describes a single range constraint. Eg. {{0, 1}, {3, 4}} is
98 /// a non-negative integer, which less than 5 and not equal to 2.
99 typedef std::vector<std::pair<RangeInt, RangeInt>> IntRangeVector;
100
101 /// A reference to an argument or return value by its number.
102 /// ArgNo in CallExpr and CallEvent is defined as Unsigned, but
103 /// obviously uint32_t should be enough for all practical purposes.
104 typedef uint32_t ArgNo;
105 /// Special argument number for specifying the return value.
106 static const ArgNo Ret;
107
108 /// Get a string representation of an argument index.
109 /// E.g.: (1) -> '1st arg', (2) - > '2nd arg'
110 static void printArgDesc(ArgNo, llvm::raw_ostream &Out);
111 /// Print value X of the argument in form " (which is X)",
112 /// if the value is a fixed known value, otherwise print nothing.
113 /// This is used as simple explanation of values if possible.
114 static void printArgValueInfo(ArgNo ArgN, ProgramStateRef State,
115 const CallEvent &Call, llvm::raw_ostream &Out);
116 /// Append textual description of a numeric range [RMin,RMax] to
117 /// \p Out.
118 static void appendInsideRangeDesc(llvm::APSInt RMin, llvm::APSInt RMax,
119 QualType ArgT, BasicValueFactory &BVF,
120 llvm::raw_ostream &Out);
121 /// Append textual description of a numeric range out of [RMin,RMax] to
122 /// \p Out.
123 static void appendOutOfRangeDesc(llvm::APSInt RMin, llvm::APSInt RMax,
124 QualType ArgT, BasicValueFactory &BVF,
125 llvm::raw_ostream &Out);
126
127 class ValueConstraint;
128
129 /// Pointer to the ValueConstraint. We need a copyable, polymorphic and
130 /// default initializable type (vector needs that). A raw pointer was good,
131 /// however, we cannot default initialize that. unique_ptr makes the Summary
132 /// class non-copyable, therefore not an option. Releasing the copyability
133 /// requirement would render the initialization of the Summary map infeasible.
134 /// Mind that a pointer to a new value constraint is created when the negate
135 /// function is used.
136 using ValueConstraintPtr = std::shared_ptr<ValueConstraint>;
137
138 /// Polymorphic base class that represents a constraint on a given argument
139 /// (or return value) of a function. Derived classes implement different kind
140 /// of constraints, e.g range constraints or correlation between two
141 /// arguments.
142 /// These are used as argument constraints (preconditions) of functions, in
143 /// which case a bug report may be emitted if the constraint is not satisfied.
144 /// Another use is as conditions for summary cases, to create different
145 /// classes of behavior for a function. In this case no description of the
146 /// constraint is needed because the summary cases have an own (not generated)
147 /// description string.
148 class ValueConstraint {
149 public:
150 ValueConstraint(ArgNo ArgN) : ArgN(ArgN) {}
151 virtual ~ValueConstraint() {}
152
153 /// Apply the effects of the constraint on the given program state. If null
154 /// is returned then the constraint is not feasible.
155 virtual ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
156 const Summary &Summary,
157 CheckerContext &C) const = 0;
158
159 /// Represents that in which context do we require a description of the
160 /// constraint.
161 enum DescriptionKind {
162 /// Describe a constraint that was violated.
163 /// Description should start with something like "should be".
164 Violation,
165 /// Describe a constraint that was assumed to be true.
166 /// This can be used when a precondition is satisfied, or when a summary
167 /// case is applied.
168 /// Description should start with something like "is".
169 Assumption
170 };
171
172 /// Give a description that explains the constraint to the user. Used when
173 /// a bug is reported or when the constraint is applied and displayed as a
174 /// note. The description should not mention the argument (getArgNo).
175 /// See StdLibraryFunctionsChecker::reportBug about how this function is
176 /// used (this function is used not only there).
177 virtual void describe(DescriptionKind DK, const CallEvent &Call,
178 ProgramStateRef State, const Summary &Summary,
179 llvm::raw_ostream &Out) const {
180 // There are some descendant classes that are not used as argument
181 // constraints, e.g. ComparisonConstraint. In that case we can safely
182 // ignore the implementation of this function.
183 llvm_unreachable(
184 "Description not implemented for summary case constraints");
185 }
186
187 /// Give a description that explains the actual argument value (where the
188 /// current ValueConstraint applies to) to the user. This function should be
189 /// called only when the current constraint is satisfied by the argument.
190 /// It should produce a more precise description than the constraint itself.
191 /// The actual value of the argument and the program state can be used to
192 /// make the description more precise. In the most simple case, if the
193 /// argument has a fixed known value this value can be printed into \p Out,
194 /// this is done by default.
195 /// The function should return true if a description was printed to \p Out,
196 /// otherwise false.
197 /// See StdLibraryFunctionsChecker::reportBug about how this function is
198 /// used.
199 virtual bool describeArgumentValue(const CallEvent &Call,
200 ProgramStateRef State,
201 const Summary &Summary,
202 llvm::raw_ostream &Out) const {
203 if (auto N = getArgSVal(Call, getArgNo()).getAs<NonLoc>()) {
204 if (const llvm::APSInt *Int = N->getAsInteger()) {
205 Out << *Int;
206 return true;
207 }
208 }
209 return false;
210 }
211
212 /// Return those arguments that should be tracked when we report a bug about
213 /// argument constraint violation. By default it is the argument that is
214 /// constrained, however, in some special cases we need to track other
215 /// arguments as well. E.g. a buffer size might be encoded in another
216 /// argument.
217 /// The "return value" argument number can not occur as returned value.
218 virtual std::vector<ArgNo> getArgsToTrack() const { return {ArgN}; }
219
220 /// Get a constraint that represents exactly the opposite of the current.
221 virtual ValueConstraintPtr negate() const {
222 llvm_unreachable("Not implemented");
223 };
224
225 /// Check whether the constraint is malformed or not. It is malformed if the
226 /// specified argument has a mismatch with the given FunctionDecl (e.g. the
227 /// arg number is out-of-range of the function's argument list).
228 /// This condition can indicate if a probably wrong or unexpected function
229 /// was found where the constraint is to be applied.
230 bool checkValidity(const FunctionDecl *FD) const {
231 const bool ValidArg = ArgN == Ret || ArgN < FD->getNumParams();
232 assert(ValidArg && "Arg out of range!");
233 if (!ValidArg)
234 return false;
235 // Subclasses may further refine the validation.
236 return checkSpecificValidity(FD);
237 }
238
239 /// Return the argument number (may be placeholder for "return value").
240 ArgNo getArgNo() const { return ArgN; }
241
242 protected:
243 /// Argument to which to apply the constraint. It can be a real argument of
244 /// the function to check, or a special value to indicate the return value
245 /// of the function.
246 /// Every constraint is assigned to one main argument, even if other
247 /// arguments are involved.
248 ArgNo ArgN;
249
250 /// Do constraint-specific validation check.
251 virtual bool checkSpecificValidity(const FunctionDecl *FD) const {
252 return true;
253 }
254 };
255
256 /// Check if a single argument falls into a specific "range".
257 /// A range is formed as a set of intervals.
258 /// E.g. \code {['A', 'Z'], ['a', 'z'], ['_', '_']} \endcode
259 /// The intervals are closed intervals that contain one or more values.
260 ///
261 /// The default constructed RangeConstraint has an empty range, applying
262 /// such constraint does not involve any assumptions, thus the State remains
263 /// unchanged. This is meaningful, if the range is dependent on a looked up
264 /// type (e.g. [0, Socklen_tMax]). If the type is not found, then the range
265 /// is default initialized to be empty.
266 class RangeConstraint : public ValueConstraint {
267 /// The constraint can be specified by allowing or disallowing the range.
268 /// WithinRange indicates allowing the range, OutOfRange indicates
269 /// disallowing it (allowing the complementary range).
270 RangeKind Kind;
271
272 /// A set of intervals.
273 IntRangeVector Ranges;
274
275 /// A textual description of this constraint for the specific case where the
276 /// constraint is used. If empty a generated description will be used that
277 /// is built from the range of the constraint.
278 StringRef Description;
279
280 public:
281 RangeConstraint(ArgNo ArgN, RangeKind Kind, const IntRangeVector &Ranges,
282 StringRef Desc = "")
283 : ValueConstraint(ArgN), Kind(Kind), Ranges(Ranges), Description(Desc) {
284 }
285
286 const IntRangeVector &getRanges() const { return Ranges; }
287
288 ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
289 const Summary &Summary,
290 CheckerContext &C) const override;
291
292 void describe(DescriptionKind DK, const CallEvent &Call,
293 ProgramStateRef State, const Summary &Summary,
294 llvm::raw_ostream &Out) const override;
295
296 bool describeArgumentValue(const CallEvent &Call, ProgramStateRef State,
297 const Summary &Summary,
298 llvm::raw_ostream &Out) const override;
299
300 ValueConstraintPtr negate() const override {
301 RangeConstraint Tmp(*this);
302 Tmp.Kind = negateKind(Kind);
303 return std::make_shared<RangeConstraint>(Tmp);
304 }
305
306 protected:
307 bool checkSpecificValidity(const FunctionDecl *FD) const override {
308 return getArgType(FD, ArgN)->isIntegralType(FD->getASTContext());
309 }
310
311 private:
312 /// A callback function that is used when iterating over the range
313 /// intervals. It gets the begin and end (inclusive) of one interval.
314 /// This is used to make any kind of task possible that needs an iteration
315 /// over the intervals.
316 using RangeApplyFunction =
317 std::function<bool(const llvm::APSInt &Min, const llvm::APSInt &Max)>;
318
319 /// Call a function on the intervals of the range.
320 /// The function is called with all intervals in the range.
321 void applyOnWithinRange(BasicValueFactory &BVF, QualType ArgT,
322 const RangeApplyFunction &F) const;
323 /// Call a function on all intervals in the complementary range.
324 /// The function is called with all intervals that fall out of the range.
325 /// E.g. consider an interval list [A, B] and [C, D]
326 /// \code
327 /// -------+--------+------------------+------------+----------->
328 /// A B C D
329 /// \endcode
330 /// We get the ranges [-inf, A - 1], [D + 1, +inf], [B + 1, C - 1].
331 /// The \p ArgT is used to determine the min and max of the type that is
332 /// used as "-inf" and "+inf".
333 void applyOnOutOfRange(BasicValueFactory &BVF, QualType ArgT,
334 const RangeApplyFunction &F) const;
335 /// Call a function on the intervals of the range or the complementary
336 /// range.
337 void applyOnRange(RangeKind Kind, BasicValueFactory &BVF, QualType ArgT,
338 const RangeApplyFunction &F) const {
339 switch (Kind) {
340 case OutOfRange:
341 applyOnOutOfRange(BVF, ArgT, F);
342 break;
343 case WithinRange:
344 applyOnWithinRange(BVF, ArgT, F);
345 break;
346 };
347 }
348 };
349
350 /// Check relation of an argument to another.
351 class ComparisonConstraint : public ValueConstraint {
353 ArgNo OtherArgN;
354
355 public:
356 ComparisonConstraint(ArgNo ArgN, BinaryOperator::Opcode Opcode,
357 ArgNo OtherArgN)
358 : ValueConstraint(ArgN), Opcode(Opcode), OtherArgN(OtherArgN) {}
359 ArgNo getOtherArgNo() const { return OtherArgN; }
360 BinaryOperator::Opcode getOpcode() const { return Opcode; }
361 ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
362 const Summary &Summary,
363 CheckerContext &C) const override;
364 };
365
366 /// Check null or non-null-ness of an argument that is of pointer type.
367 class NullnessConstraint : public ValueConstraint {
368 using ValueConstraint::ValueConstraint;
369 // This variable has a role when we negate the constraint.
370 bool CannotBeNull = true;
371
372 public:
373 NullnessConstraint(ArgNo ArgN, bool CannotBeNull = true)
374 : ValueConstraint(ArgN), CannotBeNull(CannotBeNull) {}
375
376 ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
377 const Summary &Summary,
378 CheckerContext &C) const override;
379
380 void describe(DescriptionKind DK, const CallEvent &Call,
381 ProgramStateRef State, const Summary &Summary,
382 llvm::raw_ostream &Out) const override;
383
384 bool describeArgumentValue(const CallEvent &Call, ProgramStateRef State,
385 const Summary &Summary,
386 llvm::raw_ostream &Out) const override;
387
388 ValueConstraintPtr negate() const override {
389 NullnessConstraint Tmp(*this);
390 Tmp.CannotBeNull = !this->CannotBeNull;
391 return std::make_shared<NullnessConstraint>(Tmp);
392 }
393
394 protected:
395 bool checkSpecificValidity(const FunctionDecl *FD) const override {
396 const bool ValidArg = getArgType(FD, ArgN)->isPointerType();
397 assert(ValidArg &&
398 "This constraint should be applied only on a pointer type");
399 return ValidArg;
400 }
401 };
402
403 /// Check null or non-null-ness of an argument that is of pointer type.
404 /// The argument is meant to be a buffer that has a size constraint, and it
405 /// is allowed to have a NULL value if the size is 0. The size can depend on
406 /// 1 or 2 additional arguments, if one of these is 0 the buffer is allowed to
407 /// be NULL. Otherwise, the buffer pointer must be non-null. This is useful
408 /// for functions like `fread` which have this special property.
409 class BufferNullnessConstraint : public ValueConstraint {
410 using ValueConstraint::ValueConstraint;
411 ArgNo SizeArg1N;
412 std::optional<ArgNo> SizeArg2N;
413 // This variable has a role when we negate the constraint.
414 bool CannotBeNull = true;
415
416 public:
417 BufferNullnessConstraint(ArgNo ArgN, ArgNo SizeArg1N,
418 std::optional<ArgNo> SizeArg2N,
419 bool CannotBeNull = true)
420 : ValueConstraint(ArgN), SizeArg1N(SizeArg1N), SizeArg2N(SizeArg2N),
421 CannotBeNull(CannotBeNull) {}
422
423 ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
424 const Summary &Summary,
425 CheckerContext &C) const override;
426
427 void describe(DescriptionKind DK, const CallEvent &Call,
428 ProgramStateRef State, const Summary &Summary,
429 llvm::raw_ostream &Out) const override;
430
431 bool describeArgumentValue(const CallEvent &Call, ProgramStateRef State,
432 const Summary &Summary,
433 llvm::raw_ostream &Out) const override;
434
435 ValueConstraintPtr negate() const override {
436 BufferNullnessConstraint Tmp(*this);
437 Tmp.CannotBeNull = !this->CannotBeNull;
438 return std::make_shared<BufferNullnessConstraint>(Tmp);
439 }
440
441 protected:
442 bool checkSpecificValidity(const FunctionDecl *FD) const override {
443 const bool ValidArg = getArgType(FD, ArgN)->isPointerType();
444 assert(ValidArg &&
445 "This constraint should be applied only on a pointer type");
446 return ValidArg;
447 }
448 };
449
450 // Represents a buffer argument with an additional size constraint. The
451 // constraint may be a concrete value, or a symbolic value in an argument.
452 // Example 1. Concrete value as the minimum buffer size.
453 // char *asctime_r(const struct tm *restrict tm, char *restrict buf);
454 // // `buf` size must be at least 26 bytes according the POSIX standard.
455 // Example 2. Argument as a buffer size.
456 // ctime_s(char *buffer, rsize_t bufsz, const time_t *time);
457 // Example 3. The size is computed as a multiplication of other args.
458 // size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
459 // // Here, ptr is the buffer, and its minimum size is `size * nmemb`.
460 class BufferSizeConstraint : public ValueConstraint {
461 // The concrete value which is the minimum size for the buffer.
462 std::optional<llvm::APSInt> ConcreteSize;
463 // The argument which holds the size of the buffer.
464 std::optional<ArgNo> SizeArgN;
465 // The argument which is a multiplier to size. This is set in case of
466 // `fread` like functions where the size is computed as a multiplication of
467 // two arguments.
468 std::optional<ArgNo> SizeMultiplierArgN;
469 // The operator we use in apply. This is negated in negate().
470 BinaryOperator::Opcode Op = BO_LE;
471
472 public:
473 BufferSizeConstraint(ArgNo Buffer, llvm::APSInt BufMinSize)
474 : ValueConstraint(Buffer), ConcreteSize(BufMinSize) {}
475 BufferSizeConstraint(ArgNo Buffer, ArgNo BufSize)
476 : ValueConstraint(Buffer), SizeArgN(BufSize) {}
477 BufferSizeConstraint(ArgNo Buffer, ArgNo BufSize, ArgNo BufSizeMultiplier)
478 : ValueConstraint(Buffer), SizeArgN(BufSize),
479 SizeMultiplierArgN(BufSizeMultiplier) {}
480
481 ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
482 const Summary &Summary,
483 CheckerContext &C) const override;
484
485 void describe(DescriptionKind DK, const CallEvent &Call,
486 ProgramStateRef State, const Summary &Summary,
487 llvm::raw_ostream &Out) const override;
488
489 bool describeArgumentValue(const CallEvent &Call, ProgramStateRef State,
490 const Summary &Summary,
491 llvm::raw_ostream &Out) const override;
492
493 std::vector<ArgNo> getArgsToTrack() const override {
494 std::vector<ArgNo> Result{ArgN};
495 if (SizeArgN)
496 Result.push_back(*SizeArgN);
497 if (SizeMultiplierArgN)
498 Result.push_back(*SizeMultiplierArgN);
499 return Result;
500 }
501
502 ValueConstraintPtr negate() const override {
503 BufferSizeConstraint Tmp(*this);
505 return std::make_shared<BufferSizeConstraint>(Tmp);
506 }
507
508 protected:
509 bool checkSpecificValidity(const FunctionDecl *FD) const override {
510 const bool ValidArg = getArgType(FD, ArgN)->isPointerType();
511 assert(ValidArg &&
512 "This constraint should be applied only on a pointer type");
513 return ValidArg;
514 }
515 };
516
517 /// The complete list of constraints that defines a single branch.
518 using ConstraintSet = std::vector<ValueConstraintPtr>;
519
520 /// Define how a function affects the system variable 'errno'.
521 /// This works together with the \c ErrnoModeling and \c ErrnoChecker classes.
522 /// Currently 3 use cases exist: success, failure, irrelevant.
523 /// In the future the failure case can be customized to set \c errno to a
524 /// more specific constraint (for example > 0), or new case can be added
525 /// for functions which require check of \c errno in both success and failure
526 /// case.
527 class ErrnoConstraintBase {
528 public:
529 /// Apply specific state changes related to the errno variable.
530 virtual ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
531 const Summary &Summary,
532 CheckerContext &C) const = 0;
533 /// Get a description about what happens with 'errno' here and how it causes
534 /// a later bug report created by ErrnoChecker.
535 /// Empty return value means that 'errno' related bug may not happen from
536 /// the current analyzed function.
537 virtual std::string describe(CheckerContext &C) const { return ""; }
538
539 virtual ~ErrnoConstraintBase() {}
540
541 protected:
542 ErrnoConstraintBase() = default;
543
544 /// This is used for conjure symbol for errno to differentiate from the
545 /// original call expression (same expression is used for the errno symbol).
546 static int Tag;
547 };
548
549 /// Reset errno constraints to irrelevant.
550 /// This is applicable to functions that may change 'errno' and are not
551 /// modeled elsewhere.
552 class ResetErrnoConstraint : public ErrnoConstraintBase {
553 public:
554 ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
555 const Summary &Summary,
556 CheckerContext &C) const override {
558 }
559 };
560
561 /// Do not change errno constraints.
562 /// This is applicable to functions that are modeled in another checker
563 /// and the already set errno constraints should not be changed in the
564 /// post-call event.
565 class NoErrnoConstraint : public ErrnoConstraintBase {
566 public:
567 ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
568 const Summary &Summary,
569 CheckerContext &C) const override {
570 return State;
571 }
572 };
573
574 /// Set errno constraint at failure cases of standard functions.
575 /// Failure case: 'errno' becomes not equal to 0 and may or may not be checked
576 /// by the program. \c ErrnoChecker does not emit a bug report after such a
577 /// function call.
578 class FailureErrnoConstraint : public ErrnoConstraintBase {
579 public:
580 ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
581 const Summary &Summary,
582 CheckerContext &C) const override {
583 SValBuilder &SVB = C.getSValBuilder();
584 NonLoc ErrnoSVal = SVB.conjureSymbolVal(Call, C.getASTContext().IntTy,
585 C.blockCount(), &Tag)
586 .castAs<NonLoc>();
587 return errno_modeling::setErrnoForStdFailure(State, C, ErrnoSVal);
588 }
589 };
590
591 /// Set errno constraint at success cases of standard functions.
592 /// Success case: 'errno' is not allowed to be used because the value is
593 /// undefined after successful call.
594 /// \c ErrnoChecker can emit bug report after such a function call if errno
595 /// is used.
596 class SuccessErrnoConstraint : public ErrnoConstraintBase {
597 public:
598 ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
599 const Summary &Summary,
600 CheckerContext &C) const override {
602 }
603
604 std::string describe(CheckerContext &C) const override {
605 return "'errno' becomes undefined after the call";
606 }
607 };
608
609 /// Set errno constraint at functions that indicate failure only with 'errno'.
610 /// In this case 'errno' is required to be observed.
611 /// \c ErrnoChecker can emit bug report after such a function call if errno
612 /// is overwritten without a read before.
613 class ErrnoMustBeCheckedConstraint : public ErrnoConstraintBase {
614 public:
615 ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
616 const Summary &Summary,
617 CheckerContext &C) const override {
619 Call.getCFGElementRef());
620 }
621
622 std::string describe(CheckerContext &C) const override {
623 return "reading 'errno' is required to find out if the call has failed";
624 }
625 };
626
627 /// A single branch of a function summary.
628 ///
629 /// A branch is defined by a series of constraints - "assumptions" -
630 /// that together form a single possible outcome of invoking the function.
631 /// When static analyzer considers a branch, it tries to introduce
632 /// a child node in the Exploded Graph. The child node has to include
633 /// constraints that define the branch. If the constraints contradict
634 /// existing constraints in the state, the node is not created and the branch
635 /// is dropped; otherwise it's queued for future exploration.
636 /// The branch is accompanied by a note text that may be displayed
637 /// to the user when a bug is found on a path that takes this branch.
638 ///
639 /// For example, consider the branches in `isalpha(x)`:
640 /// Branch 1)
641 /// x is in range ['A', 'Z'] or in ['a', 'z']
642 /// then the return value is not 0. (I.e. out-of-range [0, 0])
643 /// and the note may say "Assuming the character is alphabetical"
644 /// Branch 2)
645 /// x is out-of-range ['A', 'Z'] and out-of-range ['a', 'z']
646 /// then the return value is 0
647 /// and the note may say "Assuming the character is non-alphabetical".
648 class SummaryCase {
649 ConstraintSet Constraints;
650 const ErrnoConstraintBase &ErrnoConstraint;
651 StringRef Note;
652
653 public:
654 SummaryCase(ConstraintSet &&Constraints, const ErrnoConstraintBase &ErrnoC,
655 StringRef Note)
656 : Constraints(std::move(Constraints)), ErrnoConstraint(ErrnoC),
657 Note(Note) {}
658
659 SummaryCase(const ConstraintSet &Constraints,
660 const ErrnoConstraintBase &ErrnoC, StringRef Note)
661 : Constraints(Constraints), ErrnoConstraint(ErrnoC), Note(Note) {}
662
663 const ConstraintSet &getConstraints() const { return Constraints; }
664 const ErrnoConstraintBase &getErrnoConstraint() const {
665 return ErrnoConstraint;
666 }
667 StringRef getNote() const { return Note; }
668 };
669
670 using ArgTypes = ArrayRef<std::optional<QualType>>;
671 using RetType = std::optional<QualType>;
672
673 // A placeholder type, we use it whenever we do not care about the concrete
674 // type in a Signature.
675 const QualType Irrelevant{};
676 bool static isIrrelevant(QualType T) { return T.isNull(); }
677
678 // The signature of a function we want to describe with a summary. This is a
679 // concessive signature, meaning there may be irrelevant types in the
680 // signature which we do not check against a function with concrete types.
681 // All types in the spec need to be canonical.
682 class Signature {
683 using ArgQualTypes = std::vector<QualType>;
684 ArgQualTypes ArgTys;
685 QualType RetTy;
686 // True if any component type is not found by lookup.
687 bool Invalid = false;
688
689 public:
690 // Construct a signature from optional types. If any of the optional types
691 // are not set then the signature will be invalid.
692 Signature(ArgTypes ArgTys, RetType RetTy) {
693 for (std::optional<QualType> Arg : ArgTys) {
694 if (!Arg) {
695 Invalid = true;
696 return;
697 } else {
698 assertArgTypeSuitableForSignature(*Arg);
699 this->ArgTys.push_back(*Arg);
700 }
701 }
702 if (!RetTy) {
703 Invalid = true;
704 return;
705 } else {
706 assertRetTypeSuitableForSignature(*RetTy);
707 this->RetTy = *RetTy;
708 }
709 }
710
711 bool isInvalid() const { return Invalid; }
712 bool matches(const FunctionDecl *FD) const;
713
714 private:
715 static void assertArgTypeSuitableForSignature(QualType T) {
716 assert((T.isNull() || !T->isVoidType()) &&
717 "We should have no void types in the spec");
718 assert((T.isNull() || T.isCanonical()) &&
719 "We should only have canonical types in the spec");
720 }
721 static void assertRetTypeSuitableForSignature(QualType T) {
722 assert((T.isNull() || T.isCanonical()) &&
723 "We should only have canonical types in the spec");
724 }
725 };
726
727 static QualType getArgType(const FunctionDecl *FD, ArgNo ArgN) {
728 assert(FD && "Function must be set");
729 QualType T = (ArgN == Ret)
731 : FD->getParamDecl(ArgN)->getType().getCanonicalType();
732 return T;
733 }
734
735 using SummaryCases = std::vector<SummaryCase>;
736
737 /// A summary includes information about
738 /// * function prototype (signature)
739 /// * approach to invalidation,
740 /// * a list of branches - so, a list of list of ranges,
741 /// * a list of argument constraints, that must be true on every branch.
742 /// If these constraints are not satisfied that means a fatal error
743 /// usually resulting in undefined behaviour.
744 ///
745 /// Application of a summary:
746 /// The signature and argument constraints together contain information
747 /// about which functions are handled by the summary. The signature can use
748 /// "wildcards", i.e. Irrelevant types. Irrelevant type of a parameter in
749 /// a signature means that type is not compared to the type of the parameter
750 /// in the found FunctionDecl. Argument constraints may specify additional
751 /// rules for the given parameter's type, those rules are checked once the
752 /// signature is matched.
753 class Summary {
754 const InvalidationKind InvalidationKd;
755 SummaryCases Cases;
756 ConstraintSet ArgConstraints;
757
758 // The function to which the summary applies. This is set after lookup and
759 // match to the signature.
760 const FunctionDecl *FD = nullptr;
761
762 public:
763 Summary(InvalidationKind InvalidationKd) : InvalidationKd(InvalidationKd) {}
764
765 Summary &Case(ConstraintSet &&CS, const ErrnoConstraintBase &ErrnoC,
766 StringRef Note = "") {
767 Cases.push_back(SummaryCase(std::move(CS), ErrnoC, Note));
768 return *this;
769 }
770 Summary &Case(const ConstraintSet &CS, const ErrnoConstraintBase &ErrnoC,
771 StringRef Note = "") {
772 Cases.push_back(SummaryCase(CS, ErrnoC, Note));
773 return *this;
774 }
775 Summary &ArgConstraint(ValueConstraintPtr VC) {
776 assert(VC->getArgNo() != Ret &&
777 "Arg constraint should not refer to the return value");
778 ArgConstraints.push_back(VC);
779 return *this;
780 }
781
782 InvalidationKind getInvalidationKd() const { return InvalidationKd; }
783 const SummaryCases &getCases() const { return Cases; }
784 const ConstraintSet &getArgConstraints() const { return ArgConstraints; }
785
786 QualType getArgType(ArgNo ArgN) const {
787 return StdLibraryFunctionsChecker::getArgType(FD, ArgN);
788 }
789
790 // Returns true if the summary should be applied to the given function.
791 // And if yes then store the function declaration.
792 bool matchesAndSet(const Signature &Sign, const FunctionDecl *FD) {
793 bool Result = Sign.matches(FD) && validateByConstraints(FD);
794 if (Result) {
795 assert(!this->FD && "FD must not be set more than once");
796 this->FD = FD;
797 }
798 return Result;
799 }
800
801 private:
802 // Once we know the exact type of the function then do validation check on
803 // all the given constraints.
804 bool validateByConstraints(const FunctionDecl *FD) const {
805 for (const SummaryCase &Case : Cases)
806 for (const ValueConstraintPtr &Constraint : Case.getConstraints())
807 if (!Constraint->checkValidity(FD))
808 return false;
809 for (const ValueConstraintPtr &Constraint : ArgConstraints)
810 if (!Constraint->checkValidity(FD))
811 return false;
812 return true;
813 }
814 };
815
816 // The map of all functions supported by the checker. It is initialized
817 // lazily, and it doesn't change after initialization.
818 using FunctionSummaryMapType = llvm::DenseMap<const FunctionDecl *, Summary>;
819 mutable FunctionSummaryMapType FunctionSummaryMap;
820
821 const BugType BT_InvalidArg{this, "Function call with invalid argument"};
822 mutable bool SummariesInitialized = false;
823
824 static SVal getArgSVal(const CallEvent &Call, ArgNo ArgN) {
825 return ArgN == Ret ? Call.getReturnValue() : Call.getArgSVal(ArgN);
826 }
827 static std::string getFunctionName(const CallEvent &Call) {
828 assert(Call.getDecl() &&
829 "Call was found by a summary, should have declaration");
830 return cast<NamedDecl>(Call.getDecl())->getNameAsString();
831 }
832
833public:
834 void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
835 void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
836 bool evalCall(const CallEvent &Call, CheckerContext &C) const;
837
838 CheckerNameRef CheckName;
839 bool AddTestFunctions = false;
840
841 bool DisplayLoadedSummaries = false;
842 bool ModelPOSIX = false;
843 bool ShouldAssumeControlledEnvironment = false;
844
845private:
846 std::optional<Summary> findFunctionSummary(const FunctionDecl *FD,
847 CheckerContext &C) const;
848 std::optional<Summary> findFunctionSummary(const CallEvent &Call,
849 CheckerContext &C) const;
850
851 LLVM_ATTRIBUTE_MINSIZE void initFunctionSummaries(CheckerContext &C) const;
852
853 void reportBug(const CallEvent &Call, ExplodedNode *N,
854 const ValueConstraint *VC, const ValueConstraint *NegatedVC,
855 const Summary &Summary, CheckerContext &C) const {
856 assert(Call.getDecl() &&
857 "Function found in summary must have a declaration available");
858 SmallString<256> Msg;
859 llvm::raw_svector_ostream MsgOs(Msg);
860
861 MsgOs << "The ";
862 printArgDesc(VC->getArgNo(), MsgOs);
863 MsgOs << " to '" << getFunctionName(Call) << "' ";
864 bool ValuesPrinted =
865 NegatedVC->describeArgumentValue(Call, N->getState(), Summary, MsgOs);
866 if (ValuesPrinted)
867 MsgOs << " but ";
868 else
869 MsgOs << "is out of the accepted range; It ";
870 VC->describe(ValueConstraint::Violation, Call, C.getState(), Summary,
871 MsgOs);
872 Msg[0] = toupper(Msg[0]);
873 auto R = std::make_unique<PathSensitiveBugReport>(BT_InvalidArg, Msg, N);
874
875 for (ArgNo ArgN : VC->getArgsToTrack()) {
876 bugreporter::trackExpressionValue(N, Call.getArgExpr(ArgN), *R);
877 R->markInteresting(Call.getArgSVal(ArgN));
878 // All tracked arguments are important, highlight them.
879 R->addRange(Call.getArgSourceRange(ArgN));
880 }
881
882 C.emitReport(std::move(R));
883 }
884
885 /// These are the errno constraints that can be passed to summary cases.
886 /// One of these should fit for a single summary case.
887 /// Usually if a failure return value exists for function, that function
888 /// needs different cases for success and failure with different errno
889 /// constraints (and different return value constraints).
890 const NoErrnoConstraint ErrnoUnchanged{};
891 const ResetErrnoConstraint ErrnoIrrelevant{};
892 const ErrnoMustBeCheckedConstraint ErrnoMustBeChecked{};
893 const SuccessErrnoConstraint ErrnoMustNotBeChecked{};
894 const FailureErrnoConstraint ErrnoNEZeroIrrelevant{};
895};
896
897int StdLibraryFunctionsChecker::ErrnoConstraintBase::Tag = 0;
898
899const StdLibraryFunctionsChecker::ArgNo StdLibraryFunctionsChecker::Ret =
900 std::numeric_limits<ArgNo>::max();
901
902static BasicValueFactory &getBVF(ProgramStateRef State) {
903 ProgramStateManager &Mgr = State->getStateManager();
904 SValBuilder &SVB = Mgr.getSValBuilder();
905 return SVB.getBasicValueFactory();
906}
907
908} // end of anonymous namespace
909
910void StdLibraryFunctionsChecker::printArgDesc(
911 StdLibraryFunctionsChecker::ArgNo ArgN, llvm::raw_ostream &Out) {
912 Out << std::to_string(ArgN + 1);
913 Out << llvm::getOrdinalSuffix(ArgN + 1);
914 Out << " argument";
915}
916
917void StdLibraryFunctionsChecker::printArgValueInfo(ArgNo ArgN,
918 ProgramStateRef State,
919 const CallEvent &Call,
920 llvm::raw_ostream &Out) {
921 if (const llvm::APSInt *Val =
922 State->getStateManager().getSValBuilder().getKnownValue(
923 State, getArgSVal(Call, ArgN)))
924 Out << " (which is " << *Val << ")";
925}
926
927void StdLibraryFunctionsChecker::appendInsideRangeDesc(llvm::APSInt RMin,
928 llvm::APSInt RMax,
929 QualType ArgT,
930 BasicValueFactory &BVF,
931 llvm::raw_ostream &Out) {
932 if (RMin.isZero() && RMax.isZero())
933 Out << "zero";
934 else if (RMin == RMax)
935 Out << RMin;
936 else if (RMin == BVF.getMinValue(ArgT)) {
937 if (RMax == -1)
938 Out << "< 0";
939 else
940 Out << "<= " << RMax;
941 } else if (RMax == BVF.getMaxValue(ArgT)) {
942 if (RMin.isOne())
943 Out << "> 0";
944 else
945 Out << ">= " << RMin;
946 } else if (RMin.isNegative() == RMax.isNegative() &&
947 RMin.getLimitedValue() == RMax.getLimitedValue() - 1) {
948 Out << RMin << " or " << RMax;
949 } else {
950 Out << "between " << RMin << " and " << RMax;
951 }
952}
953
954void StdLibraryFunctionsChecker::appendOutOfRangeDesc(llvm::APSInt RMin,
955 llvm::APSInt RMax,
956 QualType ArgT,
957 BasicValueFactory &BVF,
958 llvm::raw_ostream &Out) {
959 if (RMin.isZero() && RMax.isZero())
960 Out << "nonzero";
961 else if (RMin == RMax) {
962 Out << "not equal to " << RMin;
963 } else if (RMin == BVF.getMinValue(ArgT)) {
964 if (RMax == -1)
965 Out << ">= 0";
966 else
967 Out << "> " << RMax;
968 } else if (RMax == BVF.getMaxValue(ArgT)) {
969 if (RMin.isOne())
970 Out << "<= 0";
971 else
972 Out << "< " << RMin;
973 } else if (RMin.isNegative() == RMax.isNegative() &&
974 RMin.getLimitedValue() == RMax.getLimitedValue() - 1) {
975 Out << "not " << RMin << " and not " << RMax;
976 } else {
977 Out << "not between " << RMin << " and " << RMax;
978 }
979}
980
981void StdLibraryFunctionsChecker::RangeConstraint::applyOnWithinRange(
982 BasicValueFactory &BVF, QualType ArgT, const RangeApplyFunction &F) const {
983 if (Ranges.empty())
984 return;
985
986 for (auto [Start, End] : getRanges()) {
987 const llvm::APSInt &Min = BVF.getValue(Start, ArgT);
988 const llvm::APSInt &Max = BVF.getValue(End, ArgT);
989 assert(Min <= Max);
990 if (!F(Min, Max))
991 return;
992 }
993}
994
995void StdLibraryFunctionsChecker::RangeConstraint::applyOnOutOfRange(
996 BasicValueFactory &BVF, QualType ArgT, const RangeApplyFunction &F) const {
997 if (Ranges.empty())
998 return;
999
1000 const IntRangeVector &R = getRanges();
1001 size_t E = R.size();
1002
1003 const llvm::APSInt &MinusInf = BVF.getMinValue(ArgT);
1004 const llvm::APSInt &PlusInf = BVF.getMaxValue(ArgT);
1005
1006 const llvm::APSInt &RangeLeft = BVF.getValue(R[0].first - 1ULL, ArgT);
1007 const llvm::APSInt &RangeRight = BVF.getValue(R[E - 1].second + 1ULL, ArgT);
1008
1009 // Iterate over the "holes" between intervals.
1010 for (size_t I = 1; I != E; ++I) {
1011 const llvm::APSInt &Min = BVF.getValue(R[I - 1].second + 1ULL, ArgT);
1012 const llvm::APSInt &Max = BVF.getValue(R[I].first - 1ULL, ArgT);
1013 if (Min <= Max) {
1014 if (!F(Min, Max))
1015 return;
1016 }
1017 }
1018 // Check the interval [T_MIN, min(R) - 1].
1019 if (RangeLeft != PlusInf) {
1020 assert(MinusInf <= RangeLeft);
1021 if (!F(MinusInf, RangeLeft))
1022 return;
1023 }
1024 // Check the interval [max(R) + 1, T_MAX],
1025 if (RangeRight != MinusInf) {
1026 assert(RangeRight <= PlusInf);
1027 if (!F(RangeRight, PlusInf))
1028 return;
1029 }
1030}
1031
1032ProgramStateRef StdLibraryFunctionsChecker::RangeConstraint::apply(
1033 ProgramStateRef State, const CallEvent &Call, const Summary &Summary,
1034 CheckerContext &C) const {
1035 ConstraintManager &CM = C.getConstraintManager();
1036 SVal V = getArgSVal(Call, getArgNo());
1037 QualType T = Summary.getArgType(getArgNo());
1038
1039 if (auto N = V.getAs<NonLoc>()) {
1040 auto ExcludeRangeFromArg = [&](const llvm::APSInt &Min,
1041 const llvm::APSInt &Max) {
1042 State = CM.assumeInclusiveRange(State, *N, Min, Max, false);
1043 return static_cast<bool>(State);
1044 };
1045 // "OutOfRange R" is handled by excluding all ranges in R.
1046 // "WithinRange R" is treated as "OutOfRange [T_MIN, T_MAX] \ R".
1047 applyOnRange(negateKind(Kind), C.getSValBuilder().getBasicValueFactory(), T,
1048 ExcludeRangeFromArg);
1049 }
1050
1051 return State;
1052}
1053
1054void StdLibraryFunctionsChecker::RangeConstraint::describe(
1055 DescriptionKind DK, const CallEvent &Call, ProgramStateRef State,
1056 const Summary &Summary, llvm::raw_ostream &Out) const {
1057
1058 BasicValueFactory &BVF = getBVF(State);
1059 QualType T = Summary.getArgType(getArgNo());
1060
1061 Out << ((DK == Violation) ? "should be " : "is ");
1062 if (!Description.empty()) {
1063 Out << Description;
1064 } else {
1065 unsigned I = Ranges.size();
1066 if (Kind == WithinRange) {
1067 for (const std::pair<RangeInt, RangeInt> &R : Ranges) {
1068 appendInsideRangeDesc(BVF.getValue(R.first, T),
1069 BVF.getValue(R.second, T), T, BVF, Out);
1070 if (--I > 0)
1071 Out << " or ";
1072 }
1073 } else {
1074 for (const std::pair<RangeInt, RangeInt> &R : Ranges) {
1075 appendOutOfRangeDesc(BVF.getValue(R.first, T),
1076 BVF.getValue(R.second, T), T, BVF, Out);
1077 if (--I > 0)
1078 Out << " and ";
1079 }
1080 }
1081 }
1082}
1083
1084bool StdLibraryFunctionsChecker::RangeConstraint::describeArgumentValue(
1085 const CallEvent &Call, ProgramStateRef State, const Summary &Summary,
1086 llvm::raw_ostream &Out) const {
1087 unsigned int NRanges = 0;
1088 bool HaveAllRanges = true;
1089
1090 ProgramStateManager &Mgr = State->getStateManager();
1091 BasicValueFactory &BVF = Mgr.getSValBuilder().getBasicValueFactory();
1092 ConstraintManager &CM = Mgr.getConstraintManager();
1093 SVal V = getArgSVal(Call, getArgNo());
1094
1095 if (auto N = V.getAs<NonLoc>()) {
1096 if (const llvm::APSInt *Int = N->getAsInteger()) {
1097 Out << "is ";
1098 Out << *Int;
1099 return true;
1100 }
1101 QualType T = Summary.getArgType(getArgNo());
1102 SmallString<128> MoreInfo;
1103 llvm::raw_svector_ostream MoreInfoOs(MoreInfo);
1104 auto ApplyF = [&](const llvm::APSInt &Min, const llvm::APSInt &Max) {
1105 if (CM.assumeInclusiveRange(State, *N, Min, Max, true)) {
1106 if (NRanges > 0)
1107 MoreInfoOs << " or ";
1108 appendInsideRangeDesc(Min, Max, T, BVF, MoreInfoOs);
1109 ++NRanges;
1110 } else {
1111 HaveAllRanges = false;
1112 }
1113 return true;
1114 };
1115
1116 applyOnRange(Kind, BVF, T, ApplyF);
1117 assert(NRanges > 0);
1118 if (!HaveAllRanges || NRanges == 1) {
1119 Out << "is ";
1120 Out << MoreInfo;
1121 return true;
1122 }
1123 }
1124 return false;
1125}
1126
1127ProgramStateRef StdLibraryFunctionsChecker::ComparisonConstraint::apply(
1128 ProgramStateRef State, const CallEvent &Call, const Summary &Summary,
1129 CheckerContext &C) const {
1130
1131 ProgramStateManager &Mgr = State->getStateManager();
1132 SValBuilder &SVB = Mgr.getSValBuilder();
1133 QualType CondT = SVB.getConditionType();
1134 QualType T = Summary.getArgType(getArgNo());
1135 SVal V = getArgSVal(Call, getArgNo());
1136
1137 BinaryOperator::Opcode Op = getOpcode();
1138 ArgNo OtherArg = getOtherArgNo();
1139 SVal OtherV = getArgSVal(Call, OtherArg);
1140 QualType OtherT = Summary.getArgType(OtherArg);
1141 // Note: we avoid integral promotion for comparison.
1142 OtherV = SVB.evalCast(OtherV, T, OtherT);
1143 if (auto CompV = SVB.evalBinOp(State, Op, V, OtherV, CondT)
1144 .getAs<DefinedOrUnknownSVal>())
1145 State = State->assume(*CompV, true);
1146 return State;
1147}
1148
1149ProgramStateRef StdLibraryFunctionsChecker::NullnessConstraint::apply(
1150 ProgramStateRef State, const CallEvent &Call, const Summary &Summary,
1151 CheckerContext &C) const {
1152 SVal V = getArgSVal(Call, getArgNo());
1153 if (V.isUndef())
1154 return State;
1155
1156 DefinedOrUnknownSVal L = V.castAs<DefinedOrUnknownSVal>();
1157 if (!isa<Loc>(L))
1158 return State;
1159
1160 return State->assume(L, CannotBeNull);
1161}
1162
1163void StdLibraryFunctionsChecker::NullnessConstraint::describe(
1164 DescriptionKind DK, const CallEvent &Call, ProgramStateRef State,
1165 const Summary &Summary, llvm::raw_ostream &Out) const {
1166 assert(CannotBeNull &&
1167 "'describe' is not implemented when the value must be NULL");
1168 if (DK == Violation)
1169 Out << "should not be NULL";
1170 else
1171 Out << "is not NULL";
1172}
1173
1174bool StdLibraryFunctionsChecker::NullnessConstraint::describeArgumentValue(
1175 const CallEvent &Call, ProgramStateRef State, const Summary &Summary,
1176 llvm::raw_ostream &Out) const {
1177 assert(!CannotBeNull && "'describeArgumentValue' is not implemented when the "
1178 "value must be non-NULL");
1179 Out << "is NULL";
1180 return true;
1181}
1182
1183ProgramStateRef StdLibraryFunctionsChecker::BufferNullnessConstraint::apply(
1184 ProgramStateRef State, const CallEvent &Call, const Summary &Summary,
1185 CheckerContext &C) const {
1186 SVal V = getArgSVal(Call, getArgNo());
1187 if (V.isUndef())
1188 return State;
1189 DefinedOrUnknownSVal L = V.castAs<DefinedOrUnknownSVal>();
1190 if (!isa<Loc>(L))
1191 return State;
1192
1193 std::optional<DefinedOrUnknownSVal> SizeArg1 =
1194 getArgSVal(Call, SizeArg1N).getAs<DefinedOrUnknownSVal>();
1195 std::optional<DefinedOrUnknownSVal> SizeArg2;
1196 if (SizeArg2N)
1197 SizeArg2 = getArgSVal(Call, *SizeArg2N).getAs<DefinedOrUnknownSVal>();
1198
1199 auto IsArgZero = [State](std::optional<DefinedOrUnknownSVal> Val) {
1200 if (!Val)
1201 return false;
1202 auto [IsNonNull, IsNull] = State->assume(*Val);
1203 return IsNull && !IsNonNull;
1204 };
1205
1206 if (IsArgZero(SizeArg1) || IsArgZero(SizeArg2))
1207 return State;
1208
1209 return State->assume(L, CannotBeNull);
1210}
1211
1212void StdLibraryFunctionsChecker::BufferNullnessConstraint::describe(
1213 DescriptionKind DK, const CallEvent &Call, ProgramStateRef State,
1214 const Summary &Summary, llvm::raw_ostream &Out) const {
1215 assert(CannotBeNull &&
1216 "'describe' is not implemented when the buffer must be NULL");
1217 if (DK == Violation)
1218 Out << "should not be NULL";
1219 else
1220 Out << "is not NULL";
1221}
1222
1223bool StdLibraryFunctionsChecker::BufferNullnessConstraint::
1224 describeArgumentValue(const CallEvent &Call, ProgramStateRef State,
1225 const Summary &Summary,
1226 llvm::raw_ostream &Out) const {
1227 assert(!CannotBeNull && "'describeArgumentValue' is not implemented when the "
1228 "buffer must be non-NULL");
1229 Out << "is NULL";
1230 return true;
1231}
1232
1233ProgramStateRef StdLibraryFunctionsChecker::BufferSizeConstraint::apply(
1234 ProgramStateRef State, const CallEvent &Call, const Summary &Summary,
1235 CheckerContext &C) const {
1236 SValBuilder &SvalBuilder = C.getSValBuilder();
1237 // The buffer argument.
1238 SVal BufV = getArgSVal(Call, getArgNo());
1239
1240 // Get the size constraint.
1241 const SVal SizeV = [this, &State, &Call, &Summary, &SvalBuilder]() {
1242 if (ConcreteSize) {
1243 return SVal(SvalBuilder.makeIntVal(*ConcreteSize));
1244 }
1245 assert(SizeArgN && "The constraint must be either a concrete value or "
1246 "encoded in an argument.");
1247 // The size argument.
1248 SVal SizeV = getArgSVal(Call, *SizeArgN);
1249 // Multiply with another argument if given.
1250 if (SizeMultiplierArgN) {
1251 SVal SizeMulV = getArgSVal(Call, *SizeMultiplierArgN);
1252 SizeV = SvalBuilder.evalBinOp(State, BO_Mul, SizeV, SizeMulV,
1253 Summary.getArgType(*SizeArgN));
1254 }
1255 return SizeV;
1256 }();
1257
1258 // The dynamic size of the buffer argument, got from the analyzer engine.
1259 SVal BufDynSize = getDynamicExtentWithOffset(State, BufV);
1260
1261 SVal Feasible = SvalBuilder.evalBinOp(State, Op, SizeV, BufDynSize,
1262 SvalBuilder.getContext().BoolTy);
1263 if (auto F = Feasible.getAs<DefinedOrUnknownSVal>())
1264 return State->assume(*F, true);
1265
1266 // We can get here only if the size argument or the dynamic size is
1267 // undefined. But the dynamic size should never be undefined, only
1268 // unknown. So, here, the size of the argument is undefined, i.e. we
1269 // cannot apply the constraint. Actually, other checkers like
1270 // CallAndMessage should catch this situation earlier, because we call a
1271 // function with an uninitialized argument.
1272 llvm_unreachable("Size argument or the dynamic size is Undefined");
1273}
1274
1275void StdLibraryFunctionsChecker::BufferSizeConstraint::describe(
1276 DescriptionKind DK, const CallEvent &Call, ProgramStateRef State,
1277 const Summary &Summary, llvm::raw_ostream &Out) const {
1278 Out << ((DK == Violation) ? "should be " : "is ");
1279 Out << "a buffer with size equal to or greater than ";
1280 if (ConcreteSize) {
1281 Out << *ConcreteSize;
1282 } else if (SizeArgN) {
1283 Out << "the value of the ";
1284 printArgDesc(*SizeArgN, Out);
1285 printArgValueInfo(*SizeArgN, State, Call, Out);
1286 if (SizeMultiplierArgN) {
1287 Out << " times the ";
1288 printArgDesc(*SizeMultiplierArgN, Out);
1289 printArgValueInfo(*SizeMultiplierArgN, State, Call, Out);
1290 }
1291 }
1292}
1293
1294bool StdLibraryFunctionsChecker::BufferSizeConstraint::describeArgumentValue(
1295 const CallEvent &Call, ProgramStateRef State, const Summary &Summary,
1296 llvm::raw_ostream &Out) const {
1297 SVal BufV = getArgSVal(Call, getArgNo());
1298 SVal BufDynSize = getDynamicExtentWithOffset(State, BufV);
1299 if (const llvm::APSInt *Val =
1300 State->getStateManager().getSValBuilder().getKnownValue(State,
1301 BufDynSize)) {
1302 Out << "is a buffer with size " << *Val;
1303 return true;
1304 }
1305 return false;
1306}
1307
1308void StdLibraryFunctionsChecker::checkPreCall(const CallEvent &Call,
1309 CheckerContext &C) const {
1310 std::optional<Summary> FoundSummary = findFunctionSummary(Call, C);
1311 if (!FoundSummary)
1312 return;
1313
1314 const Summary &Summary = *FoundSummary;
1315 ProgramStateRef State = C.getState();
1316
1317 ProgramStateRef NewState = State;
1318 ExplodedNode *NewNode = C.getPredecessor();
1319 for (const ValueConstraintPtr &Constraint : Summary.getArgConstraints()) {
1320 ValueConstraintPtr NegatedConstraint = Constraint->negate();
1321 ProgramStateRef SuccessSt = Constraint->apply(NewState, Call, Summary, C);
1322 ProgramStateRef FailureSt =
1323 NegatedConstraint->apply(NewState, Call, Summary, C);
1324 // The argument constraint is not satisfied.
1325 if (FailureSt && !SuccessSt) {
1326 if (ExplodedNode *N = C.generateErrorNode(State, NewNode))
1327 reportBug(Call, N, Constraint.get(), NegatedConstraint.get(), Summary,
1328 C);
1329 break;
1330 }
1331 // We will apply the constraint even if we cannot reason about the
1332 // argument. This means both SuccessSt and FailureSt can be true. If we
1333 // weren't applying the constraint that would mean that symbolic
1334 // execution continues on a code whose behaviour is undefined.
1335 assert(SuccessSt);
1336 NewState = SuccessSt;
1337 if (NewState != State) {
1338 SmallString<128> Msg;
1339 llvm::raw_svector_ostream Os(Msg);
1340 Os << "Assuming that the ";
1341 printArgDesc(Constraint->getArgNo(), Os);
1342 Os << " to '";
1343 Os << getFunctionName(Call);
1344 Os << "' ";
1345 Constraint->describe(ValueConstraint::Assumption, Call, NewState, Summary,
1346 Os);
1347 const auto ArgSVal = Call.getArgSVal(Constraint->getArgNo());
1348 NewNode = C.addTransition(
1349 NewState, NewNode,
1350 C.getNoteTag([Msg = std::move(Msg), ArgSVal](
1351 PathSensitiveBugReport &BR, llvm::raw_ostream &OS) {
1352 if (BR.isInteresting(ArgSVal))
1353 OS << Msg;
1354 }));
1355 }
1356 }
1357}
1358
1359void StdLibraryFunctionsChecker::checkPostCall(const CallEvent &Call,
1360 CheckerContext &C) const {
1361 std::optional<Summary> FoundSummary = findFunctionSummary(Call, C);
1362 if (!FoundSummary)
1363 return;
1364
1365 // Now apply the constraints.
1366 const Summary &Summary = *FoundSummary;
1367 ProgramStateRef State = C.getState();
1368 ExplodedNode *Node = C.getPredecessor();
1369
1370 // Apply case/branch specifications.
1371 for (const SummaryCase &Case : Summary.getCases()) {
1372 ProgramStateRef NewState = State;
1373 for (const ValueConstraintPtr &Constraint : Case.getConstraints()) {
1374 NewState = Constraint->apply(NewState, Call, Summary, C);
1375 if (!NewState)
1376 break;
1377 }
1378
1379 if (NewState)
1380 NewState = Case.getErrnoConstraint().apply(NewState, Call, Summary, C);
1381
1382 if (!NewState)
1383 continue;
1384
1385 // Here it's possible that NewState == State, e.g. when other checkers
1386 // already applied the same constraints (or stricter ones).
1387 // Still add these note tags, the other checker should add only its
1388 // specialized note tags. These general note tags are handled always by
1389 // StdLibraryFunctionsChecker.
1390
1391 ExplodedNode *Pred = Node;
1392 DeclarationName FunctionName =
1393 cast<NamedDecl>(Call.getDecl())->getDeclName();
1394
1395 std::string ErrnoNote = Case.getErrnoConstraint().describe(C);
1396 std::string CaseNote;
1397 if (Case.getNote().empty()) {
1398 if (!ErrnoNote.empty())
1399 ErrnoNote =
1400 llvm::formatv("After calling '{0}' {1}", FunctionName, ErrnoNote);
1401 } else {
1402 // Disable formatv() validation as the case note may not always have the
1403 // {0} placeholder for function name.
1404 CaseNote =
1405 llvm::formatv(false, Case.getNote().str().c_str(), FunctionName);
1406 }
1407 const SVal RV = Call.getReturnValue();
1408
1409 if (Summary.getInvalidationKd() == EvalCallAsPure) {
1410 // Do not expect that errno is interesting (the "pure" functions do not
1411 // affect it).
1412 if (!CaseNote.empty()) {
1413 const NoteTag *Tag = C.getNoteTag(
1414 [Node, CaseNote, RV](PathSensitiveBugReport &BR) -> std::string {
1415 // Try to omit the note if we know in advance which branch is
1416 // taken (this means, only one branch exists).
1417 // This check is performed inside the lambda, after other
1418 // (or this) checkers had a chance to add other successors.
1419 // Dereferencing the saved node object is valid because it's part
1420 // of a bug report call sequence.
1421 // FIXME: This check is not exact. We may be here after a state
1422 // split that was performed by another checker (and can not find
1423 // the successors). This is why this check is only used in the
1424 // EvalCallAsPure case.
1425 if (BR.isInteresting(RV) && Node->succ_size() > 1)
1426 return CaseNote;
1427 return "";
1428 });
1429 Pred = C.addTransition(NewState, Pred, Tag);
1430 }
1431 } else {
1432 if (!CaseNote.empty() || !ErrnoNote.empty()) {
1433 const NoteTag *Tag =
1434 C.getNoteTag([CaseNote, ErrnoNote,
1435 RV](PathSensitiveBugReport &BR) -> std::string {
1436 // If 'errno' is interesting, show the user a note about the case
1437 // (what happened at the function call) and about how 'errno'
1438 // causes the problem. ErrnoChecker sets the errno (but not RV) to
1439 // interesting.
1440 // If only the return value is interesting, show only the case
1441 // note.
1442 std::optional<Loc> ErrnoLoc =
1444 bool ErrnoImportant = !ErrnoNote.empty() && ErrnoLoc &&
1445 BR.isInteresting(ErrnoLoc->getAsRegion());
1446 if (ErrnoImportant) {
1447 BR.markNotInteresting(ErrnoLoc->getAsRegion());
1448 if (CaseNote.empty())
1449 return ErrnoNote;
1450 return llvm::formatv("{0}; {1}", CaseNote, ErrnoNote);
1451 } else {
1452 if (BR.isInteresting(RV))
1453 return CaseNote;
1454 }
1455 return "";
1456 });
1457 Pred = C.addTransition(NewState, Pred, Tag);
1458 }
1459 }
1460
1461 // Add the transition if no note tag was added.
1462 if (Pred == Node && NewState != State)
1463 C.addTransition(NewState);
1464 }
1465}
1466
1467bool StdLibraryFunctionsChecker::evalCall(const CallEvent &Call,
1468 CheckerContext &C) const {
1469 std::optional<Summary> FoundSummary = findFunctionSummary(Call, C);
1470 if (!FoundSummary)
1471 return false;
1472
1473 const Summary &Summary = *FoundSummary;
1474 switch (Summary.getInvalidationKd()) {
1475 case EvalCallAsPure: {
1476 ProgramStateRef State = C.getState();
1477 const auto *CE = cast<CallExpr>(Call.getOriginExpr());
1478 SVal V = C.getSValBuilder().conjureSymbolVal(Call, C.blockCount());
1479 State = State->BindExpr(CE, C.getStackFrame(), V);
1480
1481 C.addTransition(State);
1482
1483 return true;
1484 }
1485 case NoEvalCall:
1486 // Summary tells us to avoid performing eval::Call. The function is possibly
1487 // evaluated by another checker, or evaluated conservatively.
1488 return false;
1489 }
1490 llvm_unreachable("Unknown invalidation kind!");
1491}
1492
1493bool StdLibraryFunctionsChecker::Signature::matches(
1494 const FunctionDecl *FD) const {
1495 assert(!isInvalid());
1496 // Check the number of arguments.
1497 if (FD->param_size() != ArgTys.size())
1498 return false;
1499
1500 // The "restrict" keyword is illegal in C++, however, many libc
1501 // implementations use the "__restrict" compiler intrinsic in functions
1502 // prototypes. The "__restrict" keyword qualifies a type as a restricted type
1503 // even in C++.
1504 // In case of any non-C99 languages, we don't want to match based on the
1505 // restrict qualifier because we cannot know if the given libc implementation
1506 // qualifies the paramter type or not.
1507 auto RemoveRestrict = [&FD](QualType T) {
1508 if (!FD->getASTContext().getLangOpts().C99)
1509 T.removeLocalRestrict();
1510 return T;
1511 };
1512
1513 // Check the return type.
1514 if (!isIrrelevant(RetTy)) {
1515 QualType FDRetTy = RemoveRestrict(FD->getReturnType().getCanonicalType());
1516 if (RetTy != FDRetTy)
1517 return false;
1518 }
1519
1520 // Check the argument types.
1521 for (auto [Idx, ArgTy] : llvm::enumerate(ArgTys)) {
1522 if (isIrrelevant(ArgTy))
1523 continue;
1524 QualType FDArgTy =
1525 RemoveRestrict(FD->getParamDecl(Idx)->getType().getCanonicalType());
1526 if (ArgTy != FDArgTy)
1527 return false;
1528 }
1529
1530 return true;
1531}
1532
1533std::optional<StdLibraryFunctionsChecker::Summary>
1534StdLibraryFunctionsChecker::findFunctionSummary(const FunctionDecl *FD,
1535 CheckerContext &C) const {
1536 if (!FD)
1537 return std::nullopt;
1538
1539 initFunctionSummaries(C);
1540
1541 auto FSMI = FunctionSummaryMap.find(FD->getCanonicalDecl());
1542 if (FSMI == FunctionSummaryMap.end())
1543 return std::nullopt;
1544 return FSMI->second;
1545}
1546
1547std::optional<StdLibraryFunctionsChecker::Summary>
1548StdLibraryFunctionsChecker::findFunctionSummary(const CallEvent &Call,
1549 CheckerContext &C) const {
1550 const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
1551 if (!FD)
1552 return std::nullopt;
1553 return findFunctionSummary(FD, C);
1554}
1555
1556void StdLibraryFunctionsChecker::initFunctionSummaries(
1557 CheckerContext &C) const {
1558 if (SummariesInitialized)
1559 return;
1560 SummariesInitialized = true;
1561
1562 SValBuilder &SVB = C.getSValBuilder();
1563 BasicValueFactory &BVF = SVB.getBasicValueFactory();
1564 const ASTContext &ACtx = BVF.getContext();
1565 Preprocessor &PP = C.getPreprocessor();
1566
1567 // Helper class to lookup a type by its name.
1568 class LookupType {
1569 const ASTContext &ACtx;
1570
1571 public:
1572 LookupType(const ASTContext &ACtx) : ACtx(ACtx) {}
1573
1574 // Find the type. If not found then the optional is not set.
1575 std::optional<QualType> operator()(StringRef Name) {
1576 IdentifierInfo &II = ACtx.Idents.get(Name);
1577 auto LookupRes = ACtx.getTranslationUnitDecl()->lookup(&II);
1578 if (LookupRes.empty())
1579 return std::nullopt;
1580
1581 // Prioritize typedef declarations.
1582 // This is needed in case of C struct typedefs. E.g.:
1583 // typedef struct FILE FILE;
1584 // In this case, we have a RecordDecl 'struct FILE' with the name 'FILE'
1585 // and we have a TypedefDecl with the name 'FILE'.
1586 for (Decl *D : LookupRes)
1587 if (auto *TD = dyn_cast<TypedefNameDecl>(D))
1588 return ACtx.getCanonicalTypeDeclType(TD);
1589
1590 // Find the first TypeDecl.
1591 // There maybe cases when a function has the same name as a struct.
1592 // E.g. in POSIX: `struct stat` and the function `stat()`:
1593 // int stat(const char *restrict path, struct stat *restrict buf);
1594 for (Decl *D : LookupRes)
1595 if (auto *TD = dyn_cast<TypeDecl>(D))
1596 return ACtx.getCanonicalTypeDeclType(TD);
1597 return std::nullopt;
1598 }
1599 } lookupTy(ACtx);
1600
1601 // Below are auxiliary classes to handle optional types that we get as a
1602 // result of the lookup.
1603 class GetRestrictTy {
1604 const ASTContext &ACtx;
1605
1606 public:
1607 GetRestrictTy(const ASTContext &ACtx) : ACtx(ACtx) {}
1608 QualType operator()(QualType Ty) {
1609 return ACtx.getLangOpts().C99 ? ACtx.getRestrictType(Ty) : Ty;
1610 }
1611 std::optional<QualType> operator()(std::optional<QualType> Ty) {
1612 if (Ty)
1613 return operator()(*Ty);
1614 return std::nullopt;
1615 }
1616 } getRestrictTy(ACtx);
1617 class GetPointerTy {
1618 const ASTContext &ACtx;
1619
1620 public:
1621 GetPointerTy(const ASTContext &ACtx) : ACtx(ACtx) {}
1622 QualType operator()(QualType Ty) { return ACtx.getPointerType(Ty); }
1623 std::optional<QualType> operator()(std::optional<QualType> Ty) {
1624 if (Ty)
1625 return operator()(*Ty);
1626 return std::nullopt;
1627 }
1628 } getPointerTy(ACtx);
1629 class {
1630 public:
1631 std::optional<QualType> operator()(std::optional<QualType> Ty) {
1632 return Ty ? std::optional<QualType>(Ty->withConst()) : std::nullopt;
1633 }
1634 QualType operator()(QualType Ty) { return Ty.withConst(); }
1635 } getConstTy;
1636 class GetMaxValue {
1637 BasicValueFactory &BVF;
1638
1639 public:
1640 GetMaxValue(BasicValueFactory &BVF) : BVF(BVF) {}
1641 std::optional<RangeInt> operator()(QualType Ty) {
1642 return BVF.getMaxValue(Ty)->getLimitedValue();
1643 }
1644 std::optional<RangeInt> operator()(std::optional<QualType> Ty) {
1645 if (Ty) {
1646 return operator()(*Ty);
1647 }
1648 return std::nullopt;
1649 }
1650 } getMaxValue(BVF);
1651
1652 // These types are useful for writing specifications quickly,
1653 // New specifications should probably introduce more types.
1654 // Some types are hard to obtain from the AST, eg. "ssize_t".
1655 // In such cases it should be possible to provide multiple variants
1656 // of function summary for common cases (eg. ssize_t could be int or long
1657 // or long long, so three summary variants would be enough).
1658 // Of course, function variants are also useful for C++ overloads.
1659 const QualType VoidTy = ACtx.VoidTy;
1660 const QualType CharTy = ACtx.CharTy;
1661 const QualType WCharTy = ACtx.WCharTy;
1662 const QualType IntTy = ACtx.IntTy;
1663 const QualType UnsignedIntTy = ACtx.UnsignedIntTy;
1664 const QualType LongTy = ACtx.LongTy;
1665 const QualType SizeTyCanonTy = ACtx.getCanonicalSizeType();
1666
1667 const QualType VoidPtrTy = getPointerTy(VoidTy); // void *
1668 const QualType IntPtrTy = getPointerTy(IntTy); // int *
1669 const QualType UnsignedIntPtrTy =
1670 getPointerTy(UnsignedIntTy); // unsigned int *
1671 const QualType VoidPtrRestrictTy = getRestrictTy(VoidPtrTy);
1672 const QualType ConstVoidPtrTy =
1673 getPointerTy(getConstTy(VoidTy)); // const void *
1674 const QualType CharPtrTy = getPointerTy(CharTy); // char *
1675 const QualType CharPtrRestrictTy = getRestrictTy(CharPtrTy);
1676 const QualType ConstCharPtrTy =
1677 getPointerTy(getConstTy(CharTy)); // const char *
1678 const QualType ConstCharPtrRestrictTy = getRestrictTy(ConstCharPtrTy);
1679 const QualType Wchar_tPtrTy = getPointerTy(WCharTy); // wchar_t *
1680 const QualType ConstWchar_tPtrTy =
1681 getPointerTy(getConstTy(WCharTy)); // const wchar_t *
1682 const QualType ConstVoidPtrRestrictTy = getRestrictTy(ConstVoidPtrTy);
1683 const QualType SizePtrTy = getPointerTy(SizeTyCanonTy);
1684 const QualType SizePtrRestrictTy = getRestrictTy(SizePtrTy);
1685
1686 const RangeInt IntMax = BVF.getMaxValue(IntTy)->getLimitedValue();
1687 const RangeInt UnsignedIntMax =
1688 BVF.getMaxValue(UnsignedIntTy)->getLimitedValue();
1689 const RangeInt LongMax = BVF.getMaxValue(LongTy)->getLimitedValue();
1690 const RangeInt SizeMax = BVF.getMaxValue(SizeTyCanonTy)->getLimitedValue();
1691
1692 // Set UCharRangeMax to min of int or uchar maximum value.
1693 // The C standard states that the arguments of functions like isalpha must
1694 // be representable as an unsigned char. Their type is 'int', so the max
1695 // value of the argument should be min(UCharMax, IntMax). This just happen
1696 // to be true for commonly used and well tested instruction set
1697 // architectures, but not for others.
1698 const RangeInt UCharRangeMax =
1699 std::min(BVF.getMaxValue(ACtx.UnsignedCharTy)->getLimitedValue(), IntMax);
1700
1701 // Get platform dependent values of some macros.
1702 // Try our best to parse this from the Preprocessor, otherwise fallback to a
1703 // default value (what is found in a library header).
1704 const auto EOFv = tryExpandAsInteger("EOF", PP).value_or(-1);
1705 const auto AT_FDCWDv = tryExpandAsInteger("AT_FDCWD", PP).value_or(-100);
1706
1707 // Auxiliary class to aid adding summaries to the summary map.
1708 struct AddToFunctionSummaryMap {
1709 const ASTContext &ACtx;
1710 FunctionSummaryMapType &Map;
1711 bool DisplayLoadedSummaries;
1712 AddToFunctionSummaryMap(const ASTContext &ACtx, FunctionSummaryMapType &FSM,
1713 bool DisplayLoadedSummaries)
1714 : ACtx(ACtx), Map(FSM), DisplayLoadedSummaries(DisplayLoadedSummaries) {
1715 }
1716
1717 // Add a summary to a FunctionDecl found by lookup. The lookup is performed
1718 // by the given Name, and in the global scope. The summary will be attached
1719 // to the found FunctionDecl only if the signatures match.
1720 //
1721 // Returns true if the summary has been added, false otherwise.
1722 bool operator()(StringRef Name, Signature Sign, Summary Sum) {
1723 if (Sign.isInvalid())
1724 return false;
1725 IdentifierInfo &II = ACtx.Idents.get(Name);
1726 auto LookupRes = ACtx.getTranslationUnitDecl()->lookup(&II);
1727 if (LookupRes.empty())
1728 return false;
1729 for (Decl *D : LookupRes) {
1730 if (auto *FD = dyn_cast<FunctionDecl>(D)) {
1731 if (Sum.matchesAndSet(Sign, FD)) {
1732 auto Res = Map.insert({FD->getCanonicalDecl(), Sum});
1733 assert(Res.second && "Function already has a summary set!");
1734 (void)Res;
1735 if (DisplayLoadedSummaries) {
1736 llvm::errs() << "Loaded summary for: ";
1737 FD->print(llvm::errs());
1738 llvm::errs() << "\n";
1739 }
1740 return true;
1741 }
1742 }
1743 }
1744 return false;
1745 }
1746 // Add the same summary for different names with the Signature explicitly
1747 // given.
1748 void operator()(ArrayRef<StringRef> Names, Signature Sign, Summary Sum) {
1749 for (StringRef Name : Names)
1750 operator()(Name, Sign, Sum);
1751 }
1752 } addToFunctionSummaryMap(ACtx, FunctionSummaryMap, DisplayLoadedSummaries);
1753
1754 // Below are helpers functions to create the summaries.
1755 auto ArgumentCondition = [](ArgNo ArgN, RangeKind Kind, IntRangeVector Ranges,
1756 StringRef Desc = "") {
1757 return std::make_shared<RangeConstraint>(ArgN, Kind, Ranges, Desc);
1758 };
1759 auto BufferSize = [](auto... Args) {
1760 return std::make_shared<BufferSizeConstraint>(Args...);
1761 };
1762 struct {
1763 auto operator()(RangeKind Kind, IntRangeVector Ranges) {
1764 return std::make_shared<RangeConstraint>(Ret, Kind, Ranges);
1765 }
1766 auto operator()(BinaryOperator::Opcode Op, ArgNo OtherArgN) {
1767 return std::make_shared<ComparisonConstraint>(Ret, Op, OtherArgN);
1768 }
1769 } ReturnValueCondition;
1770 struct {
1771 auto operator()(RangeInt b, RangeInt e) {
1772 return IntRangeVector{std::pair<RangeInt, RangeInt>{b, e}};
1773 }
1774 auto operator()(RangeInt b, std::optional<RangeInt> e) {
1775 if (e)
1776 return IntRangeVector{std::pair<RangeInt, RangeInt>{b, *e}};
1777 return IntRangeVector{};
1778 }
1779 auto operator()(std::pair<RangeInt, RangeInt> i0,
1780 std::pair<RangeInt, std::optional<RangeInt>> i1) {
1781 if (i1.second)
1782 return IntRangeVector{i0, {i1.first, *(i1.second)}};
1783 return IntRangeVector{i0};
1784 }
1785 } Range;
1786 auto SingleValue = [](RangeInt v) {
1787 return IntRangeVector{std::pair<RangeInt, RangeInt>{v, v}};
1788 };
1789 auto LessThanOrEq = BO_LE;
1790 auto NotNull = [&](ArgNo ArgN) {
1791 return std::make_shared<NullnessConstraint>(ArgN);
1792 };
1793 auto IsNull = [&](ArgNo ArgN) {
1794 return std::make_shared<NullnessConstraint>(ArgN, false);
1795 };
1796 auto NotNullBuffer = [&](ArgNo ArgN, ArgNo SizeArg1N,
1797 std::optional<ArgNo> SizeArg2N = std::nullopt) {
1798 return std::make_shared<BufferNullnessConstraint>(ArgN, SizeArg1N,
1799 SizeArg2N);
1800 };
1801
1802 std::optional<QualType> FileTy = lookupTy("FILE");
1803 std::optional<QualType> FilePtrTy = getPointerTy(FileTy);
1804 std::optional<QualType> FilePtrRestrictTy = getRestrictTy(FilePtrTy);
1805
1806 std::optional<QualType> FPosTTy = lookupTy("fpos_t");
1807 std::optional<QualType> FPosTPtrTy = getPointerTy(FPosTTy);
1808 std::optional<QualType> ConstFPosTPtrTy = getPointerTy(getConstTy(FPosTTy));
1809 std::optional<QualType> FPosTPtrRestrictTy = getRestrictTy(FPosTPtrTy);
1810
1811 constexpr llvm::StringLiteral GenericSuccessMsg(
1812 "Assuming that '{0}' is successful");
1813 constexpr llvm::StringLiteral GenericFailureMsg("Assuming that '{0}' fails");
1814
1815 // We are finally ready to define specifications for all supported functions.
1816 //
1817 // Argument ranges should always cover all variants. If return value
1818 // is completely unknown, omit it from the respective range set.
1819 //
1820 // Every item in the list of range sets represents a particular
1821 // execution path the analyzer would need to explore once
1822 // the call is modeled - a new program state is constructed
1823 // for every range set, and each range line in the range set
1824 // corresponds to a specific constraint within this state.
1825
1826 // The isascii() family of functions.
1827 // The behavior is undefined if the value of the argument is not
1828 // representable as unsigned char or is not equal to EOF. See e.g. C99
1829 // 7.4.1.2 The isalpha function (p: 181-182).
1830 addToFunctionSummaryMap(
1831 "isalnum", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1832 Summary(EvalCallAsPure)
1833 // Boils down to isupper() or islower() or isdigit().
1834 .Case({ArgumentCondition(0U, WithinRange,
1835 {{'0', '9'}, {'A', 'Z'}, {'a', 'z'}}),
1836 ReturnValueCondition(OutOfRange, SingleValue(0))},
1837 ErrnoIrrelevant, "Assuming the character is alphanumeric")
1838 // The locale-specific range.
1839 // No post-condition. We are completely unaware of
1840 // locale-specific return values.
1841 .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})},
1842 ErrnoIrrelevant)
1843 .Case(
1844 {ArgumentCondition(
1845 0U, OutOfRange,
1846 {{'0', '9'}, {'A', 'Z'}, {'a', 'z'}, {128, UCharRangeMax}}),
1847 ReturnValueCondition(WithinRange, SingleValue(0))},
1848 ErrnoIrrelevant, "Assuming the character is non-alphanumeric")
1849 .ArgConstraint(ArgumentCondition(0U, WithinRange,
1850 {{EOFv, EOFv}, {0, UCharRangeMax}},
1851 "an unsigned char value or EOF")));
1852 addToFunctionSummaryMap(
1853 "isalpha", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1854 Summary(EvalCallAsPure)
1855 .Case({ArgumentCondition(0U, WithinRange, {{'A', 'Z'}, {'a', 'z'}}),
1856 ReturnValueCondition(OutOfRange, SingleValue(0))},
1857 ErrnoIrrelevant, "Assuming the character is alphabetical")
1858 // The locale-specific range.
1859 .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})},
1860 ErrnoIrrelevant)
1861 .Case({ArgumentCondition(
1862 0U, OutOfRange,
1863 {{'A', 'Z'}, {'a', 'z'}, {128, UCharRangeMax}}),
1864 ReturnValueCondition(WithinRange, SingleValue(0))},
1865 ErrnoIrrelevant, "Assuming the character is non-alphabetical"));
1866 addToFunctionSummaryMap(
1867 "isascii", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1868 Summary(EvalCallAsPure)
1869 .Case({ArgumentCondition(0U, WithinRange, Range(0, 127)),
1870 ReturnValueCondition(OutOfRange, SingleValue(0))},
1871 ErrnoIrrelevant, "Assuming the character is an ASCII character")
1872 .Case({ArgumentCondition(0U, OutOfRange, Range(0, 127)),
1873 ReturnValueCondition(WithinRange, SingleValue(0))},
1874 ErrnoIrrelevant,
1875 "Assuming the character is not an ASCII character"));
1876 addToFunctionSummaryMap(
1877 "isblank", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1878 Summary(EvalCallAsPure)
1879 .Case({ArgumentCondition(0U, WithinRange, {{'\t', '\t'}, {' ', ' '}}),
1880 ReturnValueCondition(OutOfRange, SingleValue(0))},
1881 ErrnoIrrelevant, "Assuming the character is a blank character")
1882 .Case({ArgumentCondition(0U, OutOfRange, {{'\t', '\t'}, {' ', ' '}}),
1883 ReturnValueCondition(WithinRange, SingleValue(0))},
1884 ErrnoIrrelevant,
1885 "Assuming the character is not a blank character"));
1886 addToFunctionSummaryMap(
1887 "iscntrl", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1888 Summary(EvalCallAsPure)
1889 .Case({ArgumentCondition(0U, WithinRange, {{0, 32}, {127, 127}}),
1890 ReturnValueCondition(OutOfRange, SingleValue(0))},
1891 ErrnoIrrelevant,
1892 "Assuming the character is a control character")
1893 .Case({ArgumentCondition(0U, OutOfRange, {{0, 32}, {127, 127}}),
1894 ReturnValueCondition(WithinRange, SingleValue(0))},
1895 ErrnoIrrelevant,
1896 "Assuming the character is not a control character"));
1897 addToFunctionSummaryMap(
1898 "isdigit", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1899 Summary(EvalCallAsPure)
1900 .Case({ArgumentCondition(0U, WithinRange, Range('0', '9')),
1901 ReturnValueCondition(OutOfRange, SingleValue(0))},
1902 ErrnoIrrelevant, "Assuming the character is a digit")
1903 .Case({ArgumentCondition(0U, OutOfRange, Range('0', '9')),
1904 ReturnValueCondition(WithinRange, SingleValue(0))},
1905 ErrnoIrrelevant, "Assuming the character is not a digit"));
1906 addToFunctionSummaryMap(
1907 "isgraph", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1908 Summary(EvalCallAsPure)
1909 .Case({ArgumentCondition(0U, WithinRange, Range(33, 126)),
1910 ReturnValueCondition(OutOfRange, SingleValue(0))},
1911 ErrnoIrrelevant,
1912 "Assuming the character has graphical representation")
1913 .Case(
1914 {ArgumentCondition(0U, OutOfRange, Range(33, 126)),
1915 ReturnValueCondition(WithinRange, SingleValue(0))},
1916 ErrnoIrrelevant,
1917 "Assuming the character does not have graphical representation"));
1918 addToFunctionSummaryMap(
1919 "islower", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1920 Summary(EvalCallAsPure)
1921 // Is certainly lowercase.
1922 .Case({ArgumentCondition(0U, WithinRange, Range('a', 'z')),
1923 ReturnValueCondition(OutOfRange, SingleValue(0))},
1924 ErrnoIrrelevant, "Assuming the character is a lowercase letter")
1925 // Is ascii but not lowercase.
1926 .Case({ArgumentCondition(0U, WithinRange, Range(0, 127)),
1927 ArgumentCondition(0U, OutOfRange, Range('a', 'z')),
1928 ReturnValueCondition(WithinRange, SingleValue(0))},
1929 ErrnoIrrelevant,
1930 "Assuming the character is not a lowercase letter")
1931 // The locale-specific range.
1932 .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})},
1933 ErrnoIrrelevant)
1934 // Is not an unsigned char.
1935 .Case({ArgumentCondition(0U, OutOfRange, Range(0, UCharRangeMax)),
1936 ReturnValueCondition(WithinRange, SingleValue(0))},
1937 ErrnoIrrelevant));
1938 addToFunctionSummaryMap(
1939 "isprint", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1940 Summary(EvalCallAsPure)
1941 .Case({ArgumentCondition(0U, WithinRange, Range(32, 126)),
1942 ReturnValueCondition(OutOfRange, SingleValue(0))},
1943 ErrnoIrrelevant, "Assuming the character is printable")
1944 .Case({ArgumentCondition(0U, OutOfRange, Range(32, 126)),
1945 ReturnValueCondition(WithinRange, SingleValue(0))},
1946 ErrnoIrrelevant, "Assuming the character is non-printable"));
1947 addToFunctionSummaryMap(
1948 "ispunct", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1949 Summary(EvalCallAsPure)
1950 .Case({ArgumentCondition(
1951 0U, WithinRange,
1952 {{'!', '/'}, {':', '@'}, {'[', '`'}, {'{', '~'}}),
1953 ReturnValueCondition(OutOfRange, SingleValue(0))},
1954 ErrnoIrrelevant, "Assuming the character is a punctuation mark")
1955 .Case({ArgumentCondition(
1956 0U, OutOfRange,
1957 {{'!', '/'}, {':', '@'}, {'[', '`'}, {'{', '~'}}),
1958 ReturnValueCondition(WithinRange, SingleValue(0))},
1959 ErrnoIrrelevant,
1960 "Assuming the character is not a punctuation mark"));
1961 addToFunctionSummaryMap(
1962 "isspace", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1963 Summary(EvalCallAsPure)
1964 // Space, '\f', '\n', '\r', '\t', '\v'.
1965 .Case({ArgumentCondition(0U, WithinRange, {{9, 13}, {' ', ' '}}),
1966 ReturnValueCondition(OutOfRange, SingleValue(0))},
1967 ErrnoIrrelevant,
1968 "Assuming the character is a whitespace character")
1969 // The locale-specific range.
1970 .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})},
1971 ErrnoIrrelevant)
1972 .Case({ArgumentCondition(0U, OutOfRange,
1973 {{9, 13}, {' ', ' '}, {128, UCharRangeMax}}),
1974 ReturnValueCondition(WithinRange, SingleValue(0))},
1975 ErrnoIrrelevant,
1976 "Assuming the character is not a whitespace character"));
1977 addToFunctionSummaryMap(
1978 "isupper", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1979 Summary(EvalCallAsPure)
1980 // Is certainly uppercase.
1981 .Case({ArgumentCondition(0U, WithinRange, Range('A', 'Z')),
1982 ReturnValueCondition(OutOfRange, SingleValue(0))},
1983 ErrnoIrrelevant,
1984 "Assuming the character is an uppercase letter")
1985 // The locale-specific range.
1986 .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})},
1987 ErrnoIrrelevant)
1988 // Other.
1989 .Case({ArgumentCondition(0U, OutOfRange,
1990 {{'A', 'Z'}, {128, UCharRangeMax}}),
1991 ReturnValueCondition(WithinRange, SingleValue(0))},
1992 ErrnoIrrelevant,
1993 "Assuming the character is not an uppercase letter"));
1994 addToFunctionSummaryMap(
1995 "isxdigit", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1996 Summary(EvalCallAsPure)
1997 .Case({ArgumentCondition(0U, WithinRange,
1998 {{'0', '9'}, {'A', 'F'}, {'a', 'f'}}),
1999 ReturnValueCondition(OutOfRange, SingleValue(0))},
2000 ErrnoIrrelevant,
2001 "Assuming the character is a hexadecimal digit")
2002 .Case({ArgumentCondition(0U, OutOfRange,
2003 {{'0', '9'}, {'A', 'F'}, {'a', 'f'}}),
2004 ReturnValueCondition(WithinRange, SingleValue(0))},
2005 ErrnoIrrelevant,
2006 "Assuming the character is not a hexadecimal digit"));
2007 addToFunctionSummaryMap(
2008 "toupper", Signature(ArgTypes{IntTy}, RetType{IntTy}),
2009 Summary(EvalCallAsPure)
2010 .ArgConstraint(ArgumentCondition(0U, WithinRange,
2011 {{EOFv, EOFv}, {0, UCharRangeMax}},
2012 "an unsigned char value or EOF")));
2013 addToFunctionSummaryMap(
2014 "tolower", Signature(ArgTypes{IntTy}, RetType{IntTy}),
2015 Summary(EvalCallAsPure)
2016 .ArgConstraint(ArgumentCondition(0U, WithinRange,
2017 {{EOFv, EOFv}, {0, UCharRangeMax}},
2018 "an unsigned char value or EOF")));
2019 addToFunctionSummaryMap(
2020 "toascii", Signature(ArgTypes{IntTy}, RetType{IntTy}),
2021 Summary(EvalCallAsPure)
2022 .ArgConstraint(ArgumentCondition(0U, WithinRange,
2023 {{EOFv, EOFv}, {0, UCharRangeMax}},
2024 "an unsigned char value or EOF")));
2025
2026 addToFunctionSummaryMap(
2027 "getchar", Signature(ArgTypes{}, RetType{IntTy}),
2028 Summary(NoEvalCall)
2029 .Case({ReturnValueCondition(WithinRange,
2030 {{EOFv, EOFv}, {0, UCharRangeMax}})},
2031 ErrnoIrrelevant));
2032
2033 // read()-like functions that never return more than buffer size.
2034 auto FreadSummary =
2035 Summary(NoEvalCall)
2036 .Case({ArgumentCondition(1U, WithinRange, Range(1, SizeMax)),
2037 ArgumentCondition(2U, WithinRange, Range(1, SizeMax)),
2038 ReturnValueCondition(BO_LT, ArgNo(2)),
2039 ReturnValueCondition(WithinRange, Range(0, SizeMax))},
2040 ErrnoNEZeroIrrelevant, GenericFailureMsg)
2041 .Case({ArgumentCondition(1U, WithinRange, Range(1, SizeMax)),
2042 ReturnValueCondition(BO_EQ, ArgNo(2)),
2043 ReturnValueCondition(WithinRange, Range(0, SizeMax))},
2044 ErrnoMustNotBeChecked, GenericSuccessMsg)
2045 .Case({ArgumentCondition(1U, WithinRange, SingleValue(0)),
2046 ReturnValueCondition(WithinRange, SingleValue(0))},
2047 ErrnoMustNotBeChecked,
2048 "Assuming that argument 'size' to '{0}' is 0")
2049 .ArgConstraint(NotNullBuffer(ArgNo(0), ArgNo(1), ArgNo(2)))
2050 .ArgConstraint(NotNull(ArgNo(3)))
2051 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1),
2052 /*BufSizeMultiplier=*/ArgNo(2)));
2053
2054 // size_t fread(void *restrict ptr, size_t size, size_t nitems,
2055 // FILE *restrict stream);
2056 addToFunctionSummaryMap("fread",
2057 Signature(ArgTypes{VoidPtrRestrictTy, SizeTyCanonTy,
2058 SizeTyCanonTy, FilePtrRestrictTy},
2059 RetType{SizeTyCanonTy}),
2060 FreadSummary);
2061 // size_t fwrite(const void *restrict ptr, size_t size, size_t nitems,
2062 // FILE *restrict stream);
2063 addToFunctionSummaryMap(
2064 "fwrite",
2065 Signature(ArgTypes{ConstVoidPtrRestrictTy, SizeTyCanonTy, SizeTyCanonTy,
2066 FilePtrRestrictTy},
2067 RetType{SizeTyCanonTy}),
2068 FreadSummary);
2069
2070 std::optional<QualType> Ssize_tTy = lookupTy("ssize_t");
2071 std::optional<RangeInt> Ssize_tMax = getMaxValue(Ssize_tTy);
2072
2073 auto ReadSummary =
2074 Summary(NoEvalCall)
2075 .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)),
2076 ReturnValueCondition(WithinRange, Range(-1, Ssize_tMax))},
2077 ErrnoIrrelevant);
2078
2079 // FIXME these are actually defined by POSIX and not by the C standard, we
2080 // should handle them together with the rest of the POSIX functions.
2081 // ssize_t read(int fildes, void *buf, size_t nbyte);
2082 addToFunctionSummaryMap(
2083 "read",
2084 Signature(ArgTypes{IntTy, VoidPtrTy, SizeTyCanonTy}, RetType{Ssize_tTy}),
2085 ReadSummary);
2086 // ssize_t write(int fildes, const void *buf, size_t nbyte);
2087 addToFunctionSummaryMap(
2088 "write",
2089 Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTyCanonTy},
2090 RetType{Ssize_tTy}),
2091 ReadSummary);
2092
2093 auto GetLineSummary =
2094 Summary(NoEvalCall)
2095 .Case({ReturnValueCondition(WithinRange,
2096 Range({-1, -1}, {1, Ssize_tMax}))},
2097 ErrnoIrrelevant);
2098
2099 QualType CharPtrPtrRestrictTy = getRestrictTy(getPointerTy(CharPtrTy));
2100
2101 // getline()-like functions either fail or read at least the delimiter.
2102 // FIXME these are actually defined by POSIX and not by the C standard, we
2103 // should handle them together with the rest of the POSIX functions.
2104 // ssize_t getline(char **restrict lineptr, size_t *restrict n,
2105 // FILE *restrict stream);
2106 addToFunctionSummaryMap(
2107 "getline",
2108 Signature(
2109 ArgTypes{CharPtrPtrRestrictTy, SizePtrRestrictTy, FilePtrRestrictTy},
2110 RetType{Ssize_tTy}),
2111 GetLineSummary);
2112 // ssize_t getdelim(char **restrict lineptr, size_t *restrict n,
2113 // int delimiter, FILE *restrict stream);
2114 addToFunctionSummaryMap(
2115 "getdelim",
2116 Signature(ArgTypes{CharPtrPtrRestrictTy, SizePtrRestrictTy, IntTy,
2117 FilePtrRestrictTy},
2118 RetType{Ssize_tTy}),
2119 GetLineSummary);
2120
2121 {
2122 Summary GetenvSummary =
2123 Summary(NoEvalCall)
2124 .ArgConstraint(NotNull(ArgNo(0)))
2125 .Case({NotNull(Ret)}, ErrnoIrrelevant,
2126 "Assuming the environment variable exists");
2127 // In untrusted environments the envvar might not exist.
2128 if (!ShouldAssumeControlledEnvironment)
2129 GetenvSummary.Case({NotNull(Ret)->negate()}, ErrnoIrrelevant,
2130 "Assuming the environment variable does not exist");
2131
2132 // char *getenv(const char *name);
2133 addToFunctionSummaryMap(
2134 "getenv", Signature(ArgTypes{ConstCharPtrTy}, RetType{CharPtrTy}),
2135 std::move(GetenvSummary));
2136 }
2137
2138 if (!ModelPOSIX) {
2139 // Without POSIX use of 'errno' is not specified (in these cases).
2140 // Add these functions without 'errno' checks.
2141 addToFunctionSummaryMap(
2142 {"getc", "fgetc"}, Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
2143 Summary(NoEvalCall)
2144 .Case({ReturnValueCondition(WithinRange,
2145 {{EOFv, EOFv}, {0, UCharRangeMax}})},
2146 ErrnoIrrelevant)
2147 .ArgConstraint(NotNull(ArgNo(0))));
2148 } else {
2149 const auto ReturnsZero =
2150 ConstraintSet{ReturnValueCondition(WithinRange, SingleValue(0))};
2151 const auto ReturnsMinusOne =
2152 ConstraintSet{ReturnValueCondition(WithinRange, SingleValue(-1))};
2153 const auto ReturnsEOF =
2154 ConstraintSet{ReturnValueCondition(WithinRange, SingleValue(EOFv))};
2155 const auto ReturnsNonnegative =
2156 ConstraintSet{ReturnValueCondition(WithinRange, Range(0, IntMax))};
2157 const auto ReturnsNonZero =
2158 ConstraintSet{ReturnValueCondition(OutOfRange, SingleValue(0))};
2159 const auto &ReturnsValidFileDescriptor = ReturnsNonnegative;
2160
2161 auto ValidFileDescriptorOrAtFdcwd = [&](ArgNo ArgN) {
2162 return std::make_shared<RangeConstraint>(
2163 ArgN, WithinRange, Range({AT_FDCWDv, AT_FDCWDv}, {0, IntMax}),
2164 "a valid file descriptor or AT_FDCWD");
2165 };
2166
2167 // FILE *fopen(const char *restrict pathname, const char *restrict mode);
2168 addToFunctionSummaryMap(
2169 "fopen",
2170 Signature(ArgTypes{ConstCharPtrRestrictTy, ConstCharPtrRestrictTy},
2171 RetType{FilePtrTy}),
2172 Summary(NoEvalCall)
2173 .Case({NotNull(Ret)}, ErrnoMustNotBeChecked, GenericSuccessMsg)
2174 .Case({IsNull(Ret)}, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2175 .ArgConstraint(NotNull(ArgNo(0)))
2176 .ArgConstraint(NotNull(ArgNo(1))));
2177
2178 // FILE *fdopen(int fd, const char *mode);
2179 addToFunctionSummaryMap(
2180 "fdopen",
2181 Signature(ArgTypes{IntTy, ConstCharPtrTy}, RetType{FilePtrTy}),
2182 Summary(NoEvalCall)
2183 .Case({NotNull(Ret)}, ErrnoMustNotBeChecked, GenericSuccessMsg)
2184 .Case({IsNull(Ret)}, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2185 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
2186 .ArgConstraint(NotNull(ArgNo(1))));
2187
2188 // FILE *tmpfile(void);
2189 addToFunctionSummaryMap(
2190 "tmpfile", Signature(ArgTypes{}, RetType{FilePtrTy}),
2191 Summary(NoEvalCall)
2192 .Case({NotNull(Ret)}, ErrnoMustNotBeChecked, GenericSuccessMsg)
2193 .Case({IsNull(Ret)}, ErrnoNEZeroIrrelevant, GenericFailureMsg));
2194
2195 // FILE *freopen(const char *restrict pathname, const char *restrict mode,
2196 // FILE *restrict stream);
2197 addToFunctionSummaryMap(
2198 "freopen",
2199 Signature(ArgTypes{ConstCharPtrRestrictTy, ConstCharPtrRestrictTy,
2200 FilePtrRestrictTy},
2201 RetType{FilePtrTy}),
2202 Summary(NoEvalCall)
2203 .Case({ReturnValueCondition(BO_EQ, ArgNo(2))},
2204 ErrnoMustNotBeChecked, GenericSuccessMsg)
2205 .Case({IsNull(Ret)}, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2206 .ArgConstraint(NotNull(ArgNo(1)))
2207 .ArgConstraint(NotNull(ArgNo(2))));
2208
2209 // FILE *popen(const char *command, const char *type);
2210 addToFunctionSummaryMap(
2211 "popen",
2212 Signature(ArgTypes{ConstCharPtrTy, ConstCharPtrTy}, RetType{FilePtrTy}),
2213 Summary(NoEvalCall)
2214 .Case({NotNull(Ret)}, ErrnoMustNotBeChecked, GenericSuccessMsg)
2215 .Case({IsNull(Ret)}, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2216 .ArgConstraint(NotNull(ArgNo(0)))
2217 .ArgConstraint(NotNull(ArgNo(1))));
2218
2219 // int fclose(FILE *stream);
2220 addToFunctionSummaryMap(
2221 "fclose", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
2222 Summary(NoEvalCall)
2223 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2224 .Case(ReturnsEOF, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2225 .ArgConstraint(NotNull(ArgNo(0))));
2226
2227 // int pclose(FILE *stream);
2228 addToFunctionSummaryMap(
2229 "pclose", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
2230 Summary(NoEvalCall)
2231 .Case({ReturnValueCondition(WithinRange, {{0, IntMax}})},
2232 ErrnoMustNotBeChecked, GenericSuccessMsg)
2233 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2234 .ArgConstraint(NotNull(ArgNo(0))));
2235
2236 std::optional<QualType> Off_tTy = lookupTy("off_t");
2237 std::optional<RangeInt> Off_tMax = getMaxValue(Off_tTy);
2238
2239 // int fgetc(FILE *stream);
2240 // 'getc' is the same as 'fgetc' but may be a macro
2241 addToFunctionSummaryMap(
2242 {"getc", "fgetc"}, Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
2243 Summary(NoEvalCall)
2244 .Case({ReturnValueCondition(WithinRange, {{0, UCharRangeMax}})},
2245 ErrnoMustNotBeChecked, GenericSuccessMsg)
2246 .Case({ReturnValueCondition(WithinRange, SingleValue(EOFv))},
2247 ErrnoIrrelevant, GenericFailureMsg)
2248 .ArgConstraint(NotNull(ArgNo(0))));
2249
2250 // int fputc(int c, FILE *stream);
2251 // 'putc' is the same as 'fputc' but may be a macro
2252 addToFunctionSummaryMap(
2253 {"putc", "fputc"},
2254 Signature(ArgTypes{IntTy, FilePtrTy}, RetType{IntTy}),
2255 Summary(NoEvalCall)
2256 .Case({ArgumentCondition(0, WithinRange, Range(0, UCharRangeMax)),
2257 ReturnValueCondition(BO_EQ, ArgNo(0))},
2258 ErrnoMustNotBeChecked, GenericSuccessMsg)
2259 .Case({ArgumentCondition(0, OutOfRange, Range(0, UCharRangeMax)),
2260 ReturnValueCondition(WithinRange, Range(0, UCharRangeMax))},
2261 ErrnoMustNotBeChecked, GenericSuccessMsg)
2262 .Case({ReturnValueCondition(WithinRange, SingleValue(EOFv))},
2263 ErrnoNEZeroIrrelevant, GenericFailureMsg)
2264 .ArgConstraint(NotNull(ArgNo(1))));
2265
2266 // char *fgets(char *restrict s, int n, FILE *restrict stream);
2267 addToFunctionSummaryMap(
2268 "fgets",
2269 Signature(ArgTypes{CharPtrRestrictTy, IntTy, FilePtrRestrictTy},
2270 RetType{CharPtrTy}),
2271 Summary(NoEvalCall)
2272 .Case({NotNull(Ret), ReturnValueCondition(BO_EQ, ArgNo(0))},
2273 ErrnoMustNotBeChecked, GenericSuccessMsg)
2274 .Case({IsNull(Ret)}, ErrnoIrrelevant, GenericFailureMsg)
2275 .ArgConstraint(NotNull(ArgNo(0)))
2276 .ArgConstraint(ArgumentCondition(1, WithinRange, Range(0, IntMax)))
2277 .ArgConstraint(
2278 BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1)))
2279 .ArgConstraint(NotNull(ArgNo(2))));
2280
2281 // int fputs(const char *restrict s, FILE *restrict stream);
2282 addToFunctionSummaryMap(
2283 "fputs",
2284 Signature(ArgTypes{ConstCharPtrRestrictTy, FilePtrRestrictTy},
2285 RetType{IntTy}),
2286 Summary(NoEvalCall)
2287 .Case(ReturnsNonnegative, ErrnoMustNotBeChecked, GenericSuccessMsg)
2288 .Case({ReturnValueCondition(WithinRange, SingleValue(EOFv))},
2289 ErrnoNEZeroIrrelevant, GenericFailureMsg)
2290 .ArgConstraint(NotNull(ArgNo(0)))
2291 .ArgConstraint(NotNull(ArgNo(1))));
2292
2293 // int ungetc(int c, FILE *stream);
2294 addToFunctionSummaryMap(
2295 "ungetc", Signature(ArgTypes{IntTy, FilePtrTy}, RetType{IntTy}),
2296 Summary(NoEvalCall)
2297 .Case({ReturnValueCondition(BO_EQ, ArgNo(0)),
2298 ArgumentCondition(0, WithinRange, {{0, UCharRangeMax}})},
2299 ErrnoMustNotBeChecked, GenericSuccessMsg)
2300 .Case({ReturnValueCondition(WithinRange, SingleValue(EOFv)),
2301 ArgumentCondition(0, WithinRange, SingleValue(EOFv))},
2302 ErrnoNEZeroIrrelevant,
2303 "Assuming that 'ungetc' fails because EOF was passed as "
2304 "character")
2305 .Case({ReturnValueCondition(WithinRange, SingleValue(EOFv)),
2306 ArgumentCondition(0, WithinRange, {{0, UCharRangeMax}})},
2307 ErrnoNEZeroIrrelevant, GenericFailureMsg)
2308 .ArgConstraint(ArgumentCondition(
2309 0, WithinRange, {{EOFv, EOFv}, {0, UCharRangeMax}}))
2310 .ArgConstraint(NotNull(ArgNo(1))));
2311
2312 // int fseek(FILE *stream, long offset, int whence);
2313 // FIXME: It can be possible to get the 'SEEK_' values (like EOFv) and use
2314 // these for condition of arg 2.
2315 // Now the range [0,2] is used (the `SEEK_*` constants are usually 0,1,2).
2316 addToFunctionSummaryMap(
2317 "fseek", Signature(ArgTypes{FilePtrTy, LongTy, IntTy}, RetType{IntTy}),
2318 Summary(NoEvalCall)
2319 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2320 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2321 .ArgConstraint(NotNull(ArgNo(0)))
2322 .ArgConstraint(ArgumentCondition(2, WithinRange, {{0, 2}})));
2323
2324 // int fseeko(FILE *stream, off_t offset, int whence);
2325 addToFunctionSummaryMap(
2326 "fseeko",
2327 Signature(ArgTypes{FilePtrTy, Off_tTy, IntTy}, RetType{IntTy}),
2328 Summary(NoEvalCall)
2329 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2330 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2331 .ArgConstraint(NotNull(ArgNo(0)))
2332 .ArgConstraint(ArgumentCondition(2, WithinRange, {{0, 2}})));
2333
2334 // int fgetpos(FILE *restrict stream, fpos_t *restrict pos);
2335 // From 'The Open Group Base Specifications Issue 7, 2018 edition':
2336 // "The fgetpos() function shall not change the setting of errno if
2337 // successful."
2338 addToFunctionSummaryMap(
2339 "fgetpos",
2340 Signature(ArgTypes{FilePtrRestrictTy, FPosTPtrRestrictTy},
2341 RetType{IntTy}),
2342 Summary(NoEvalCall)
2343 .Case(ReturnsZero, ErrnoUnchanged, GenericSuccessMsg)
2344 .Case(ReturnsNonZero, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2345 .ArgConstraint(NotNull(ArgNo(0)))
2346 .ArgConstraint(NotNull(ArgNo(1))));
2347
2348 // int fsetpos(FILE *stream, const fpos_t *pos);
2349 // From 'The Open Group Base Specifications Issue 7, 2018 edition':
2350 // "The fsetpos() function shall not change the setting of errno if
2351 // successful."
2352 addToFunctionSummaryMap(
2353 "fsetpos",
2354 Signature(ArgTypes{FilePtrTy, ConstFPosTPtrTy}, RetType{IntTy}),
2355 Summary(NoEvalCall)
2356 .Case(ReturnsZero, ErrnoUnchanged, GenericSuccessMsg)
2357 .Case(ReturnsNonZero, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2358 .ArgConstraint(NotNull(ArgNo(0)))
2359 .ArgConstraint(NotNull(ArgNo(1))));
2360
2361 // int fflush(FILE *stream);
2362 addToFunctionSummaryMap(
2363 "fflush", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
2364 Summary(NoEvalCall)
2365 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2366 .Case(ReturnsEOF, ErrnoNEZeroIrrelevant, GenericFailureMsg));
2367
2368 // long ftell(FILE *stream);
2369 // From 'The Open Group Base Specifications Issue 7, 2018 edition':
2370 // "The ftell() function shall not change the setting of errno if
2371 // successful."
2372 addToFunctionSummaryMap(
2373 "ftell", Signature(ArgTypes{FilePtrTy}, RetType{LongTy}),
2374 Summary(NoEvalCall)
2375 .Case({ReturnValueCondition(WithinRange, Range(0, LongMax))},
2376 ErrnoUnchanged, GenericSuccessMsg)
2377 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2378 .ArgConstraint(NotNull(ArgNo(0))));
2379
2380 // off_t ftello(FILE *stream);
2381 addToFunctionSummaryMap(
2382 "ftello", Signature(ArgTypes{FilePtrTy}, RetType{Off_tTy}),
2383 Summary(NoEvalCall)
2384 .Case({ReturnValueCondition(WithinRange, Range(0, Off_tMax))},
2385 ErrnoMustNotBeChecked, GenericSuccessMsg)
2386 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2387 .ArgConstraint(NotNull(ArgNo(0))));
2388
2389 // int fileno(FILE *stream);
2390 // According to POSIX 'fileno' may fail and set 'errno'.
2391 // But in Linux it may fail only if the specified file pointer is invalid.
2392 // At many places 'fileno' is used without check for failure and a failure
2393 // case here would produce a large amount of likely false positive warnings.
2394 // To avoid this, we assume here that it does not fail.
2395 addToFunctionSummaryMap(
2396 "fileno", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
2397 Summary(NoEvalCall)
2398 .Case(ReturnsValidFileDescriptor, ErrnoUnchanged, GenericSuccessMsg)
2399 .ArgConstraint(NotNull(ArgNo(0))));
2400
2401 // void rewind(FILE *stream);
2402 // This function indicates error only by setting of 'errno'.
2403 addToFunctionSummaryMap("rewind",
2404 Signature(ArgTypes{FilePtrTy}, RetType{VoidTy}),
2405 Summary(NoEvalCall)
2406 .Case({}, ErrnoMustBeChecked)
2407 .ArgConstraint(NotNull(ArgNo(0))));
2408
2409 // void clearerr(FILE *stream);
2410 addToFunctionSummaryMap(
2411 "clearerr", Signature(ArgTypes{FilePtrTy}, RetType{VoidTy}),
2412 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2413
2414 // int feof(FILE *stream);
2415 addToFunctionSummaryMap(
2416 "feof", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
2417 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2418
2419 // int ferror(FILE *stream);
2420 addToFunctionSummaryMap(
2421 "ferror", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
2422 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2423
2424 // long a64l(const char *str64);
2425 addToFunctionSummaryMap(
2426 "a64l", Signature(ArgTypes{ConstCharPtrTy}, RetType{LongTy}),
2427 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2428
2429 // char *l64a(long value);
2430 addToFunctionSummaryMap("l64a",
2431 Signature(ArgTypes{LongTy}, RetType{CharPtrTy}),
2432 Summary(NoEvalCall)
2433 .ArgConstraint(ArgumentCondition(
2434 0, WithinRange, Range(0, LongMax))));
2435
2436 // int open(const char *path, int oflag, ...);
2437 addToFunctionSummaryMap(
2438 "open", Signature(ArgTypes{ConstCharPtrTy, IntTy}, RetType{IntTy}),
2439 Summary(NoEvalCall)
2440 .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked,
2441 GenericSuccessMsg)
2442 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2443 .ArgConstraint(NotNull(ArgNo(0))));
2444
2445 // int openat(int fd, const char *path, int oflag, ...);
2446 addToFunctionSummaryMap(
2447 "openat",
2448 Signature(ArgTypes{IntTy, ConstCharPtrTy, IntTy}, RetType{IntTy}),
2449 Summary(NoEvalCall)
2450 .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked,
2451 GenericSuccessMsg)
2452 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2453 .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2454 .ArgConstraint(NotNull(ArgNo(1))));
2455
2456 // int access(const char *pathname, int amode);
2457 addToFunctionSummaryMap(
2458 "access", Signature(ArgTypes{ConstCharPtrTy, IntTy}, RetType{IntTy}),
2459 Summary(NoEvalCall)
2460 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2461 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2462 .ArgConstraint(NotNull(ArgNo(0))));
2463
2464 // int faccessat(int dirfd, const char *pathname, int mode, int flags);
2465 addToFunctionSummaryMap(
2466 "faccessat",
2467 Signature(ArgTypes{IntTy, ConstCharPtrTy, IntTy, IntTy},
2468 RetType{IntTy}),
2469 Summary(NoEvalCall)
2470 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2471 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2472 .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2473 .ArgConstraint(NotNull(ArgNo(1))));
2474
2475 // int dup(int fildes);
2476 addToFunctionSummaryMap(
2477 "dup", Signature(ArgTypes{IntTy}, RetType{IntTy}),
2478 Summary(NoEvalCall)
2479 .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked,
2480 GenericSuccessMsg)
2481 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2482 .ArgConstraint(
2483 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
2484
2485 // int dup2(int fildes1, int filedes2);
2486 addToFunctionSummaryMap(
2487 "dup2", Signature(ArgTypes{IntTy, IntTy}, RetType{IntTy}),
2488 Summary(NoEvalCall)
2489 .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked,
2490 GenericSuccessMsg)
2491 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2492 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
2493 .ArgConstraint(
2494 ArgumentCondition(1, WithinRange, Range(0, IntMax))));
2495
2496 // int fdatasync(int fildes);
2497 addToFunctionSummaryMap(
2498 "fdatasync", Signature(ArgTypes{IntTy}, RetType{IntTy}),
2499 Summary(NoEvalCall)
2500 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2501 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2502 .ArgConstraint(
2503 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
2504
2505 // int fnmatch(const char *pattern, const char *string, int flags);
2506 addToFunctionSummaryMap(
2507 "fnmatch",
2508 Signature(ArgTypes{ConstCharPtrTy, ConstCharPtrTy, IntTy},
2509 RetType{IntTy}),
2510 Summary(NoEvalCall)
2511 .ArgConstraint(NotNull(ArgNo(0)))
2512 .ArgConstraint(NotNull(ArgNo(1))));
2513
2514 // int fsync(int fildes);
2515 addToFunctionSummaryMap(
2516 "fsync", Signature(ArgTypes{IntTy}, RetType{IntTy}),
2517 Summary(NoEvalCall)
2518 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2519 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2520 .ArgConstraint(
2521 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
2522
2523 // int truncate(const char *path, off_t length);
2524 addToFunctionSummaryMap(
2525 "truncate",
2526 Signature(ArgTypes{ConstCharPtrTy, Off_tTy}, RetType{IntTy}),
2527 Summary(NoEvalCall)
2528 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2529 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2530 .ArgConstraint(NotNull(ArgNo(0))));
2531
2532 // int symlink(const char *oldpath, const char *newpath);
2533 addToFunctionSummaryMap(
2534 "symlink",
2535 Signature(ArgTypes{ConstCharPtrTy, ConstCharPtrTy}, RetType{IntTy}),
2536 Summary(NoEvalCall)
2537 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2538 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2539 .ArgConstraint(NotNull(ArgNo(0)))
2540 .ArgConstraint(NotNull(ArgNo(1))));
2541
2542 // int symlinkat(const char *oldpath, int newdirfd, const char *newpath);
2543 addToFunctionSummaryMap(
2544 "symlinkat",
2545 Signature(ArgTypes{ConstCharPtrTy, IntTy, ConstCharPtrTy},
2546 RetType{IntTy}),
2547 Summary(NoEvalCall)
2548 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2549 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2550 .ArgConstraint(NotNull(ArgNo(0)))
2551 .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(1)))
2552 .ArgConstraint(NotNull(ArgNo(2))));
2553
2554 // int lockf(int fd, int cmd, off_t len);
2555 addToFunctionSummaryMap(
2556 "lockf", Signature(ArgTypes{IntTy, IntTy, Off_tTy}, RetType{IntTy}),
2557 Summary(NoEvalCall)
2558 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2559 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2560 .ArgConstraint(
2561 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
2562
2563 std::optional<QualType> Mode_tTy = lookupTy("mode_t");
2564
2565 // int creat(const char *pathname, mode_t mode);
2566 addToFunctionSummaryMap(
2567 "creat", Signature(ArgTypes{ConstCharPtrTy, Mode_tTy}, RetType{IntTy}),
2568 Summary(NoEvalCall)
2569 .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked,
2570 GenericSuccessMsg)
2571 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2572 .ArgConstraint(NotNull(ArgNo(0))));
2573
2574 // unsigned int sleep(unsigned int seconds);
2575 addToFunctionSummaryMap(
2576 "sleep", Signature(ArgTypes{UnsignedIntTy}, RetType{UnsignedIntTy}),
2577 Summary(NoEvalCall)
2578 .ArgConstraint(
2579 ArgumentCondition(0, WithinRange, Range(0, UnsignedIntMax))));
2580
2581 std::optional<QualType> DirTy = lookupTy("DIR");
2582 std::optional<QualType> DirPtrTy = getPointerTy(DirTy);
2583
2584 // int dirfd(DIR *dirp);
2585 addToFunctionSummaryMap(
2586 "dirfd", Signature(ArgTypes{DirPtrTy}, RetType{IntTy}),
2587 Summary(NoEvalCall)
2588 .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked,
2589 GenericSuccessMsg)
2590 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2591 .ArgConstraint(NotNull(ArgNo(0))));
2592
2593 // unsigned int alarm(unsigned int seconds);
2594 addToFunctionSummaryMap(
2595 "alarm", Signature(ArgTypes{UnsignedIntTy}, RetType{UnsignedIntTy}),
2596 Summary(NoEvalCall)
2597 .ArgConstraint(
2598 ArgumentCondition(0, WithinRange, Range(0, UnsignedIntMax))));
2599
2600 // int closedir(DIR *dir);
2601 addToFunctionSummaryMap(
2602 "closedir", Signature(ArgTypes{DirPtrTy}, RetType{IntTy}),
2603 Summary(NoEvalCall)
2604 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2605 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2606 .ArgConstraint(NotNull(ArgNo(0))));
2607
2608 // char *strdup(const char *s);
2609 addToFunctionSummaryMap(
2610 "strdup", Signature(ArgTypes{ConstCharPtrTy}, RetType{CharPtrTy}),
2611 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2612
2613 // char *strndup(const char *s, size_t n);
2614 addToFunctionSummaryMap(
2615 "strndup",
2616 Signature(ArgTypes{ConstCharPtrTy, SizeTyCanonTy}, RetType{CharPtrTy}),
2617 Summary(NoEvalCall)
2618 .ArgConstraint(NotNull(ArgNo(0)))
2619 .ArgConstraint(
2620 ArgumentCondition(1, WithinRange, Range(0, SizeMax))));
2621
2622 // wchar_t *wcsdup(const wchar_t *s);
2623 addToFunctionSummaryMap(
2624 "wcsdup", Signature(ArgTypes{ConstWchar_tPtrTy}, RetType{Wchar_tPtrTy}),
2625 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2626
2627 // int mkstemp(char *template);
2628 addToFunctionSummaryMap(
2629 "mkstemp", Signature(ArgTypes{CharPtrTy}, RetType{IntTy}),
2630 Summary(NoEvalCall)
2631 .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked,
2632 GenericSuccessMsg)
2633 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2634 .ArgConstraint(NotNull(ArgNo(0))));
2635
2636 // char *mkdtemp(char *template);
2637 addToFunctionSummaryMap(
2638 "mkdtemp", Signature(ArgTypes{CharPtrTy}, RetType{CharPtrTy}),
2639 Summary(NoEvalCall)
2640 .Case({NotNull(Ret), ReturnValueCondition(BO_EQ, ArgNo(0))},
2641 ErrnoMustNotBeChecked, GenericSuccessMsg)
2642 .Case({IsNull(Ret)}, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2643 .ArgConstraint(NotNull(ArgNo(0))));
2644
2645 // char *getcwd(char *buf, size_t size);
2646 addToFunctionSummaryMap(
2647 "getcwd",
2648 Signature(ArgTypes{CharPtrTy, SizeTyCanonTy}, RetType{CharPtrTy}),
2649 Summary(NoEvalCall)
2650 .Case({NotNull(0),
2651 ArgumentCondition(1, WithinRange, Range(1, SizeMax)),
2652 ReturnValueCondition(BO_EQ, ArgNo(0)), NotNull(Ret)},
2653 ErrnoMustNotBeChecked, GenericSuccessMsg)
2654 .Case({NotNull(0),
2655 ArgumentCondition(1, WithinRange, SingleValue(0)),
2656 IsNull(Ret)},
2657 ErrnoNEZeroIrrelevant, "Assuming that argument 'size' is 0")
2658 .Case({NotNull(0),
2659 ArgumentCondition(1, WithinRange, Range(1, SizeMax)),
2660 IsNull(Ret)},
2661 ErrnoNEZeroIrrelevant, GenericFailureMsg)
2662 .Case({IsNull(0), NotNull(Ret)}, ErrnoMustNotBeChecked,
2663 GenericSuccessMsg)
2664 .Case({IsNull(0), IsNull(Ret)}, ErrnoNEZeroIrrelevant,
2665 GenericFailureMsg)
2666 .ArgConstraint(
2667 BufferSize(/*Buffer*/ ArgNo(0), /*BufSize*/ ArgNo(1)))
2668 .ArgConstraint(
2669 ArgumentCondition(1, WithinRange, Range(0, SizeMax))));
2670
2671 // int mkdir(const char *pathname, mode_t mode);
2672 addToFunctionSummaryMap(
2673 "mkdir", Signature(ArgTypes{ConstCharPtrTy, Mode_tTy}, RetType{IntTy}),
2674 Summary(NoEvalCall)
2675 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2676 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2677 .ArgConstraint(NotNull(ArgNo(0))));
2678
2679 // int mkdirat(int dirfd, const char *pathname, mode_t mode);
2680 addToFunctionSummaryMap(
2681 "mkdirat",
2682 Signature(ArgTypes{IntTy, ConstCharPtrTy, Mode_tTy}, RetType{IntTy}),
2683 Summary(NoEvalCall)
2684 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2685 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2686 .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2687 .ArgConstraint(NotNull(ArgNo(1))));
2688
2689 std::optional<QualType> Dev_tTy = lookupTy("dev_t");
2690
2691 // int mknod(const char *pathname, mode_t mode, dev_t dev);
2692 addToFunctionSummaryMap(
2693 "mknod",
2694 Signature(ArgTypes{ConstCharPtrTy, Mode_tTy, Dev_tTy}, RetType{IntTy}),
2695 Summary(NoEvalCall)
2696 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2697 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2698 .ArgConstraint(NotNull(ArgNo(0))));
2699
2700 // int mknodat(int dirfd, const char *pathname, mode_t mode, dev_t dev);
2701 addToFunctionSummaryMap(
2702 "mknodat",
2703 Signature(ArgTypes{IntTy, ConstCharPtrTy, Mode_tTy, Dev_tTy},
2704 RetType{IntTy}),
2705 Summary(NoEvalCall)
2706 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2707 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2708 .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2709 .ArgConstraint(NotNull(ArgNo(1))));
2710
2711 // int chmod(const char *path, mode_t mode);
2712 addToFunctionSummaryMap(
2713 "chmod", Signature(ArgTypes{ConstCharPtrTy, Mode_tTy}, RetType{IntTy}),
2714 Summary(NoEvalCall)
2715 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2716 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2717 .ArgConstraint(NotNull(ArgNo(0))));
2718
2719 // int fchmodat(int dirfd, const char *pathname, mode_t mode, int flags);
2720 addToFunctionSummaryMap(
2721 "fchmodat",
2722 Signature(ArgTypes{IntTy, ConstCharPtrTy, Mode_tTy, IntTy},
2723 RetType{IntTy}),
2724 Summary(NoEvalCall)
2725 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2726 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2727 .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2728 .ArgConstraint(NotNull(ArgNo(1))));
2729
2730 // int fchmod(int fildes, mode_t mode);
2731 addToFunctionSummaryMap(
2732 "fchmod", Signature(ArgTypes{IntTy, Mode_tTy}, RetType{IntTy}),
2733 Summary(NoEvalCall)
2734 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2735 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2736 .ArgConstraint(
2737 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
2738
2739 std::optional<QualType> Uid_tTy = lookupTy("uid_t");
2740 std::optional<QualType> Gid_tTy = lookupTy("gid_t");
2741
2742 // int fchownat(int dirfd, const char *pathname, uid_t owner, gid_t group,
2743 // int flags);
2744 addToFunctionSummaryMap(
2745 "fchownat",
2746 Signature(ArgTypes{IntTy, ConstCharPtrTy, Uid_tTy, Gid_tTy, IntTy},
2747 RetType{IntTy}),
2748 Summary(NoEvalCall)
2749 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2750 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2751 .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2752 .ArgConstraint(NotNull(ArgNo(1))));
2753
2754 // int chown(const char *path, uid_t owner, gid_t group);
2755 addToFunctionSummaryMap(
2756 "chown",
2757 Signature(ArgTypes{ConstCharPtrTy, Uid_tTy, Gid_tTy}, RetType{IntTy}),
2758 Summary(NoEvalCall)
2759 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2760 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2761 .ArgConstraint(NotNull(ArgNo(0))));
2762
2763 // int lchown(const char *path, uid_t owner, gid_t group);
2764 addToFunctionSummaryMap(
2765 "lchown",
2766 Signature(ArgTypes{ConstCharPtrTy, Uid_tTy, Gid_tTy}, RetType{IntTy}),
2767 Summary(NoEvalCall)
2768 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2769 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2770 .ArgConstraint(NotNull(ArgNo(0))));
2771
2772 // int fchown(int fildes, uid_t owner, gid_t group);
2773 addToFunctionSummaryMap(
2774 "fchown", Signature(ArgTypes{IntTy, Uid_tTy, Gid_tTy}, RetType{IntTy}),
2775 Summary(NoEvalCall)
2776 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2777 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2778 .ArgConstraint(
2779 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
2780
2781 // int rmdir(const char *pathname);
2782 addToFunctionSummaryMap(
2783 "rmdir", Signature(ArgTypes{ConstCharPtrTy}, RetType{IntTy}),
2784 Summary(NoEvalCall)
2785 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2786 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2787 .ArgConstraint(NotNull(ArgNo(0))));
2788
2789 // int chdir(const char *path);
2790 addToFunctionSummaryMap(
2791 "chdir", Signature(ArgTypes{ConstCharPtrTy}, RetType{IntTy}),
2792 Summary(NoEvalCall)
2793 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2794 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2795 .ArgConstraint(NotNull(ArgNo(0))));
2796
2797 // int link(const char *oldpath, const char *newpath);
2798 addToFunctionSummaryMap(
2799 "link",
2800 Signature(ArgTypes{ConstCharPtrTy, ConstCharPtrTy}, RetType{IntTy}),
2801 Summary(NoEvalCall)
2802 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2803 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2804 .ArgConstraint(NotNull(ArgNo(0)))
2805 .ArgConstraint(NotNull(ArgNo(1))));
2806
2807 // int linkat(int fd1, const char *path1, int fd2, const char *path2,
2808 // int flag);
2809 addToFunctionSummaryMap(
2810 "linkat",
2811 Signature(ArgTypes{IntTy, ConstCharPtrTy, IntTy, ConstCharPtrTy, IntTy},
2812 RetType{IntTy}),
2813 Summary(NoEvalCall)
2814 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2815 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2816 .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2817 .ArgConstraint(NotNull(ArgNo(1)))
2818 .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(2)))
2819 .ArgConstraint(NotNull(ArgNo(3))));
2820
2821 // int unlink(const char *pathname);
2822 addToFunctionSummaryMap(
2823 "unlink", Signature(ArgTypes{ConstCharPtrTy}, RetType{IntTy}),
2824 Summary(NoEvalCall)
2825 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2826 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2827 .ArgConstraint(NotNull(ArgNo(0))));
2828
2829 // int unlinkat(int fd, const char *path, int flag);
2830 addToFunctionSummaryMap(
2831 "unlinkat",
2832 Signature(ArgTypes{IntTy, ConstCharPtrTy, IntTy}, RetType{IntTy}),
2833 Summary(NoEvalCall)
2834 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2835 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2836 .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2837 .ArgConstraint(NotNull(ArgNo(1))));
2838
2839 std::optional<QualType> StructStatTy = lookupTy("stat");
2840 std::optional<QualType> StructStatPtrTy = getPointerTy(StructStatTy);
2841 std::optional<QualType> StructStatPtrRestrictTy =
2842 getRestrictTy(StructStatPtrTy);
2843
2844 // int fstat(int fd, struct stat *statbuf);
2845 addToFunctionSummaryMap(
2846 "fstat", Signature(ArgTypes{IntTy, StructStatPtrTy}, RetType{IntTy}),
2847 Summary(NoEvalCall)
2848 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2849 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2850 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
2851 .ArgConstraint(NotNull(ArgNo(1))));
2852
2853 // int stat(const char *restrict path, struct stat *restrict buf);
2854 addToFunctionSummaryMap(
2855 "stat",
2856 Signature(ArgTypes{ConstCharPtrRestrictTy, StructStatPtrRestrictTy},
2857 RetType{IntTy}),
2858 Summary(NoEvalCall)
2859 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2860 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2861 .ArgConstraint(NotNull(ArgNo(0)))
2862 .ArgConstraint(NotNull(ArgNo(1))));
2863
2864 // int lstat(const char *restrict path, struct stat *restrict buf);
2865 addToFunctionSummaryMap(
2866 "lstat",
2867 Signature(ArgTypes{ConstCharPtrRestrictTy, StructStatPtrRestrictTy},
2868 RetType{IntTy}),
2869 Summary(NoEvalCall)
2870 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2871 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2872 .ArgConstraint(NotNull(ArgNo(0)))
2873 .ArgConstraint(NotNull(ArgNo(1))));
2874
2875 // int fstatat(int fd, const char *restrict path,
2876 // struct stat *restrict buf, int flag);
2877 addToFunctionSummaryMap(
2878 "fstatat",
2879 Signature(ArgTypes{IntTy, ConstCharPtrRestrictTy,
2880 StructStatPtrRestrictTy, IntTy},
2881 RetType{IntTy}),
2882 Summary(NoEvalCall)
2883 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2884 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2885 .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2886 .ArgConstraint(NotNull(ArgNo(1)))
2887 .ArgConstraint(NotNull(ArgNo(2))));
2888
2889 // DIR *opendir(const char *name);
2890 addToFunctionSummaryMap(
2891 "opendir", Signature(ArgTypes{ConstCharPtrTy}, RetType{DirPtrTy}),
2892 Summary(NoEvalCall)
2893 .Case({NotNull(Ret)}, ErrnoMustNotBeChecked, GenericSuccessMsg)
2894 .Case({IsNull(Ret)}, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2895 .ArgConstraint(NotNull(ArgNo(0))));
2896
2897 // DIR *fdopendir(int fd);
2898 addToFunctionSummaryMap(
2899 "fdopendir", Signature(ArgTypes{IntTy}, RetType{DirPtrTy}),
2900 Summary(NoEvalCall)
2901 .Case({NotNull(Ret)}, ErrnoMustNotBeChecked, GenericSuccessMsg)
2902 .Case({IsNull(Ret)}, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2903 .ArgConstraint(
2904 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
2905
2906 // int isatty(int fildes);
2907 addToFunctionSummaryMap(
2908 "isatty", Signature(ArgTypes{IntTy}, RetType{IntTy}),
2909 Summary(NoEvalCall)
2910 .Case({ReturnValueCondition(WithinRange, Range(0, 1))},
2911 ErrnoIrrelevant)
2912 .ArgConstraint(
2913 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
2914
2915 // int close(int fildes);
2916 addToFunctionSummaryMap(
2917 "close", Signature(ArgTypes{IntTy}, RetType{IntTy}),
2918 Summary(NoEvalCall)
2919 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2920 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2921 .ArgConstraint(
2922 ArgumentCondition(0, WithinRange, Range(-1, IntMax))));
2923
2924 // long fpathconf(int fildes, int name);
2925 addToFunctionSummaryMap("fpathconf",
2926 Signature(ArgTypes{IntTy, IntTy}, RetType{LongTy}),
2927 Summary(NoEvalCall)
2928 .ArgConstraint(ArgumentCondition(
2929 0, WithinRange, Range(0, IntMax))));
2930
2931 // long pathconf(const char *path, int name);
2932 addToFunctionSummaryMap(
2933 "pathconf", Signature(ArgTypes{ConstCharPtrTy, IntTy}, RetType{LongTy}),
2934 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2935
2936 // void rewinddir(DIR *dir);
2937 addToFunctionSummaryMap(
2938 "rewinddir", Signature(ArgTypes{DirPtrTy}, RetType{VoidTy}),
2939 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2940
2941 // void seekdir(DIR *dirp, long loc);
2942 addToFunctionSummaryMap(
2943 "seekdir", Signature(ArgTypes{DirPtrTy, LongTy}, RetType{VoidTy}),
2944 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2945
2946 // int rand_r(unsigned int *seedp);
2947 addToFunctionSummaryMap(
2948 "rand_r", Signature(ArgTypes{UnsignedIntPtrTy}, RetType{IntTy}),
2949 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2950
2951 // void *mmap(void *addr, size_t length, int prot, int flags, int fd,
2952 // off_t offset);
2953 // FIXME: Improve for errno modeling.
2954 auto MmapSignature = Signature(
2955 ArgTypes{VoidPtrTy, SizeTyCanonTy, IntTy, IntTy, IntTy, Off_tTy},
2956 RetType{VoidPtrTy});
2957 auto MmapSummaryWithLengthConstraint =
2958 Summary(NoEvalCall)
2959 .ArgConstraint(
2960 ArgumentCondition(1, WithinRange, Range(1, SizeMax)));
2961
2962 if (ACtx.getTargetInfo().getTriple().isOSDarwin()) {
2963 // On Darwin, MAP_ANON + VM_MAKE_TAG(tag) uses argument 4 (len) for
2964 // the tag, which looks like a large negative signed integer.
2965 // The valid range for fd is not expressible as a simple union of
2966 // ranges so we only constrain the length parameter.
2967 addToFunctionSummaryMap("mmap", MmapSignature,
2968 MmapSummaryWithLengthConstraint);
2969 } else {
2970 // On other platforms, we also constrain the fd parameter (-1 <= fd).
2971 addToFunctionSummaryMap(
2972 "mmap", MmapSignature,
2973 MmapSummaryWithLengthConstraint.ArgConstraint(
2974 ArgumentCondition(4, WithinRange, Range(-1, IntMax))));
2975 }
2976
2977 std::optional<QualType> Off64_tTy = lookupTy("off64_t");
2978 // void *mmap64(void *addr, size_t length, int prot, int flags, int fd,
2979 // off64_t offset);
2980 // FIXME: Improve for errno modeling.
2981 addToFunctionSummaryMap(
2982 "mmap64",
2983 Signature(
2984 ArgTypes{VoidPtrTy, SizeTyCanonTy, IntTy, IntTy, IntTy, Off64_tTy},
2985 RetType{VoidPtrTy}),
2986 Summary(NoEvalCall)
2987 .ArgConstraint(ArgumentCondition(1, WithinRange, Range(1, SizeMax)))
2988 .ArgConstraint(
2989 ArgumentCondition(4, WithinRange, Range(-1, IntMax))));
2990
2991 // int pipe(int fildes[2]);
2992 addToFunctionSummaryMap(
2993 "pipe", Signature(ArgTypes{IntPtrTy}, RetType{IntTy}),
2994 Summary(NoEvalCall)
2995 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2996 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2997 .ArgConstraint(NotNull(ArgNo(0))));
2998
2999 // off_t lseek(int fildes, off_t offset, int whence);
3000 // In the first case we can not tell for sure if it failed or not.
3001 // A return value different from of the expected offset (that is unknown
3002 // here) may indicate failure. For this reason we do not enforce the errno
3003 // check (can cause false positive).
3004 addToFunctionSummaryMap(
3005 "lseek", Signature(ArgTypes{IntTy, Off_tTy, IntTy}, RetType{Off_tTy}),
3006 Summary(NoEvalCall)
3007 .Case(ReturnsNonnegative, ErrnoIrrelevant)
3008 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3009 .ArgConstraint(
3010 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
3011
3012 // ssize_t readlink(const char *restrict path, char *restrict buf,
3013 // size_t bufsize);
3014 addToFunctionSummaryMap(
3015 "readlink",
3016 Signature(
3017 ArgTypes{ConstCharPtrRestrictTy, CharPtrRestrictTy, SizeTyCanonTy},
3018 RetType{Ssize_tTy}),
3019 Summary(NoEvalCall)
3020 .Case({ArgumentCondition(2, WithinRange, Range(1, IntMax)),
3021 ReturnValueCondition(LessThanOrEq, ArgNo(2)),
3022 ReturnValueCondition(WithinRange, Range(1, Ssize_tMax))},
3023 ErrnoMustNotBeChecked, GenericSuccessMsg)
3024 .Case({ArgumentCondition(2, WithinRange, SingleValue(0)),
3025 ReturnValueCondition(WithinRange, SingleValue(0))},
3026 ErrnoMustNotBeChecked,
3027 "Assuming that argument 'bufsize' is 0")
3028 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3029 .ArgConstraint(NotNull(ArgNo(0)))
3030 .ArgConstraint(NotNull(ArgNo(1)))
3031 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
3032 /*BufSize=*/ArgNo(2)))
3033 .ArgConstraint(
3034 ArgumentCondition(2, WithinRange, Range(0, SizeMax))));
3035
3036 // ssize_t readlinkat(int fd, const char *restrict path,
3037 // char *restrict buf, size_t bufsize);
3038 addToFunctionSummaryMap(
3039 "readlinkat",
3040 Signature(ArgTypes{IntTy, ConstCharPtrRestrictTy, CharPtrRestrictTy,
3041 SizeTyCanonTy},
3042 RetType{Ssize_tTy}),
3043 Summary(NoEvalCall)
3044 .Case({ArgumentCondition(3, WithinRange, Range(1, IntMax)),
3045 ReturnValueCondition(LessThanOrEq, ArgNo(3)),
3046 ReturnValueCondition(WithinRange, Range(1, Ssize_tMax))},
3047 ErrnoMustNotBeChecked, GenericSuccessMsg)
3048 .Case({ArgumentCondition(3, WithinRange, SingleValue(0)),
3049 ReturnValueCondition(WithinRange, SingleValue(0))},
3050 ErrnoMustNotBeChecked,
3051 "Assuming that argument 'bufsize' is 0")
3052 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3053 .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
3054 .ArgConstraint(NotNull(ArgNo(1)))
3055 .ArgConstraint(NotNull(ArgNo(2)))
3056 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(2),
3057 /*BufSize=*/ArgNo(3)))
3058 .ArgConstraint(
3059 ArgumentCondition(3, WithinRange, Range(0, SizeMax))));
3060
3061 // int renameat(int olddirfd, const char *oldpath, int newdirfd, const char
3062 // *newpath);
3063 addToFunctionSummaryMap(
3064 "renameat",
3065 Signature(ArgTypes{IntTy, ConstCharPtrTy, IntTy, ConstCharPtrTy},
3066 RetType{IntTy}),
3067 Summary(NoEvalCall)
3068 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3069 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3070 .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
3071 .ArgConstraint(NotNull(ArgNo(1)))
3072 .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(2)))
3073 .ArgConstraint(NotNull(ArgNo(3))));
3074
3075 // char *realpath(const char *restrict file_name,
3076 // char *restrict resolved_name);
3077 // FIXME: If the argument 'resolved_name' is not NULL, macro 'PATH_MAX'
3078 // should be defined in "limits.h" to guarrantee a success.
3079 addToFunctionSummaryMap(
3080 "realpath",
3081 Signature(ArgTypes{ConstCharPtrRestrictTy, CharPtrRestrictTy},
3082 RetType{CharPtrTy}),
3083 Summary(NoEvalCall)
3084 .Case({NotNull(Ret)}, ErrnoMustNotBeChecked, GenericSuccessMsg)
3085 .Case({IsNull(Ret)}, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3086 .ArgConstraint(NotNull(ArgNo(0))));
3087
3088 QualType CharPtrConstPtr = getPointerTy(getConstTy(CharPtrTy));
3089
3090 // int execv(const char *path, char *const argv[]);
3091 addToFunctionSummaryMap(
3092 "execv",
3093 Signature(ArgTypes{ConstCharPtrTy, CharPtrConstPtr}, RetType{IntTy}),
3094 Summary(NoEvalCall)
3095 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
3096 .ArgConstraint(NotNull(ArgNo(0))));
3097
3098 // int execvp(const char *file, char *const argv[]);
3099 addToFunctionSummaryMap(
3100 "execvp",
3101 Signature(ArgTypes{ConstCharPtrTy, CharPtrConstPtr}, RetType{IntTy}),
3102 Summary(NoEvalCall)
3103 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
3104 .ArgConstraint(NotNull(ArgNo(0))));
3105
3106 // int getopt(int argc, char * const argv[], const char *optstring);
3107 addToFunctionSummaryMap(
3108 "getopt",
3109 Signature(ArgTypes{IntTy, CharPtrConstPtr, ConstCharPtrTy},
3110 RetType{IntTy}),
3111 Summary(NoEvalCall)
3112 .Case({ReturnValueCondition(WithinRange, Range(-1, UCharRangeMax))},
3113 ErrnoIrrelevant)
3114 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
3115 .ArgConstraint(NotNull(ArgNo(1)))
3116 .ArgConstraint(NotNull(ArgNo(2))));
3117
3118 std::optional<QualType> StructSockaddrTy = lookupTy("sockaddr");
3119 std::optional<QualType> StructSockaddrPtrTy =
3120 getPointerTy(StructSockaddrTy);
3121 std::optional<QualType> ConstStructSockaddrPtrTy =
3122 getPointerTy(getConstTy(StructSockaddrTy));
3123 std::optional<QualType> StructSockaddrPtrRestrictTy =
3124 getRestrictTy(StructSockaddrPtrTy);
3125 std::optional<QualType> ConstStructSockaddrPtrRestrictTy =
3126 getRestrictTy(ConstStructSockaddrPtrTy);
3127 std::optional<QualType> Socklen_tTy = lookupTy("socklen_t");
3128 std::optional<QualType> Socklen_tPtrTy = getPointerTy(Socklen_tTy);
3129 std::optional<QualType> Socklen_tPtrRestrictTy =
3130 getRestrictTy(Socklen_tPtrTy);
3131 std::optional<RangeInt> Socklen_tMax = getMaxValue(Socklen_tTy);
3132
3133 // In 'socket.h' of some libc implementations with C99, sockaddr parameter
3134 // is a transparent union of the underlying sockaddr_ family of pointers
3135 // instead of being a pointer to struct sockaddr. In these cases, the
3136 // standardized signature will not match, thus we try to match with another
3137 // signature that has the joker Irrelevant type. We also remove those
3138 // constraints which require pointer types for the sockaddr param.
3139
3140 // int socket(int domain, int type, int protocol);
3141 addToFunctionSummaryMap(
3142 "socket", Signature(ArgTypes{IntTy, IntTy, IntTy}, RetType{IntTy}),
3143 Summary(NoEvalCall)
3144 .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked,
3145 GenericSuccessMsg)
3146 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg));
3147
3148 auto Accept =
3149 Summary(NoEvalCall)
3150 .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked,
3151 GenericSuccessMsg)
3152 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3153 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)));
3154 if (!addToFunctionSummaryMap(
3155 "accept",
3156 // int accept(int socket, struct sockaddr *restrict address,
3157 // socklen_t *restrict address_len);
3158 Signature(ArgTypes{IntTy, StructSockaddrPtrRestrictTy,
3159 Socklen_tPtrRestrictTy},
3160 RetType{IntTy}),
3161 Accept))
3162 addToFunctionSummaryMap(
3163 "accept",
3164 Signature(ArgTypes{IntTy, Irrelevant, Socklen_tPtrRestrictTy},
3165 RetType{IntTy}),
3166 Accept);
3167
3168 // int bind(int socket, const struct sockaddr *address, socklen_t
3169 // address_len);
3170 if (!addToFunctionSummaryMap(
3171 "bind",
3172 Signature(ArgTypes{IntTy, ConstStructSockaddrPtrTy, Socklen_tTy},
3173 RetType{IntTy}),
3174 Summary(NoEvalCall)
3175 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3176 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3177 .ArgConstraint(
3178 ArgumentCondition(0, WithinRange, Range(0, IntMax)))
3179 .ArgConstraint(NotNull(ArgNo(1)))
3180 .ArgConstraint(
3181 BufferSize(/*Buffer=*/ArgNo(1), /*BufSize=*/ArgNo(2)))
3182 .ArgConstraint(
3183 ArgumentCondition(2, WithinRange, Range(0, Socklen_tMax)))))
3184 // Do not add constraints on sockaddr.
3185 addToFunctionSummaryMap(
3186 "bind",
3187 Signature(ArgTypes{IntTy, Irrelevant, Socklen_tTy}, RetType{IntTy}),
3188 Summary(NoEvalCall)
3189 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3190 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3191 .ArgConstraint(
3192 ArgumentCondition(0, WithinRange, Range(0, IntMax)))
3193 .ArgConstraint(
3194 ArgumentCondition(2, WithinRange, Range(0, Socklen_tMax))));
3195
3196 // int getpeername(int socket, struct sockaddr *restrict address,
3197 // socklen_t *restrict address_len);
3198 if (!addToFunctionSummaryMap(
3199 "getpeername",
3200 Signature(ArgTypes{IntTy, StructSockaddrPtrRestrictTy,
3201 Socklen_tPtrRestrictTy},
3202 RetType{IntTy}),
3203 Summary(NoEvalCall)
3204 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3205 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3206 .ArgConstraint(
3207 ArgumentCondition(0, WithinRange, Range(0, IntMax)))
3208 .ArgConstraint(NotNull(ArgNo(1)))
3209 .ArgConstraint(NotNull(ArgNo(2)))))
3210 addToFunctionSummaryMap(
3211 "getpeername",
3212 Signature(ArgTypes{IntTy, Irrelevant, Socklen_tPtrRestrictTy},
3213 RetType{IntTy}),
3214 Summary(NoEvalCall)
3215 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3216 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3217 .ArgConstraint(
3218 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
3219
3220 // int getsockname(int socket, struct sockaddr *restrict address,
3221 // socklen_t *restrict address_len);
3222 if (!addToFunctionSummaryMap(
3223 "getsockname",
3224 Signature(ArgTypes{IntTy, StructSockaddrPtrRestrictTy,
3225 Socklen_tPtrRestrictTy},
3226 RetType{IntTy}),
3227 Summary(NoEvalCall)
3228 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3229 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3230 .ArgConstraint(
3231 ArgumentCondition(0, WithinRange, Range(0, IntMax)))
3232 .ArgConstraint(NotNull(ArgNo(1)))
3233 .ArgConstraint(NotNull(ArgNo(2)))))
3234 addToFunctionSummaryMap(
3235 "getsockname",
3236 Signature(ArgTypes{IntTy, Irrelevant, Socklen_tPtrRestrictTy},
3237 RetType{IntTy}),
3238 Summary(NoEvalCall)
3239 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3240 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3241 .ArgConstraint(
3242 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
3243
3244 // int connect(int socket, const struct sockaddr *address, socklen_t
3245 // address_len);
3246 if (!addToFunctionSummaryMap(
3247 "connect",
3248 Signature(ArgTypes{IntTy, ConstStructSockaddrPtrTy, Socklen_tTy},
3249 RetType{IntTy}),
3250 Summary(NoEvalCall)
3251 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3252 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3253 .ArgConstraint(
3254 ArgumentCondition(0, WithinRange, Range(0, IntMax)))
3255 .ArgConstraint(NotNull(ArgNo(1)))))
3256 addToFunctionSummaryMap(
3257 "connect",
3258 Signature(ArgTypes{IntTy, Irrelevant, Socklen_tTy}, RetType{IntTy}),
3259 Summary(NoEvalCall)
3260 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3261 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3262 .ArgConstraint(
3263 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
3264
3265 auto Recvfrom =
3266 Summary(NoEvalCall)
3267 .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)),
3268 ReturnValueCondition(WithinRange, Range(1, Ssize_tMax))},
3269 ErrnoMustNotBeChecked, GenericSuccessMsg)
3270 .Case({ReturnValueCondition(WithinRange, SingleValue(0)),
3271 ArgumentCondition(2, WithinRange, SingleValue(0))},
3272 ErrnoMustNotBeChecked, GenericSuccessMsg)
3273 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3274 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
3275 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
3276 /*BufSize=*/ArgNo(2)));
3277 if (!addToFunctionSummaryMap(
3278 "recvfrom",
3279 // ssize_t recvfrom(int socket, void *restrict buffer,
3280 // size_t length,
3281 // int flags, struct sockaddr *restrict address,
3282 // socklen_t *restrict address_len);
3283 Signature(ArgTypes{IntTy, VoidPtrRestrictTy, SizeTyCanonTy, IntTy,
3284 StructSockaddrPtrRestrictTy,
3285 Socklen_tPtrRestrictTy},
3286 RetType{Ssize_tTy}),
3287 Recvfrom))
3288 addToFunctionSummaryMap(
3289 "recvfrom",
3290 Signature(ArgTypes{IntTy, VoidPtrRestrictTy, SizeTyCanonTy, IntTy,
3291 Irrelevant, Socklen_tPtrRestrictTy},
3292 RetType{Ssize_tTy}),
3293 Recvfrom);
3294
3295 auto Sendto =
3296 Summary(NoEvalCall)
3297 .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)),
3298 ReturnValueCondition(WithinRange, Range(1, Ssize_tMax))},
3299 ErrnoMustNotBeChecked, GenericSuccessMsg)
3300 .Case({ReturnValueCondition(WithinRange, SingleValue(0)),
3301 ArgumentCondition(2, WithinRange, SingleValue(0))},
3302 ErrnoMustNotBeChecked, GenericSuccessMsg)
3303 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3304 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
3305 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
3306 /*BufSize=*/ArgNo(2)));
3307 if (!addToFunctionSummaryMap(
3308 "sendto",
3309 // ssize_t sendto(int socket, const void *message, size_t length,
3310 // int flags, const struct sockaddr *dest_addr,
3311 // socklen_t dest_len);
3312 Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTyCanonTy, IntTy,
3313 ConstStructSockaddrPtrTy, Socklen_tTy},
3314 RetType{Ssize_tTy}),
3315 Sendto))
3316 addToFunctionSummaryMap(
3317 "sendto",
3318 Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTyCanonTy, IntTy,
3319 Irrelevant, Socklen_tTy},
3320 RetType{Ssize_tTy}),
3321 Sendto);
3322
3323 // int listen(int sockfd, int backlog);
3324 addToFunctionSummaryMap(
3325 "listen", Signature(ArgTypes{IntTy, IntTy}, RetType{IntTy}),
3326 Summary(NoEvalCall)
3327 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3328 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3329 .ArgConstraint(
3330 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
3331
3332 // ssize_t recv(int sockfd, void *buf, size_t len, int flags);
3333 addToFunctionSummaryMap(
3334 "recv",
3335 Signature(ArgTypes{IntTy, VoidPtrTy, SizeTyCanonTy, IntTy},
3336 RetType{Ssize_tTy}),
3337 Summary(NoEvalCall)
3338 .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)),
3339 ReturnValueCondition(WithinRange, Range(1, Ssize_tMax))},
3340 ErrnoMustNotBeChecked, GenericSuccessMsg)
3341 .Case({ReturnValueCondition(WithinRange, SingleValue(0)),
3342 ArgumentCondition(2, WithinRange, SingleValue(0))},
3343 ErrnoMustNotBeChecked, GenericSuccessMsg)
3344 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3345 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
3346 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
3347 /*BufSize=*/ArgNo(2))));
3348
3349 std::optional<QualType> StructMsghdrTy = lookupTy("msghdr");
3350 std::optional<QualType> StructMsghdrPtrTy = getPointerTy(StructMsghdrTy);
3351 std::optional<QualType> ConstStructMsghdrPtrTy =
3352 getPointerTy(getConstTy(StructMsghdrTy));
3353
3354 // ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);
3355 addToFunctionSummaryMap(
3356 "recvmsg",
3357 Signature(ArgTypes{IntTy, StructMsghdrPtrTy, IntTy},
3358 RetType{Ssize_tTy}),
3359 Summary(NoEvalCall)
3360 .Case({ReturnValueCondition(WithinRange, Range(1, Ssize_tMax))},
3361 ErrnoMustNotBeChecked, GenericSuccessMsg)
3362 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3363 .ArgConstraint(
3364 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
3365
3366 // ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
3367 addToFunctionSummaryMap(
3368 "sendmsg",
3369 Signature(ArgTypes{IntTy, ConstStructMsghdrPtrTy, IntTy},
3370 RetType{Ssize_tTy}),
3371 Summary(NoEvalCall)
3372 .Case({ReturnValueCondition(WithinRange, Range(1, Ssize_tMax))},
3373 ErrnoMustNotBeChecked, GenericSuccessMsg)
3374 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3375 .ArgConstraint(
3376 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
3377
3378 // int setsockopt(int socket, int level, int option_name,
3379 // const void *option_value, socklen_t option_len);
3380 addToFunctionSummaryMap(
3381 "setsockopt",
3382 Signature(ArgTypes{IntTy, IntTy, IntTy, ConstVoidPtrTy, Socklen_tTy},
3383 RetType{IntTy}),
3384 Summary(NoEvalCall)
3385 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3386 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3387 .ArgConstraint(NotNullBuffer(ArgNo(3), ArgNo(4)))
3388 .ArgConstraint(
3389 BufferSize(/*Buffer=*/ArgNo(3), /*BufSize=*/ArgNo(4)))
3390 .ArgConstraint(
3391 ArgumentCondition(4, WithinRange, Range(0, Socklen_tMax))));
3392
3393 // int getsockopt(int socket, int level, int option_name,
3394 // void *restrict option_value,
3395 // socklen_t *restrict option_len);
3396 addToFunctionSummaryMap(
3397 "getsockopt",
3398 Signature(ArgTypes{IntTy, IntTy, IntTy, VoidPtrRestrictTy,
3399 Socklen_tPtrRestrictTy},
3400 RetType{IntTy}),
3401 Summary(NoEvalCall)
3402 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3403 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3404 .ArgConstraint(NotNull(ArgNo(3)))
3405 .ArgConstraint(NotNull(ArgNo(4))));
3406
3407 // ssize_t send(int sockfd, const void *buf, size_t len, int flags);
3408 addToFunctionSummaryMap(
3409 "send",
3410 Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTyCanonTy, IntTy},
3411 RetType{Ssize_tTy}),
3412 Summary(NoEvalCall)
3413 .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)),
3414 ReturnValueCondition(WithinRange, Range(1, Ssize_tMax))},
3415 ErrnoMustNotBeChecked, GenericSuccessMsg)
3416 .Case({ReturnValueCondition(WithinRange, SingleValue(0)),
3417 ArgumentCondition(2, WithinRange, SingleValue(0))},
3418 ErrnoMustNotBeChecked, GenericSuccessMsg)
3419 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3420 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
3421 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
3422 /*BufSize=*/ArgNo(2))));
3423
3424 // int socketpair(int domain, int type, int protocol, int sv[2]);
3425 addToFunctionSummaryMap(
3426 "socketpair",
3427 Signature(ArgTypes{IntTy, IntTy, IntTy, IntPtrTy}, RetType{IntTy}),
3428 Summary(NoEvalCall)
3429 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3430 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3431 .ArgConstraint(NotNull(ArgNo(3))));
3432
3433 // int shutdown(int socket, int how);
3434 addToFunctionSummaryMap(
3435 "shutdown", Signature(ArgTypes{IntTy, IntTy}, RetType{IntTy}),
3436 Summary(NoEvalCall)
3437 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3438 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3439 .ArgConstraint(
3440 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
3441
3442 // int getnameinfo(const struct sockaddr *restrict sa, socklen_t salen,
3443 // char *restrict node, socklen_t nodelen,
3444 // char *restrict service,
3445 // socklen_t servicelen, int flags);
3446 //
3447 // This is defined in netdb.h. And contrary to 'socket.h', the sockaddr
3448 // parameter is never handled as a transparent union in netdb.h
3449 addToFunctionSummaryMap(
3450 "getnameinfo",
3451 Signature(ArgTypes{ConstStructSockaddrPtrRestrictTy, Socklen_tTy,
3452 CharPtrRestrictTy, Socklen_tTy, CharPtrRestrictTy,
3453 Socklen_tTy, IntTy},
3454 RetType{IntTy}),
3455 Summary(NoEvalCall)
3456 .ArgConstraint(
3457 BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1)))
3458 .ArgConstraint(
3459 ArgumentCondition(1, WithinRange, Range(0, Socklen_tMax)))
3460 .ArgConstraint(
3461 BufferSize(/*Buffer=*/ArgNo(2), /*BufSize=*/ArgNo(3)))
3462 .ArgConstraint(
3463 ArgumentCondition(3, WithinRange, Range(0, Socklen_tMax)))
3464 .ArgConstraint(
3465 BufferSize(/*Buffer=*/ArgNo(4), /*BufSize=*/ArgNo(5)))
3466 .ArgConstraint(
3467 ArgumentCondition(5, WithinRange, Range(0, Socklen_tMax))));
3468
3469 std::optional<QualType> StructUtimbufTy = lookupTy("utimbuf");
3470 std::optional<QualType> StructUtimbufPtrTy = getPointerTy(StructUtimbufTy);
3471
3472 // int utime(const char *filename, struct utimbuf *buf);
3473 addToFunctionSummaryMap(
3474 "utime",
3475 Signature(ArgTypes{ConstCharPtrTy, StructUtimbufPtrTy}, RetType{IntTy}),
3476 Summary(NoEvalCall)
3477 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3478 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3479 .ArgConstraint(NotNull(ArgNo(0))));
3480
3481 std::optional<QualType> StructTimespecTy = lookupTy("timespec");
3482 std::optional<QualType> StructTimespecPtrTy =
3483 getPointerTy(StructTimespecTy);
3484 std::optional<QualType> ConstStructTimespecPtrTy =
3485 getPointerTy(getConstTy(StructTimespecTy));
3486
3487 // int futimens(int fd, const struct timespec times[2]);
3488 addToFunctionSummaryMap(
3489 "futimens",
3490 Signature(ArgTypes{IntTy, ConstStructTimespecPtrTy}, RetType{IntTy}),
3491 Summary(NoEvalCall)
3492 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3493 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3494 .ArgConstraint(
3495 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
3496
3497 // int utimensat(int dirfd, const char *pathname,
3498 // const struct timespec times[2], int flags);
3499 addToFunctionSummaryMap(
3500 "utimensat",
3501 Signature(
3502 ArgTypes{IntTy, ConstCharPtrTy, ConstStructTimespecPtrTy, IntTy},
3503 RetType{IntTy}),
3504 Summary(NoEvalCall)
3505 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3506 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3507 .ArgConstraint(NotNull(ArgNo(1))));
3508
3509 std::optional<QualType> StructTimevalTy = lookupTy("timeval");
3510 std::optional<QualType> ConstStructTimevalPtrTy =
3511 getPointerTy(getConstTy(StructTimevalTy));
3512
3513 // int utimes(const char *filename, const struct timeval times[2]);
3514 addToFunctionSummaryMap(
3515 "utimes",
3516 Signature(ArgTypes{ConstCharPtrTy, ConstStructTimevalPtrTy},
3517 RetType{IntTy}),
3518 Summary(NoEvalCall)
3519 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3520 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3521 .ArgConstraint(NotNull(ArgNo(0))));
3522
3523 // int nanosleep(const struct timespec *rqtp, struct timespec *rmtp);
3524 addToFunctionSummaryMap(
3525 "nanosleep",
3526 Signature(ArgTypes{ConstStructTimespecPtrTy, StructTimespecPtrTy},
3527 RetType{IntTy}),
3528 Summary(NoEvalCall)
3529 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3530 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3531 .ArgConstraint(NotNull(ArgNo(0))));
3532
3533 std::optional<QualType> Time_tTy = lookupTy("time_t");
3534 std::optional<QualType> ConstTime_tPtrTy =
3535 getPointerTy(getConstTy(Time_tTy));
3536 std::optional<QualType> ConstTime_tPtrRestrictTy =
3537 getRestrictTy(ConstTime_tPtrTy);
3538
3539 std::optional<QualType> StructTmTy = lookupTy("tm");
3540 std::optional<QualType> StructTmPtrTy = getPointerTy(StructTmTy);
3541 std::optional<QualType> StructTmPtrRestrictTy =
3542 getRestrictTy(StructTmPtrTy);
3543 std::optional<QualType> ConstStructTmPtrTy =
3544 getPointerTy(getConstTy(StructTmTy));
3545 std::optional<QualType> ConstStructTmPtrRestrictTy =
3546 getRestrictTy(ConstStructTmPtrTy);
3547
3548 // struct tm * localtime(const time_t *tp);
3549 addToFunctionSummaryMap(
3550 "localtime",
3551 Signature(ArgTypes{ConstTime_tPtrTy}, RetType{StructTmPtrTy}),
3552 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
3553
3554 // struct tm *localtime_r(const time_t *restrict timer,
3555 // struct tm *restrict result);
3556 addToFunctionSummaryMap(
3557 "localtime_r",
3558 Signature(ArgTypes{ConstTime_tPtrRestrictTy, StructTmPtrRestrictTy},
3559 RetType{StructTmPtrTy}),
3560 Summary(NoEvalCall)
3561 .ArgConstraint(NotNull(ArgNo(0)))
3562 .ArgConstraint(NotNull(ArgNo(1))));
3563
3564 // char *asctime_r(const struct tm *restrict tm, char *restrict buf);
3565 addToFunctionSummaryMap(
3566 "asctime_r",
3567 Signature(ArgTypes{ConstStructTmPtrRestrictTy, CharPtrRestrictTy},
3568 RetType{CharPtrTy}),
3569 Summary(NoEvalCall)
3570 .ArgConstraint(NotNull(ArgNo(0)))
3571 .ArgConstraint(NotNull(ArgNo(1)))
3572 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
3573 /*MinBufSize=*/BVF.getValue(26, IntTy))));
3574
3575 // char *ctime_r(const time_t *timep, char *buf);
3576 addToFunctionSummaryMap(
3577 "ctime_r",
3578 Signature(ArgTypes{ConstTime_tPtrTy, CharPtrTy}, RetType{CharPtrTy}),
3579 Summary(NoEvalCall)
3580 .ArgConstraint(NotNull(ArgNo(0)))
3581 .ArgConstraint(NotNull(ArgNo(1)))
3582 .ArgConstraint(BufferSize(
3583 /*Buffer=*/ArgNo(1),
3584 /*MinBufSize=*/BVF.getValue(26, IntTy))));
3585
3586 // struct tm *gmtime_r(const time_t *restrict timer,
3587 // struct tm *restrict result);
3588 addToFunctionSummaryMap(
3589 "gmtime_r",
3590 Signature(ArgTypes{ConstTime_tPtrRestrictTy, StructTmPtrRestrictTy},
3591 RetType{StructTmPtrTy}),
3592 Summary(NoEvalCall)
3593 .ArgConstraint(NotNull(ArgNo(0)))
3594 .ArgConstraint(NotNull(ArgNo(1))));
3595
3596 // struct tm * gmtime(const time_t *tp);
3597 addToFunctionSummaryMap(
3598 "gmtime", Signature(ArgTypes{ConstTime_tPtrTy}, RetType{StructTmPtrTy}),
3599 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
3600
3601 std::optional<QualType> Clockid_tTy = lookupTy("clockid_t");
3602
3603 // int clock_gettime(clockid_t clock_id, struct timespec *tp);
3604 addToFunctionSummaryMap(
3605 "clock_gettime",
3606 Signature(ArgTypes{Clockid_tTy, StructTimespecPtrTy}, RetType{IntTy}),
3607 Summary(NoEvalCall)
3608 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3609 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3610 .ArgConstraint(NotNull(ArgNo(1))));
3611
3612 std::optional<QualType> StructItimervalTy = lookupTy("itimerval");
3613 std::optional<QualType> StructItimervalPtrTy =
3614 getPointerTy(StructItimervalTy);
3615
3616 // int getitimer(int which, struct itimerval *curr_value);
3617 addToFunctionSummaryMap(
3618 "getitimer",
3619 Signature(ArgTypes{IntTy, StructItimervalPtrTy}, RetType{IntTy}),
3620 Summary(NoEvalCall)
3621 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3622 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3623 .ArgConstraint(NotNull(ArgNo(1))));
3624
3625 std::optional<QualType> Pthread_cond_tTy = lookupTy("pthread_cond_t");
3626 std::optional<QualType> Pthread_cond_tPtrTy =
3627 getPointerTy(Pthread_cond_tTy);
3628 std::optional<QualType> Pthread_tTy = lookupTy("pthread_t");
3629 std::optional<QualType> Pthread_tPtrTy = getPointerTy(Pthread_tTy);
3630 std::optional<QualType> Pthread_tPtrRestrictTy =
3631 getRestrictTy(Pthread_tPtrTy);
3632 std::optional<QualType> Pthread_mutex_tTy = lookupTy("pthread_mutex_t");
3633 std::optional<QualType> Pthread_mutex_tPtrTy =
3634 getPointerTy(Pthread_mutex_tTy);
3635 std::optional<QualType> Pthread_mutex_tPtrRestrictTy =
3636 getRestrictTy(Pthread_mutex_tPtrTy);
3637 std::optional<QualType> Pthread_attr_tTy = lookupTy("pthread_attr_t");
3638 std::optional<QualType> Pthread_attr_tPtrTy =
3639 getPointerTy(Pthread_attr_tTy);
3640 std::optional<QualType> ConstPthread_attr_tPtrTy =
3641 getPointerTy(getConstTy(Pthread_attr_tTy));
3642 std::optional<QualType> ConstPthread_attr_tPtrRestrictTy =
3643 getRestrictTy(ConstPthread_attr_tPtrTy);
3644 std::optional<QualType> Pthread_mutexattr_tTy =
3645 lookupTy("pthread_mutexattr_t");
3646 std::optional<QualType> ConstPthread_mutexattr_tPtrTy =
3647 getPointerTy(getConstTy(Pthread_mutexattr_tTy));
3648 std::optional<QualType> ConstPthread_mutexattr_tPtrRestrictTy =
3649 getRestrictTy(ConstPthread_mutexattr_tPtrTy);
3650
3651 QualType PthreadStartRoutineTy = getPointerTy(
3652 ACtx.getFunctionType(/*ResultTy=*/VoidPtrTy, /*Args=*/VoidPtrTy,
3653 FunctionProtoType::ExtProtoInfo()));
3654
3655 // int pthread_cond_signal(pthread_cond_t *cond);
3656 // int pthread_cond_broadcast(pthread_cond_t *cond);
3657 addToFunctionSummaryMap(
3658 {"pthread_cond_signal", "pthread_cond_broadcast"},
3659 Signature(ArgTypes{Pthread_cond_tPtrTy}, RetType{IntTy}),
3660 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
3661
3662 // int pthread_create(pthread_t *restrict thread,
3663 // const pthread_attr_t *restrict attr,
3664 // void *(*start_routine)(void*), void *restrict arg);
3665 addToFunctionSummaryMap(
3666 "pthread_create",
3667 Signature(ArgTypes{Pthread_tPtrRestrictTy,
3668 ConstPthread_attr_tPtrRestrictTy,
3669 PthreadStartRoutineTy, VoidPtrRestrictTy},
3670 RetType{IntTy}),
3671 Summary(NoEvalCall)
3672 .ArgConstraint(NotNull(ArgNo(0)))
3673 .ArgConstraint(NotNull(ArgNo(2))));
3674
3675 // int pthread_attr_destroy(pthread_attr_t *attr);
3676 // int pthread_attr_init(pthread_attr_t *attr);
3677 addToFunctionSummaryMap(
3678 {"pthread_attr_destroy", "pthread_attr_init"},
3679 Signature(ArgTypes{Pthread_attr_tPtrTy}, RetType{IntTy}),
3680 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
3681
3682 // int pthread_attr_getstacksize(const pthread_attr_t *restrict attr,
3683 // size_t *restrict stacksize);
3684 // int pthread_attr_getguardsize(const pthread_attr_t *restrict attr,
3685 // size_t *restrict guardsize);
3686 addToFunctionSummaryMap(
3687 {"pthread_attr_getstacksize", "pthread_attr_getguardsize"},
3688 Signature(ArgTypes{ConstPthread_attr_tPtrRestrictTy, SizePtrRestrictTy},
3689 RetType{IntTy}),
3690 Summary(NoEvalCall)
3691 .ArgConstraint(NotNull(ArgNo(0)))
3692 .ArgConstraint(NotNull(ArgNo(1))));
3693
3694 // int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize);
3695 // int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize);
3696 addToFunctionSummaryMap(
3697 {"pthread_attr_setstacksize", "pthread_attr_setguardsize"},
3698 Signature(ArgTypes{Pthread_attr_tPtrTy, SizeTyCanonTy}, RetType{IntTy}),
3699 Summary(NoEvalCall)
3700 .ArgConstraint(NotNull(ArgNo(0)))
3701 .ArgConstraint(
3702 ArgumentCondition(1, WithinRange, Range(0, SizeMax))));
3703
3704 // int pthread_mutex_init(pthread_mutex_t *restrict mutex, const
3705 // pthread_mutexattr_t *restrict attr);
3706 addToFunctionSummaryMap(
3707 "pthread_mutex_init",
3708 Signature(ArgTypes{Pthread_mutex_tPtrRestrictTy,
3709 ConstPthread_mutexattr_tPtrRestrictTy},
3710 RetType{IntTy}),
3711 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
3712
3713 // int pthread_mutex_destroy(pthread_mutex_t *mutex);
3714 // int pthread_mutex_lock(pthread_mutex_t *mutex);
3715 // int pthread_mutex_trylock(pthread_mutex_t *mutex);
3716 // int pthread_mutex_unlock(pthread_mutex_t *mutex);
3717 addToFunctionSummaryMap(
3718 {"pthread_mutex_destroy", "pthread_mutex_lock", "pthread_mutex_trylock",
3719 "pthread_mutex_unlock"},
3720 Signature(ArgTypes{Pthread_mutex_tPtrTy}, RetType{IntTy}),
3721 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
3722 }
3723
3724 // Functions for testing.
3725 if (AddTestFunctions) {
3726 const RangeInt IntMin = BVF.getMinValue(IntTy)->getLimitedValue();
3727
3728 addToFunctionSummaryMap(
3729 "__not_null", Signature(ArgTypes{IntPtrTy}, RetType{IntTy}),
3730 Summary(EvalCallAsPure).ArgConstraint(NotNull(ArgNo(0))));
3731
3732 addToFunctionSummaryMap(
3733 "__not_null_buffer",
3734 Signature(ArgTypes{VoidPtrTy, IntTy, IntTy}, RetType{IntTy}),
3735 Summary(EvalCallAsPure)
3736 .ArgConstraint(NotNullBuffer(ArgNo(0), ArgNo(1), ArgNo(2))));
3737
3738 // Test inside range constraints.
3739 addToFunctionSummaryMap(
3740 "__single_val_0", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3741 Summary(EvalCallAsPure)
3742 .ArgConstraint(ArgumentCondition(0U, WithinRange, SingleValue(0))));
3743 addToFunctionSummaryMap(
3744 "__single_val_1", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3745 Summary(EvalCallAsPure)
3746 .ArgConstraint(ArgumentCondition(0U, WithinRange, SingleValue(1))));
3747 addToFunctionSummaryMap(
3748 "__range_1_2", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3749 Summary(EvalCallAsPure)
3750 .ArgConstraint(ArgumentCondition(0U, WithinRange, Range(1, 2))));
3751 addToFunctionSummaryMap(
3752 "__range_m1_1", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3753 Summary(EvalCallAsPure)
3754 .ArgConstraint(ArgumentCondition(0U, WithinRange, Range(-1, 1))));
3755 addToFunctionSummaryMap(
3756 "__range_m2_m1", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3757 Summary(EvalCallAsPure)
3758 .ArgConstraint(ArgumentCondition(0U, WithinRange, Range(-2, -1))));
3759 addToFunctionSummaryMap(
3760 "__range_m10_10", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3761 Summary(EvalCallAsPure)
3762 .ArgConstraint(ArgumentCondition(0U, WithinRange, Range(-10, 10))));
3763 addToFunctionSummaryMap("__range_m1_inf",
3764 Signature(ArgTypes{IntTy}, RetType{IntTy}),
3765 Summary(EvalCallAsPure)
3766 .ArgConstraint(ArgumentCondition(
3767 0U, WithinRange, Range(-1, IntMax))));
3768 addToFunctionSummaryMap("__range_0_inf",
3769 Signature(ArgTypes{IntTy}, RetType{IntTy}),
3770 Summary(EvalCallAsPure)
3771 .ArgConstraint(ArgumentCondition(
3772 0U, WithinRange, Range(0, IntMax))));
3773 addToFunctionSummaryMap("__range_1_inf",
3774 Signature(ArgTypes{IntTy}, RetType{IntTy}),
3775 Summary(EvalCallAsPure)
3776 .ArgConstraint(ArgumentCondition(
3777 0U, WithinRange, Range(1, IntMax))));
3778 addToFunctionSummaryMap("__range_minf_m1",
3779 Signature(ArgTypes{IntTy}, RetType{IntTy}),
3780 Summary(EvalCallAsPure)
3781 .ArgConstraint(ArgumentCondition(
3782 0U, WithinRange, Range(IntMin, -1))));
3783 addToFunctionSummaryMap("__range_minf_0",
3784 Signature(ArgTypes{IntTy}, RetType{IntTy}),
3785 Summary(EvalCallAsPure)
3786 .ArgConstraint(ArgumentCondition(
3787 0U, WithinRange, Range(IntMin, 0))));
3788 addToFunctionSummaryMap("__range_minf_1",
3789 Signature(ArgTypes{IntTy}, RetType{IntTy}),
3790 Summary(EvalCallAsPure)
3791 .ArgConstraint(ArgumentCondition(
3792 0U, WithinRange, Range(IntMin, 1))));
3793 addToFunctionSummaryMap("__range_1_2__4_6",
3794 Signature(ArgTypes{IntTy}, RetType{IntTy}),
3795 Summary(EvalCallAsPure)
3796 .ArgConstraint(ArgumentCondition(
3797 0U, WithinRange, Range({1, 2}, {4, 6}))));
3798 addToFunctionSummaryMap(
3799 "__range_1_2__4_inf", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3800 Summary(EvalCallAsPure)
3801 .ArgConstraint(ArgumentCondition(0U, WithinRange,
3802 Range({1, 2}, {4, IntMax}))));
3803
3804 // Test out of range constraints.
3805 addToFunctionSummaryMap(
3806 "__single_val_out_0", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3807 Summary(EvalCallAsPure)
3808 .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(0))));
3809 addToFunctionSummaryMap(
3810 "__single_val_out_1", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3811 Summary(EvalCallAsPure)
3812 .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(1))));
3813 addToFunctionSummaryMap(
3814 "__range_out_1_2", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3815 Summary(EvalCallAsPure)
3816 .ArgConstraint(ArgumentCondition(0U, OutOfRange, Range(1, 2))));
3817 addToFunctionSummaryMap(
3818 "__range_out_m1_1", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3819 Summary(EvalCallAsPure)
3820 .ArgConstraint(ArgumentCondition(0U, OutOfRange, Range(-1, 1))));
3821 addToFunctionSummaryMap(
3822 "__range_out_m2_m1", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3823 Summary(EvalCallAsPure)
3824 .ArgConstraint(ArgumentCondition(0U, OutOfRange, Range(-2, -1))));
3825 addToFunctionSummaryMap(
3826 "__range_out_m10_10", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3827 Summary(EvalCallAsPure)
3828 .ArgConstraint(ArgumentCondition(0U, OutOfRange, Range(-10, 10))));
3829 addToFunctionSummaryMap("__range_out_m1_inf",
3830 Signature(ArgTypes{IntTy}, RetType{IntTy}),
3831 Summary(EvalCallAsPure)
3832 .ArgConstraint(ArgumentCondition(
3833 0U, OutOfRange, Range(-1, IntMax))));
3834 addToFunctionSummaryMap("__range_out_0_inf",
3835 Signature(ArgTypes{IntTy}, RetType{IntTy}),
3836 Summary(EvalCallAsPure)
3837 .ArgConstraint(ArgumentCondition(
3838 0U, OutOfRange, Range(0, IntMax))));
3839 addToFunctionSummaryMap("__range_out_1_inf",
3840 Signature(ArgTypes{IntTy}, RetType{IntTy}),
3841 Summary(EvalCallAsPure)
3842 .ArgConstraint(ArgumentCondition(
3843 0U, OutOfRange, Range(1, IntMax))));
3844 addToFunctionSummaryMap("__range_out_minf_m1",
3845 Signature(ArgTypes{IntTy}, RetType{IntTy}),
3846 Summary(EvalCallAsPure)
3847 .ArgConstraint(ArgumentCondition(
3848 0U, OutOfRange, Range(IntMin, -1))));
3849 addToFunctionSummaryMap("__range_out_minf_0",
3850 Signature(ArgTypes{IntTy}, RetType{IntTy}),
3851 Summary(EvalCallAsPure)
3852 .ArgConstraint(ArgumentCondition(
3853 0U, OutOfRange, Range(IntMin, 0))));
3854 addToFunctionSummaryMap("__range_out_minf_1",
3855 Signature(ArgTypes{IntTy}, RetType{IntTy}),
3856 Summary(EvalCallAsPure)
3857 .ArgConstraint(ArgumentCondition(
3858 0U, OutOfRange, Range(IntMin, 1))));
3859 addToFunctionSummaryMap("__range_out_1_2__4_6",
3860 Signature(ArgTypes{IntTy}, RetType{IntTy}),
3861 Summary(EvalCallAsPure)
3862 .ArgConstraint(ArgumentCondition(
3863 0U, OutOfRange, Range({1, 2}, {4, 6}))));
3864 addToFunctionSummaryMap(
3865 "__range_out_1_2__4_inf", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3866 Summary(EvalCallAsPure)
3867 .ArgConstraint(
3868 ArgumentCondition(0U, OutOfRange, Range({1, 2}, {4, IntMax}))));
3869
3870 // Test range kind.
3871 addToFunctionSummaryMap(
3872 "__within", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3873 Summary(EvalCallAsPure)
3874 .ArgConstraint(ArgumentCondition(0U, WithinRange, SingleValue(1))));
3875 addToFunctionSummaryMap(
3876 "__out_of", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3877 Summary(EvalCallAsPure)
3878 .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(1))));
3879
3880 addToFunctionSummaryMap(
3881 "__two_constrained_args",
3882 Signature(ArgTypes{IntTy, IntTy}, RetType{IntTy}),
3883 Summary(EvalCallAsPure)
3884 .ArgConstraint(ArgumentCondition(0U, WithinRange, SingleValue(1)))
3885 .ArgConstraint(ArgumentCondition(1U, WithinRange, SingleValue(1))));
3886 addToFunctionSummaryMap(
3887 "__arg_constrained_twice", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3888 Summary(EvalCallAsPure)
3889 .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(1)))
3890 .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(2))));
3891 addToFunctionSummaryMap(
3892 "__defaultparam",
3893 Signature(ArgTypes{Irrelevant, IntTy}, RetType{IntTy}),
3894 Summary(EvalCallAsPure).ArgConstraint(NotNull(ArgNo(0))));
3895 addToFunctionSummaryMap(
3896 "__variadic",
3897 Signature(ArgTypes{VoidPtrTy, ConstCharPtrTy}, RetType{IntTy}),
3898 Summary(EvalCallAsPure)
3899 .ArgConstraint(NotNull(ArgNo(0)))
3900 .ArgConstraint(NotNull(ArgNo(1))));
3901 addToFunctionSummaryMap(
3902 "__buf_size_arg_constraint",
3903 Signature(ArgTypes{ConstVoidPtrTy, SizeTyCanonTy}, RetType{IntTy}),
3904 Summary(EvalCallAsPure)
3905 .ArgConstraint(
3906 BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1))));
3907 addToFunctionSummaryMap(
3908 "__buf_size_arg_constraint_mul",
3909 Signature(ArgTypes{ConstVoidPtrTy, SizeTyCanonTy, SizeTyCanonTy},
3910 RetType{IntTy}),
3911 Summary(EvalCallAsPure)
3912 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1),
3913 /*BufSizeMultiplier=*/ArgNo(2))));
3914 addToFunctionSummaryMap(
3915 "__buf_size_arg_constraint_concrete",
3916 Signature(ArgTypes{ConstVoidPtrTy}, RetType{IntTy}),
3917 Summary(EvalCallAsPure)
3918 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(0),
3919 /*BufSize=*/BVF.getValue(10, IntTy))));
3920 addToFunctionSummaryMap(
3921 {"__test_restrict_param_0", "__test_restrict_param_1",
3922 "__test_restrict_param_2"},
3923 Signature(ArgTypes{VoidPtrRestrictTy}, RetType{VoidTy}),
3924 Summary(EvalCallAsPure));
3925
3926 // Test the application of cases.
3927 addToFunctionSummaryMap(
3928 "__test_case_note", Signature(ArgTypes{}, RetType{IntTy}),
3929 Summary(EvalCallAsPure)
3930 .Case({ReturnValueCondition(WithinRange, SingleValue(0))},
3931 ErrnoIrrelevant, "Function returns 0")
3932 .Case({ReturnValueCondition(WithinRange, SingleValue(1))},
3933 ErrnoIrrelevant, "Function returns 1"));
3934 addToFunctionSummaryMap(
3935 "__test_case_range_1_2__4_6",
3936 Signature(ArgTypes{IntTy}, RetType{IntTy}),
3937 Summary(EvalCallAsPure)
3938 .Case({ArgumentCondition(0U, WithinRange,
3939 IntRangeVector{{IntMin, 0}, {3, 3}}),
3940 ReturnValueCondition(WithinRange, SingleValue(1))},
3941 ErrnoIrrelevant)
3942 .Case({ArgumentCondition(0U, WithinRange,
3943 IntRangeVector{{3, 3}, {7, IntMax}}),
3944 ReturnValueCondition(WithinRange, SingleValue(2))},
3945 ErrnoIrrelevant)
3946 .Case({ArgumentCondition(0U, WithinRange,
3947 IntRangeVector{{IntMin, 0}, {7, IntMax}}),
3948 ReturnValueCondition(WithinRange, SingleValue(3))},
3949 ErrnoIrrelevant)
3950 .Case({ArgumentCondition(
3951 0U, WithinRange,
3952 IntRangeVector{{IntMin, 0}, {3, 3}, {7, IntMax}}),
3953 ReturnValueCondition(WithinRange, SingleValue(4))},
3954 ErrnoIrrelevant));
3955 }
3956}
3957
3958void ento::registerStdCLibraryFunctionsChecker(CheckerManager &mgr) {
3959 auto *Checker = mgr.registerChecker<StdLibraryFunctionsChecker>();
3960 Checker->CheckName = mgr.getCurrentCheckerName();
3961 const AnalyzerOptions &Opts = mgr.getAnalyzerOptions();
3962 Checker->DisplayLoadedSummaries =
3963 Opts.getCheckerBooleanOption(Checker, "DisplayLoadedSummaries");
3964 Checker->ModelPOSIX = Opts.getCheckerBooleanOption(Checker, "ModelPOSIX");
3965 Checker->ShouldAssumeControlledEnvironment =
3966 Opts.ShouldAssumeControlledEnvironment;
3967}
3968
3969bool ento::shouldRegisterStdCLibraryFunctionsChecker(
3970 const CheckerManager &mgr) {
3971 return true;
3972}
3973
3974void ento::registerStdCLibraryFunctionsTesterChecker(CheckerManager &mgr) {
3975 auto *Checker = mgr.getChecker<StdLibraryFunctionsChecker>();
3976 Checker->AddTestFunctions = true;
3977}
3978
3979bool ento::shouldRegisterStdCLibraryFunctionsTesterChecker(
3980 const CheckerManager &mgr) {
3981 return true;
3982}
#define V(N, I)
static std::string getFunctionName(const CallEvent &Call)
static bool isInvalid(LocType Loc, bool *Invalid)
TranslationUnitDecl * getTranslationUnitDecl() const
CanQualType LongTy
QualType getPointerType(QualType T) const
Return the uniqued reference to the type for a pointer to the specified type.
IdentifierTable & Idents
Definition ASTContext.h:846
const LangOptions & getLangOpts() const
CanQualType getCanonicalSizeType() const
CanQualType BoolTy
QualType getRestrictType(QualType T) const
Return the uniqued reference to the type for a restrict qualified type.
CanQualType CharTy
CanQualType IntTy
CanQualType getCanonicalTypeDeclType(const TypeDecl *TD) const
CanQualType VoidTy
CanQualType UnsignedCharTy
CanQualType UnsignedIntTy
QualType getFunctionType(QualType ResultTy, ArrayRef< QualType > Args, const FunctionProtoType::ExtProtoInfo &EPI) const
Return a normal function type with a typed argument list.
const TargetInfo & getTargetInfo() const
Definition ASTContext.h:965
CanQualType WCharTy
static Opcode negateComparisonOp(Opcode Opc)
Definition Expr.h:4188
BinaryOperatorKind Opcode
Definition Expr.h:4087
lookup_result lookup(DeclarationName Name) const
lookup - Find the declarations (if any) with the given Name in this context.
ASTContext & getASTContext() const LLVM_READONLY
Definition DeclBase.cpp:550
void print(raw_ostream &Out, unsigned Indentation=0, bool PrintInstantiation=false) const
const ParmVarDecl * getParamDecl(unsigned i) const
Definition Decl.h:2928
QualType getReturnType() const
Definition Decl.h:2976
FunctionDecl * getCanonicalDecl() override
Retrieves the "canonical" declaration of the given declaration.
Definition Decl.cpp:3791
unsigned getNumParams() const
Return the number of parameters this function must have based on its FunctionType.
Definition Decl.cpp:3870
size_t param_size() const
Definition Decl.h:2921
IdentifierInfo & get(StringRef Name)
Return the identifier token info for the specified named identifier.
QualType withConst() const
Definition TypeBase.h:1175
QualType getCanonicalType() const
Definition TypeBase.h:8510
const llvm::Triple & getTriple() const
Returns the target triple of the primary target.
bool isVoidType() const
Definition TypeBase.h:9067
QualType getType() const
Definition Decl.h:724
APSIntPtr getMaxValue(const llvm::APSInt &v)
APSIntPtr getMinValue(const llvm::APSInt &v)
const AnalyzerOptions & getAnalyzerOptions() const
CHECKER * registerChecker(AT &&...Args)
Register a single-part checker (derived from Checker): construct its singleton instance,...
CheckerNameRef getCurrentCheckerName() const
CHECKER * getChecker(AT &&...Args)
If the the singleton instance of a checker class is not yet constructed, then construct it (with the ...
Simple checker classes that implement one frontend (i.e.
Definition Checker.h:565
ProgramStateRef assumeInclusiveRange(ProgramStateRef State, NonLoc Value, const llvm::APSInt &From, const llvm::APSInt &To, bool InBound)
const ProgramStateRef & getState() const
unsigned succ_size() const
const ExplodedNode * getErrorNode() const
bool isInteresting(SymbolRef sym) const
ConstraintManager & getConstraintManager()
BasicValueFactory & getBasicValueFactory()
ASTContext & getContext()
nonloc::ConcreteInt makeIntVal(const IntegerLiteral *integer)
SVal evalCast(SVal V, QualType CastTy, QualType OriginalTy)
Cast a given SVal to another SVal using given QualType's.
QualType getConditionType() const
SVal evalBinOp(ProgramStateRef state, BinaryOperator::Opcode op, SVal lhs, SVal rhs, QualType type)
DefinedOrUnknownSVal conjureSymbolVal(const void *symbolTag, ConstCFGElementRef elem, const StackFrame *SF, unsigned count)
Create a new symbol with a unique 'name'.
std::optional< T > getAs() const
Convert to the specified SVal type, returning std::nullopt if this SVal is not of the desired type.
Definition SVals.h:88
T castAs() const
Convert to the specified SVal type, asserting that this SVal is of the desired type.
Definition SVals.h:84
Defines the clang::TargetInfo interface.
bool trackExpressionValue(const ExplodedNode *N, const Expr *E, PathSensitiveBugReport &R, TrackingOptions Opts={})
Attempts to add visitors to track expression value back to its point of origin.
std::optional< Loc > getErrnoLoc(ProgramStateRef State)
Returns the location that points to the MemoryRegion where the 'errno' value is stored.
ProgramStateRef setErrnoForStdSuccess(ProgramStateRef State, CheckerContext &C)
Set errno state for the common case when a standard function is successful.
ProgramStateRef setErrnoStdMustBeChecked(ProgramStateRef State, CheckerContext &C, ConstCFGElementRef Elem)
Set errno state for the common case when a standard function indicates failure only by errno.
ProgramStateRef setErrnoState(ProgramStateRef State, ErrnoCheckState EState)
Set the errno check state, do not modify the errno value.
ProgramStateRef setErrnoForStdFailure(ProgramStateRef State, CheckerContext &C, NonLoc ErrnoSym)
Set errno state for the common case when a standard function fails.
@ Irrelevant
We do not know anything about 'errno'.
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
SVal getDynamicExtentWithOffset(ProgramStateRef State, SVal BufV)
Get the dynamic extent for a symbolic value that represents a buffer.
@ OS
Indicates that the tracking object is a descendant of a referenced-counted OSObject,...
std::optional< int > tryExpandAsInteger(StringRef Macro, const Preprocessor &PP)
Try to parse the value of a defined preprocessor macro.
PRESERVE_NONE bool Ret(InterpState &S)
Definition Interp.h:288
bool IsNonNull(InterpState &S)
Definition Interp.h:3220
bool matches(const til::SExpr *E1, const til::SExpr *E2)
Stencil describe(llvm::StringRef Id)
Produces a human-readable rendering of the node bound to Id, suitable for diagnostics and debugging.
Top level wrappers for InstallAPI frontend operations.
bool isa(CodeGen::Address addr)
Definition Address.h:330
@ Result
The result type of a method or function.
Definition TypeBase.h:906
const FunctionProtoType * T
U cast(CodeGen::Address addr)
Definition Address.h:327
unsigned long uint64_t
int const char * function
Definition c++config.h:31
__packed_splat4 __packed_splat2 __packed_splat8 __packed_splat4 __packed_splat2 __packed_splat4 __packed_splat2 __packed_splat8 __packed_splat4 uint32_t