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