1//=== StdLibraryFunctionsChecker.cpp - Model standard functions -*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This checker improves modeling of a few simple library functions.
10//
11// This checker provides a specification format - `Summary' - and
12// contains descriptions of some library functions in this format. Each
13// specification contains a list of branches for splitting the program state
14// upon call, and range constraints on argument and return-value symbols that
15// are satisfied on each branch. This spec can be expanded to include more
16// items, like external effects of the function.
17//
18// The main difference between this approach and the body farms technique is
19// in more explicit control over how many branches are produced. For example,
20// consider standard C function `ispunct(int x)', which returns a non-zero value
21// iff `x' is a punctuation character, that is, when `x' is in range
22// ['!', '/'] [':', '@'] U ['[', '\`'] U ['{', '~'].
23// `Summary' provides only two branches for this function. However,
24// any attempt to describe this range with if-statements in the body farm
25// would result in many more branches. Because each branch needs to be analyzed
26// independently, this significantly reduces performance. Additionally,
27// once we consider a branch on which `x' is in range, say, ['!', '/'],
28// we assume that such branch is an important separate path through the program,
29// which may lead to false positives because considering this particular path
30// was not consciously intended, and therefore it might have been unreachable.
31//
32// This checker uses eval::Call for modeling pure functions (functions without
33// side effects), for which their `Summary' is a precise model. This avoids
34// unnecessary invalidation passes. Conflicts with other checkers are unlikely
35// because if the function has no other effects, other checkers would probably
36// never want to improve upon the modeling done by this checker.
37//
38// Non-pure functions, for which only partial improvement over the default
39// behavior is expected, are modeled via check::PostCall, non-intrusively.
40//
41//===----------------------------------------------------------------------===//
42
43#include "ErrnoModeling.h"
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 StdLibraryFunctionsChecker
65 : public Checker<check::PreCall, check::PostCall, eval::Call> {
66
67 class Summary;
68
69 /// Specify how much the analyzer engine should entrust modeling this function
70 /// 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 EvalCallAsPure
77 };
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}} is
97 /// 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, but
102 /// 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] to
116 /// \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] to
121 /// \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 and
129 /// default initializable type (vector needs that). A raw pointer was good,
130 /// however, we cannot default initialize that. unique_ptr makes the Summary
131 /// class non-copyable, therefore not an option. Releasing the copyability
132 /// requirement would render the initialization of the Summary map infeasible.
133 /// Mind that a pointer to a new value constraint is created when the negate
134 /// function is used.
135 using ValueConstraintPtr = std::shared_ptr<ValueConstraint>;
136
137 /// Polymorphic base class that represents a constraint on a given argument
138 /// (or return value) of a function. Derived classes implement different kind
139 /// of constraints, e.g range constraints or correlation between two
140 /// arguments.
141 /// These are used as argument constraints (preconditions) of functions, in
142 /// 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 different
144 /// classes of behavior for a function. In this case no description of the
145 /// 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 null
153 /// 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 the
159 /// 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 summary
166 /// case is applied.
167 /// Description should start with something like "is".
168 Assumption
169 };
170
171 /// Give a description that explains the constraint to the user. Used when
172 /// a bug is reported or when the constraint is applied and displayed as a
173 /// note. The description should not mention the argument (getArgNo).
174 /// See StdLibraryFunctionsChecker::reportBug about how this function is
175 /// 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 argument
180 // constraints, e.g. ComparisonConstraint. In that case we can safely
181 // 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 the
187 /// current ValueConstraint applies to) to the user. This function should be
188 /// 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 to
191 /// make the description more precise. In the most simple case, if the
192 /// 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 is
197 /// 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, ArgN: 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 about
212 /// argument constraint violation. By default it is the argument that is
213 /// constrained, however, in some special cases we need to track other
214 /// arguments as well. E.g. a buffer size might be encoded in another
215 /// 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 the
225 /// specified argument has a mismatch with the given FunctionDecl (e.g. the
226 /// arg number is out-of-range of the function's argument list).
227 /// This condition can indicate if a probably wrong or unexpected function
228 /// 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 of
243 /// the function to check, or a special value to indicate the return value
244 /// of the function.
245 /// Every constraint is assigned to one main argument, even if other
246 /// 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'], ['_', '_']} \endcode
258 /// The intervals are closed intervals that contain one or more values.
259 ///
260 /// The default constructed RangeConstraint has an empty range, applying
261 /// such constraint does not involve any assumptions, thus the State remains
262 /// unchanged. This is meaningful, if the range is dependent on a looked up
263 /// type (e.g. [0, Socklen_tMax]). If the type is not found, then the range
264 /// 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 indicates
268 /// 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 the
275 /// constraint is used. If empty a generated description will be used that
276 /// 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(K: Kind);
302 return std::make_shared<RangeConstraint>(args&: Tmp);
303 }
304
305 protected:
306 bool checkSpecificValidity(const FunctionDecl *FD) const override {
307 const bool ValidArg =
308 getArgType(FD, ArgN)->isIntegralType(Ctx: 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 range
316 /// 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 iteration
318 /// 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 /// \code
330 /// -------+--------+------------------+------------+----------->
331 /// A B C D
332 /// \endcode
333 /// 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 is
335 /// 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 complementary
339 /// 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>(args&: 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 it
408 /// is allowed to have a NULL value if the size is 0. The size can depend on
409 /// 1 or 2 additional arguments, if one of these is 0 the buffer is allowed to
410 /// be NULL. Otherwise, the buffer pointer must be non-null. This is useful
411 /// 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>(args&: 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. The
454 // 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 of
469 // `fread` like functions where the size is computed as a multiplication of
470 // 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(x: *SizeArgN);
500 if (SizeMultiplierArgN)
501 Result.push_back(x: *SizeMultiplierArgN);
502 return Result;
503 }
504
505 ValueConstraintPtr negate() const override {
506 BufferSizeConstraint Tmp(*this);
507 Tmp.Op = BinaryOperator::negateComparisonOp(Opc: Op);
508 return std::make_shared<BufferSizeConstraint>(args&: 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 a
527 /// more specific constraint (for example > 0), or new case can be added
528 /// for functions which require check of \c errno in both success and failure
529 /// 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 causes
537 /// a later bug report created by ErrnoChecker.
538 /// Empty return value means that 'errno' related bug may not happen from
539 /// 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 the
548 /// 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 not
554 /// 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, EState: errno_modeling::Irrelevant);
561 }
562 };
563
564 /// Do not change errno constraints.
565 /// This is applicable to functions that are modeled in another checker
566 /// and the already set errno constraints should not be changed in the
567 /// 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 checked
579 /// by the program. \c ErrnoChecker does not emit a bug report after such a
580 /// 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: Call, type: C.getASTContext().IntTy,
588 visitCount: C.blockCount(), symbolTag: &Tag)
589 .castAs<NonLoc>();
590 return errno_modeling::setErrnoForStdFailure(State, C, ErrnoSym: 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 is
596 /// undefined after successful call.
597 /// \c ErrnoChecker can emit bug report after such a function call if errno
598 /// 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 errno
615 /// 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 Elem: 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 introduce
635 /// a child node in the Exploded Graph. The child node has to include
636 /// constraints that define the branch. If the constraints contradict
637 /// existing constraints in the state, the node is not created and the branch
638 /// is dropped; otherwise it's queued for future exploration.
639 /// The branch is accompanied by a note text that may be displayed
640 /// 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 0
650 /// 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 concrete
677 // 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 a
682 // concessive signature, meaning there may be irrelevant types in the
683 // 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 types
694 // 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(T: *Arg);
702 this->ArgTys.push_back(x: *Arg);
703 }
704 }
705 if (!RetTy) {
706 Invalid = true;
707 return;
708 } else {
709 assertRetTypeSuitableForSignature(T: *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(i: ArgN)->getType().getCanonicalType();
735 return T;
736 }
737
738 using SummaryCases = std::vector<SummaryCase>;
739
740 /// A summary includes information about
741 /// * 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 error
746 /// usually resulting in undefined behaviour.
747 ///
748 /// Application of a summary:
749 /// The signature and argument constraints together contain information
750 /// about which functions are handled by the summary. The signature can use
751 /// "wildcards", i.e. Irrelevant types. Irrelevant type of a parameter in
752 /// a signature means that type is not compared to the type of the parameter
753 /// in the found FunctionDecl. Argument constraints may specify additional
754 /// rules for the given parameter's type, those rules are checked once the
755 /// 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 and
762 // 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(x: 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(x: 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(x: 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 on
806 // 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 initialized
820 // 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(Index: 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>(Val: 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 LLVM_ATTRIBUTE_MINSIZE 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(), Out&: MsgOs);
866 MsgOs << " to '" << getFunctionName(Call) << "' ";
867 bool ValuesPrinted =
868 NegatedVC->describeArgumentValue(Call, State: N->getState(), Summary, Out&: MsgOs);
869 if (ValuesPrinted)
870 MsgOs << " but ";
871 else
872 MsgOs << "is out of the accepted range; It ";
873 VC->describe(DK: ValueConstraint::Violation, Call, State: C.getState(), Summary,
874 Out&: MsgOs);
875 Msg[0] = toupper(c: Msg[0]);
876 auto R = std::make_unique<PathSensitiveBugReport>(args: BT_InvalidArg, args&: Msg, args&: N);
877
878 for (ArgNo ArgN : VC->getArgsToTrack()) {
879 bugreporter::trackExpressionValue(N, E: Call.getArgExpr(Index: ArgN), R&: *R);
880 R->markInteresting(V: Call.getArgSVal(Index: ArgN));
881 // All tracked arguments are important, highlight them.
882 R->addRange(R: Call.getArgSourceRange(Index: ArgN));
883 }
884
885 C.emitReport(R: 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 function
891 /// needs different cases for success and failure with different errno
892 /// 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 namespace
912
913void StdLibraryFunctionsChecker::printArgDesc(
914 StdLibraryFunctionsChecker::ArgNo ArgN, llvm::raw_ostream &Out) {
915 Out << std::to_string(val: ArgN + 1);
916 Out << llvm::getOrdinalSuffix(Val: 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: State, val: 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(T: ArgT)) {
940 if (RMax == -1)
941 Out << "< 0";
942 else
943 Out << "<= " << RMax;
944 } else if (RMax == BVF.getMaxValue(T: ArgT)) {
945 if (RMin.isOne())
946 Out << "> 0";
947 else
948 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(T: ArgT)) {
967 if (RMax == -1)
968 Out << ">= 0";
969 else
970 Out << "> " << RMax;
971 } else if (RMax == BVF.getMaxValue(T: ArgT)) {
972 if (RMin.isOne())
973 Out << "<= 0";
974 else
975 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(X: Start, T: ArgT);
991 const llvm::APSInt &Max = BVF.getValue(X: End, T: 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(T: ArgT);
1007 const llvm::APSInt &PlusInf = BVF.getMaxValue(T: ArgT);
1008
1009 const llvm::APSInt &RangeLeft = BVF.getValue(X: R[0].first - 1ULL, T: ArgT);
1010 const llvm::APSInt &RangeRight = BVF.getValue(X: R[E - 1].second + 1ULL, T: 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(X: R[I - 1].second + 1ULL, T: ArgT);
1015 const llvm::APSInt &Max = BVF.getValue(X: R[I].first - 1ULL, T: 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, ArgN: getArgNo());
1040 QualType T = Summary.getArgType(ArgN: 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, Value: *N, From: Min, To: Max, InBound: 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(Kind: negateKind(K: Kind), BVF&: C.getSValBuilder().getBasicValueFactory(), ArgT: T,
1051 F: 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(ArgN: 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(RMin: BVF.getValue(X: R.first, T),
1072 RMax: BVF.getValue(X: R.second, T), ArgT: T, BVF, Out);
1073 if (--I > 0)
1074 Out << " or ";
1075 }
1076 } else {
1077 for (const std::pair<RangeInt, RangeInt> &R : Ranges) {
1078 appendOutOfRangeDesc(RMin: BVF.getValue(X: R.first, T),
1079 RMax: BVF.getValue(X: R.second, T), ArgT: 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, ArgN: 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(ArgN: 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, Value: *N, From: Min, To: Max, InBound: true)) {
1109 if (NRanges > 0)
1110 MoreInfoOs << " or ";
1111 appendInsideRangeDesc(RMin: Min, RMax: Max, ArgT: T, BVF, Out&: MoreInfoOs);
1112 ++NRanges;
1113 } else {
1114 HaveAllRanges = false;
1115 }
1116 return true;
1117 };
1118
1119 applyOnRange(Kind, BVF, ArgT: T, F: 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(ArgN: getArgNo());
1138 SVal V = getArgSVal(Call, ArgN: getArgNo());
1139
1140 BinaryOperator::Opcode Op = getOpcode();
1141 ArgNo OtherArg = getOtherArgNo();
1142 SVal OtherV = getArgSVal(Call, ArgN: OtherArg);
1143 QualType OtherT = Summary.getArgType(ArgN: OtherArg);
1144 // Note: we avoid integral promotion for comparison.
1145 OtherV = SVB.evalCast(V: OtherV, CastTy: T, OriginalTy: OtherT);
1146 if (auto CompV = SVB.evalBinOp(state: State, op: Op, lhs: V, rhs: OtherV, type: CondT)
1147 .getAs<DefinedOrUnknownSVal>())
1148 State = State->assume(Cond: *CompV, Assumption: 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, ArgN: getArgNo());
1156 if (V.isUndef())
1157 return State;
1158
1159 DefinedOrUnknownSVal L = V.castAs<DefinedOrUnknownSVal>();
1160 if (!isa<Loc>(Val: L))
1161 return State;
1162
1163 return State->assume(Cond: L, Assumption: 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 else
1174 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, ArgN: getArgNo());
1190 if (V.isUndef())
1191 return State;
1192 DefinedOrUnknownSVal L = V.castAs<DefinedOrUnknownSVal>();
1193 if (!isa<Loc>(Val: L))
1194 return State;
1195
1196 std::optional<DefinedOrUnknownSVal> SizeArg1 =
1197 getArgSVal(Call, ArgN: SizeArg1N).getAs<DefinedOrUnknownSVal>();
1198 std::optional<DefinedOrUnknownSVal> SizeArg2;
1199 if (SizeArg2N)
1200 SizeArg2 = getArgSVal(Call, ArgN: *SizeArg2N).getAs<DefinedOrUnknownSVal>();
1201
1202 auto IsArgZero = [State](std::optional<DefinedOrUnknownSVal> Val) {
1203 if (!Val)
1204 return false;
1205 auto [IsNonNull, IsNull] = State->assume(Cond: *Val);
1206 return IsNull && !IsNonNull;
1207 };
1208
1209 if (IsArgZero(SizeArg1) || IsArgZero(SizeArg2))
1210 return State;
1211
1212 return State->assume(Cond: L, Assumption: 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 else
1223 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, ArgN: getArgNo());
1242
1243 // Get the size constraint.
1244 const SVal SizeV = [this, &State, &Call, &Summary, &SvalBuilder]() {
1245 if (ConcreteSize) {
1246 return SVal(SvalBuilder.makeIntVal(integer: *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, ArgN: *SizeArgN);
1252 // Multiply with another argument if given.
1253 if (SizeMultiplierArgN) {
1254 SVal SizeMulV = getArgSVal(Call, ArgN: *SizeMultiplierArgN);
1255 SizeV = SvalBuilder.evalBinOp(state: State, op: BO_Mul, lhs: SizeV, rhs: SizeMulV,
1256 type: Summary.getArgType(ArgN: *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: State, op: Op, lhs: SizeV, rhs: BufDynSize,
1265 type: SvalBuilder.getContext().BoolTy);
1266 if (auto F = Feasible.getAs<DefinedOrUnknownSVal>())
1267 return State->assume(Cond: *F, Assumption: true);
1268
1269 // We can get here only if the size argument or the dynamic size is
1270 // undefined. But the dynamic size should never be undefined, only
1271 // unknown. So, here, the size of the argument is undefined, i.e. we
1272 // cannot apply the constraint. Actually, other checkers like
1273 // CallAndMessage should catch this situation earlier, because we call a
1274 // 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(ArgN: *SizeArgN, Out);
1288 printArgValueInfo(ArgN: *SizeArgN, State, Call, Out);
1289 if (SizeMultiplierArgN) {
1290 Out << " times the ";
1291 printArgDesc(ArgN: *SizeMultiplierArgN, Out);
1292 printArgValueInfo(ArgN: *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, ArgN: getArgNo());
1301 SVal BufDynSize = getDynamicExtentWithOffset(State, BufV);
1302 if (const llvm::APSInt *Val =
1303 State->getStateManager().getSValBuilder().getKnownValue(state: State,
1304 val: 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(State: NewState, Call, Summary, C);
1325 ProgramStateRef FailureSt =
1326 NegatedConstraint->apply(State: NewState, Call, Summary, C);
1327 // The argument constraint is not satisfied.
1328 if (FailureSt && !SuccessSt) {
1329 if (ExplodedNode *N = C.generateErrorNode(State, Pred: NewNode))
1330 reportBug(Call, N, VC: Constraint.get(), NegatedVC: NegatedConstraint.get(), Summary,
1331 C);
1332 break;
1333 }
1334 // We will apply the constraint even if we cannot reason about the
1335 // argument. This means both SuccessSt and FailureSt can be true. If we
1336 // weren't applying the constraint that would mean that symbolic
1337 // 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(ArgN: Constraint->getArgNo(), Out&: Os);
1345 Os << " to '";
1346 Os << getFunctionName(Call);
1347 Os << "' ";
1348 Constraint->describe(DK: ValueConstraint::Assumption, Call, State: NewState, Summary,
1349 Out&: Os);
1350 const auto ArgSVal = Call.getArgSVal(Index: Constraint->getArgNo());
1351 NewNode = C.addTransition(
1352 State: NewState, Pred: NewNode,
1353 Tag: C.getNoteTag(Cb: [Msg = std::move(Msg), ArgSVal](
1354 PathSensitiveBugReport &BR, llvm::raw_ostream &OS) {
1355 if (BR.isInteresting(V: 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(State: NewState, Call, Summary, C);
1378 if (!NewState)
1379 break;
1380 }
1381
1382 if (NewState)
1383 NewState = Case.getErrnoConstraint().apply(State: NewState, Call, Summary, C);
1384
1385 if (!NewState)
1386 continue;
1387
1388 // Here it's possible that NewState == State, e.g. when other checkers
1389 // already applied the same constraints (or stricter ones).
1390 // Still add these note tags, the other checker should add only its
1391 // specialized note tags. These general note tags are handled always by
1392 // StdLibraryFunctionsChecker.
1393
1394 ExplodedNode *Pred = Node;
1395 DeclarationName FunctionName =
1396 cast<NamedDecl>(Val: 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(Fmt: "After calling '{0}' {1}", Vals&: FunctionName, Vals&: ErrnoNote);
1404 } else {
1405 // Disable formatv() validation as the case note may not always have the
1406 // {0} placeholder for function name.
1407 CaseNote =
1408 llvm::formatv(Validate: false, Fmt: Case.getNote().str().c_str(), Vals&: 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 not
1414 // affect it).
1415 if (!CaseNote.empty()) {
1416 const NoteTag *Tag = C.getNoteTag(
1417 Cb: [Node, CaseNote, RV](PathSensitiveBugReport &BR) -> std::string {
1418 // Try to omit the note if we know in advance which branch is
1419 // taken (this means, only one branch exists).
1420 // This check is performed inside the lambda, after other
1421 // (or this) checkers had a chance to add other successors.
1422 // Dereferencing the saved node object is valid because it's part
1423 // of a bug report call sequence.
1424 // FIXME: This check is not exact. We may be here after a state
1425 // split that was performed by another checker (and can not find
1426 // the successors). This is why this check is only used in the
1427 // EvalCallAsPure case.
1428 if (BR.isInteresting(V: RV) && Node->succ_size() > 1)
1429 return CaseNote;
1430 return "";
1431 });
1432 Pred = C.addTransition(State: NewState, Pred, Tag);
1433 }
1434 } else {
1435 if (!CaseNote.empty() || !ErrnoNote.empty()) {
1436 const NoteTag *Tag =
1437 C.getNoteTag(Cb: [CaseNote, ErrnoNote,
1438 RV](PathSensitiveBugReport &BR) -> std::string {
1439 // If 'errno' is interesting, show the user a note about the case
1440 // (what happened at the function call) and about how 'errno'
1441 // causes the problem. ErrnoChecker sets the errno (but not RV) to
1442 // interesting.
1443 // If only the return value is interesting, show only the case
1444 // note.
1445 std::optional<Loc> ErrnoLoc =
1446 errno_modeling::getErrnoLoc(State: BR.getErrorNode()->getState());
1447 bool ErrnoImportant = !ErrnoNote.empty() && ErrnoLoc &&
1448 BR.isInteresting(R: ErrnoLoc->getAsRegion());
1449 if (ErrnoImportant) {
1450 BR.markNotInteresting(R: ErrnoLoc->getAsRegion());
1451 if (CaseNote.empty())
1452 return ErrnoNote;
1453 return llvm::formatv(Fmt: "{0}; {1}", Vals: CaseNote, Vals: ErrnoNote);
1454 } else {
1455 if (BR.isInteresting(V: RV))
1456 return CaseNote;
1457 }
1458 return "";
1459 });
1460 Pred = C.addTransition(State: 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(State: 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 auto *CE = cast<CallExpr>(Val: Call.getOriginExpr());
1481 SVal V = C.getSValBuilder().conjureSymbolVal(call: Call, visitCount: C.blockCount());
1482 State = State->BindExpr(E: CE, SF: C.getStackFrame(), V);
1483
1484 C.addTransition(State);
1485
1486 return true;
1487 }
1488 case NoEvalCall:
1489 // Summary tells us to avoid performing eval::Call. The function is possibly
1490 // evaluated by another checker, or evaluated conservatively.
1491 return false;
1492 }
1493 llvm_unreachable("Unknown invalidation kind!");
1494}
1495
1496bool StdLibraryFunctionsChecker::Signature::matches(
1497 const FunctionDecl *FD) const {
1498 assert(!isInvalid());
1499 // Check the number of arguments.
1500 if (FD->param_size() != ArgTys.size())
1501 return false;
1502
1503 // The "restrict" keyword is illegal in C++, however, many libc
1504 // implementations use the "__restrict" compiler intrinsic in functions
1505 // prototypes. The "__restrict" keyword qualifies a type as a restricted type
1506 // even in C++.
1507 // In case of any non-C99 languages, we don't want to match based on the
1508 // restrict qualifier because we cannot know if the given libc implementation
1509 // qualifies the paramter type or not.
1510 auto RemoveRestrict = [&FD](QualType T) {
1511 if (!FD->getASTContext().getLangOpts().C99)
1512 T.removeLocalRestrict();
1513 return T;
1514 };
1515
1516 // Check the return type.
1517 if (!isIrrelevant(T: RetTy)) {
1518 QualType FDRetTy = RemoveRestrict(FD->getReturnType().getCanonicalType());
1519 if (RetTy != FDRetTy)
1520 return false;
1521 }
1522
1523 // Check the argument types.
1524 for (auto [Idx, ArgTy] : llvm::enumerate(First: ArgTys)) {
1525 if (isIrrelevant(T: ArgTy))
1526 continue;
1527 QualType FDArgTy =
1528 RemoveRestrict(FD->getParamDecl(i: Idx)->getType().getCanonicalType());
1529 if (ArgTy != FDArgTy)
1530 return false;
1531 }
1532
1533 return true;
1534}
1535
1536std::optional<StdLibraryFunctionsChecker::Summary>
1537StdLibraryFunctionsChecker::findFunctionSummary(const FunctionDecl *FD,
1538 CheckerContext &C) const {
1539 if (!FD)
1540 return std::nullopt;
1541
1542 initFunctionSummaries(C);
1543
1544 auto FSMI = FunctionSummaryMap.find(Val: FD->getCanonicalDecl());
1545 if (FSMI == FunctionSummaryMap.end())
1546 return std::nullopt;
1547 return FSMI->second;
1548}
1549
1550std::optional<StdLibraryFunctionsChecker::Summary>
1551StdLibraryFunctionsChecker::findFunctionSummary(const CallEvent &Call,
1552 CheckerContext &C) const {
1553 const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(Val: Call.getDecl());
1554 if (!FD)
1555 return std::nullopt;
1556 return findFunctionSummary(FD, C);
1557}
1558
1559void StdLibraryFunctionsChecker::initFunctionSummaries(
1560 CheckerContext &C) const {
1561 if (SummariesInitialized)
1562 return;
1563 SummariesInitialized = true;
1564
1565 SValBuilder &SVB = C.getSValBuilder();
1566 BasicValueFactory &BVF = SVB.getBasicValueFactory();
1567 const ASTContext &ACtx = BVF.getContext();
1568 Preprocessor &PP = C.getPreprocessor();
1569
1570 // Helper class to lookup a type by its name.
1571 class LookupType {
1572 const ASTContext &ACtx;
1573
1574 public:
1575 LookupType(const ASTContext &ACtx) : ACtx(ACtx) {}
1576
1577 // Find the type. If not found then the optional is not set.
1578 std::optional<QualType> operator()(StringRef Name) {
1579 IdentifierInfo &II = ACtx.Idents.get(Name);
1580 auto LookupRes = ACtx.getTranslationUnitDecl()->lookup(Name: &II);
1581 if (LookupRes.empty())
1582 return std::nullopt;
1583
1584 // Prioritize typedef declarations.
1585 // This is needed in case of C struct typedefs. E.g.:
1586 // typedef struct FILE FILE;
1587 // In this case, we have a RecordDecl 'struct FILE' with the name 'FILE'
1588 // and we have a TypedefDecl with the name 'FILE'.
1589 for (Decl *D : LookupRes)
1590 if (auto *TD = dyn_cast<TypedefNameDecl>(Val: D))
1591 return ACtx.getCanonicalTypeDeclType(TD);
1592
1593 // Find the first TypeDecl.
1594 // There maybe cases when a function has the same name as a struct.
1595 // E.g. in POSIX: `struct stat` and the function `stat()`:
1596 // int stat(const char *restrict path, struct stat *restrict buf);
1597 for (Decl *D : LookupRes)
1598 if (auto *TD = dyn_cast<TypeDecl>(Val: D))
1599 return ACtx.getCanonicalTypeDeclType(TD);
1600 return std::nullopt;
1601 }
1602 } lookupTy(ACtx);
1603
1604 // Below are auxiliary classes to handle optional types that we get as a
1605 // result of the lookup.
1606 class GetRestrictTy {
1607 const ASTContext &ACtx;
1608
1609 public:
1610 GetRestrictTy(const ASTContext &ACtx) : ACtx(ACtx) {}
1611 QualType operator()(QualType Ty) {
1612 return ACtx.getLangOpts().C99 ? ACtx.getRestrictType(T: Ty) : Ty;
1613 }
1614 std::optional<QualType> operator()(std::optional<QualType> Ty) {
1615 if (Ty)
1616 return operator()(Ty: *Ty);
1617 return std::nullopt;
1618 }
1619 } getRestrictTy(ACtx);
1620 class GetPointerTy {
1621 const ASTContext &ACtx;
1622
1623 public:
1624 GetPointerTy(const ASTContext &ACtx) : ACtx(ACtx) {}
1625 QualType operator()(QualType Ty) { return ACtx.getPointerType(T: Ty); }
1626 std::optional<QualType> operator()(std::optional<QualType> Ty) {
1627 if (Ty)
1628 return operator()(Ty: *Ty);
1629 return std::nullopt;
1630 }
1631 } getPointerTy(ACtx);
1632 class {
1633 public:
1634 std::optional<QualType> operator()(std::optional<QualType> Ty) {
1635 return Ty ? std::optional<QualType>(Ty->withConst()) : std::nullopt;
1636 }
1637 QualType operator()(QualType Ty) { return Ty.withConst(); }
1638 } getConstTy;
1639 class GetMaxValue {
1640 BasicValueFactory &BVF;
1641
1642 public:
1643 GetMaxValue(BasicValueFactory &BVF) : BVF(BVF) {}
1644 std::optional<RangeInt> operator()(QualType Ty) {
1645 return BVF.getMaxValue(T: Ty)->getLimitedValue();
1646 }
1647 std::optional<RangeInt> operator()(std::optional<QualType> Ty) {
1648 if (Ty) {
1649 return operator()(Ty: *Ty);
1650 }
1651 return std::nullopt;
1652 }
1653 } getMaxValue(BVF);
1654
1655 // These types are useful for writing specifications quickly,
1656 // New specifications should probably introduce more types.
1657 // Some types are hard to obtain from the AST, eg. "ssize_t".
1658 // In such cases it should be possible to provide multiple variants
1659 // of function summary for common cases (eg. ssize_t could be int or long
1660 // or long long, so three summary variants would be enough).
1661 // Of course, function variants are also useful for C++ overloads.
1662 const QualType VoidTy = ACtx.VoidTy;
1663 const QualType CharTy = ACtx.CharTy;
1664 const QualType WCharTy = ACtx.WCharTy;
1665 const QualType IntTy = ACtx.IntTy;
1666 const QualType UnsignedIntTy = ACtx.UnsignedIntTy;
1667 const QualType LongTy = ACtx.LongTy;
1668 const QualType SizeTyCanonTy = ACtx.getCanonicalSizeType();
1669
1670 const QualType VoidPtrTy = getPointerTy(VoidTy); // void *
1671 const QualType IntPtrTy = getPointerTy(IntTy); // int *
1672 const QualType UnsignedIntPtrTy =
1673 getPointerTy(UnsignedIntTy); // unsigned int *
1674 const QualType VoidPtrRestrictTy = getRestrictTy(VoidPtrTy);
1675 const QualType ConstVoidPtrTy =
1676 getPointerTy(getConstTy(VoidTy)); // const void *
1677 const QualType CharPtrTy = getPointerTy(CharTy); // char *
1678 const QualType CharPtrRestrictTy = getRestrictTy(CharPtrTy);
1679 const QualType ConstCharPtrTy =
1680 getPointerTy(getConstTy(CharTy)); // const char *
1681 const QualType ConstCharPtrRestrictTy = getRestrictTy(ConstCharPtrTy);
1682 const QualType Wchar_tPtrTy = getPointerTy(WCharTy); // wchar_t *
1683 const QualType ConstWchar_tPtrTy =
1684 getPointerTy(getConstTy(WCharTy)); // const wchar_t *
1685 const QualType ConstVoidPtrRestrictTy = getRestrictTy(ConstVoidPtrTy);
1686 const QualType SizePtrTy = getPointerTy(SizeTyCanonTy);
1687 const QualType SizePtrRestrictTy = getRestrictTy(SizePtrTy);
1688
1689 const RangeInt IntMax = BVF.getMaxValue(T: IntTy)->getLimitedValue();
1690 const RangeInt UnsignedIntMax =
1691 BVF.getMaxValue(T: UnsignedIntTy)->getLimitedValue();
1692 const RangeInt LongMax = BVF.getMaxValue(T: LongTy)->getLimitedValue();
1693 const RangeInt SizeMax = BVF.getMaxValue(T: SizeTyCanonTy)->getLimitedValue();
1694
1695 // Set UCharRangeMax to min of int or uchar maximum value.
1696 // The C standard states that the arguments of functions like isalpha must
1697 // be representable as an unsigned char. Their type is 'int', so the max
1698 // value of the argument should be min(UCharMax, IntMax). This just happen
1699 // to be true for commonly used and well tested instruction set
1700 // architectures, but not for others.
1701 const RangeInt UCharRangeMax =
1702 std::min(a: BVF.getMaxValue(T: ACtx.UnsignedCharTy)->getLimitedValue(), b: IntMax);
1703
1704 // Get platform dependent values of some macros.
1705 // Try our best to parse this from the Preprocessor, otherwise fallback to a
1706 // default value (what is found in a library header).
1707 const auto EOFv = tryExpandAsInteger(Macro: "EOF", PP).value_or(u: -1);
1708 const auto AT_FDCWDv = tryExpandAsInteger(Macro: "AT_FDCWD", PP).value_or(u: -100);
1709
1710 // Auxiliary class to aid adding summaries to the summary map.
1711 struct AddToFunctionSummaryMap {
1712 const ASTContext &ACtx;
1713 FunctionSummaryMapType &Map;
1714 bool DisplayLoadedSummaries;
1715 AddToFunctionSummaryMap(const ASTContext &ACtx, FunctionSummaryMapType &FSM,
1716 bool DisplayLoadedSummaries)
1717 : ACtx(ACtx), Map(FSM), DisplayLoadedSummaries(DisplayLoadedSummaries) {
1718 }
1719
1720 // Add a summary to a FunctionDecl found by lookup. The lookup is performed
1721 // by the given Name, and in the global scope. The summary will be attached
1722 // to the found FunctionDecl only if the signatures match.
1723 //
1724 // Returns true if the summary has been added, false otherwise.
1725 bool operator()(StringRef Name, Signature Sign, Summary Sum) {
1726 if (Sign.isInvalid())
1727 return false;
1728 IdentifierInfo &II = ACtx.Idents.get(Name);
1729 auto LookupRes = ACtx.getTranslationUnitDecl()->lookup(Name: &II);
1730 if (LookupRes.empty())
1731 return false;
1732 for (Decl *D : LookupRes) {
1733 if (auto *FD = dyn_cast<FunctionDecl>(Val: D)) {
1734 if (Sum.matchesAndSet(Sign, FD)) {
1735 auto Res = Map.insert(KV: {FD->getCanonicalDecl(), Sum});
1736 assert(Res.second && "Function already has a summary set!");
1737 (void)Res;
1738 if (DisplayLoadedSummaries) {
1739 llvm::errs() << "Loaded summary for: ";
1740 FD->print(Out&: llvm::errs());
1741 llvm::errs() << "\n";
1742 }
1743 return true;
1744 }
1745 }
1746 }
1747 return false;
1748 }
1749 // Add the same summary for different names with the Signature explicitly
1750 // given.
1751 void operator()(ArrayRef<StringRef> Names, Signature Sign, Summary Sum) {
1752 for (StringRef Name : Names)
1753 operator()(Name, Sign, Sum);
1754 }
1755 } addToFunctionSummaryMap(ACtx, FunctionSummaryMap, DisplayLoadedSummaries);
1756
1757 // Below are helpers functions to create the summaries.
1758 auto ArgumentCondition = [](ArgNo ArgN, RangeKind Kind, IntRangeVector Ranges,
1759 StringRef Desc = "") {
1760 return std::make_shared<RangeConstraint>(args&: ArgN, args&: Kind, args&: Ranges, args&: Desc);
1761 };
1762 auto BufferSize = [](auto... Args) {
1763 return std::make_shared<BufferSizeConstraint>(Args...);
1764 };
1765 struct {
1766 auto operator()(RangeKind Kind, IntRangeVector Ranges) {
1767 return std::make_shared<RangeConstraint>(args: Ret, args&: Kind, args&: Ranges);
1768 }
1769 auto operator()(BinaryOperator::Opcode Op, ArgNo OtherArgN) {
1770 return std::make_shared<ComparisonConstraint>(args: Ret, args&: Op, args&: OtherArgN);
1771 }
1772 } ReturnValueCondition;
1773 struct {
1774 auto operator()(RangeInt b, RangeInt e) {
1775 return IntRangeVector{std::pair<RangeInt, RangeInt>{b, e}};
1776 }
1777 auto operator()(RangeInt b, std::optional<RangeInt> e) {
1778 if (e)
1779 return IntRangeVector{std::pair<RangeInt, RangeInt>{b, *e}};
1780 return IntRangeVector{};
1781 }
1782 auto operator()(std::pair<RangeInt, RangeInt> i0,
1783 std::pair<RangeInt, std::optional<RangeInt>> i1) {
1784 if (i1.second)
1785 return IntRangeVector{i0, {i1.first, *(i1.second)}};
1786 return IntRangeVector{i0};
1787 }
1788 } Range;
1789 auto SingleValue = [](RangeInt v) {
1790 return IntRangeVector{std::pair<RangeInt, RangeInt>{v, v}};
1791 };
1792 auto LessThanOrEq = BO_LE;
1793 auto NotNull = [&](ArgNo ArgN) {
1794 return std::make_shared<NullnessConstraint>(args&: ArgN);
1795 };
1796 auto IsNull = [&](ArgNo ArgN) {
1797 return std::make_shared<NullnessConstraint>(args&: ArgN, args: false);
1798 };
1799 auto NotNullBuffer = [&](ArgNo ArgN, ArgNo SizeArg1N,
1800 std::optional<ArgNo> SizeArg2N = std::nullopt) {
1801 return std::make_shared<BufferNullnessConstraint>(args&: ArgN, args&: SizeArg1N,
1802 args&: SizeArg2N);
1803 };
1804
1805 std::optional<QualType> FileTy = lookupTy("FILE");
1806 std::optional<QualType> FilePtrTy = getPointerTy(FileTy);
1807 std::optional<QualType> FilePtrRestrictTy = getRestrictTy(FilePtrTy);
1808
1809 std::optional<QualType> FPosTTy = lookupTy("fpos_t");
1810 std::optional<QualType> FPosTPtrTy = getPointerTy(FPosTTy);
1811 std::optional<QualType> ConstFPosTPtrTy = getPointerTy(getConstTy(FPosTTy));
1812 std::optional<QualType> FPosTPtrRestrictTy = getRestrictTy(FPosTPtrTy);
1813
1814 constexpr llvm::StringLiteral GenericSuccessMsg(
1815 "Assuming that '{0}' is successful");
1816 constexpr llvm::StringLiteral GenericFailureMsg("Assuming that '{0}' fails");
1817
1818 // We are finally ready to define specifications for all supported functions.
1819 //
1820 // Argument ranges should always cover all variants. If return value
1821 // is completely unknown, omit it from the respective range set.
1822 //
1823 // Every item in the list of range sets represents a particular
1824 // execution path the analyzer would need to explore once
1825 // the call is modeled - a new program state is constructed
1826 // for every range set, and each range line in the range set
1827 // corresponds to a specific constraint within this state.
1828
1829 // The isascii() family of functions.
1830 // The behavior is undefined if the value of the argument is not
1831 // representable as unsigned char or is not equal to EOF. See e.g. C99
1832 // 7.4.1.2 The isalpha function (p: 181-182).
1833 addToFunctionSummaryMap(
1834 "isalnum", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1835 Summary(EvalCallAsPure)
1836 // Boils down to isupper() or islower() or isdigit().
1837 .Case(CS: {ArgumentCondition(0U, WithinRange,
1838 {{'0', '9'}, {'A', 'Z'}, {'a', 'z'}}),
1839 ReturnValueCondition(OutOfRange, SingleValue(0))},
1840 ErrnoC: ErrnoIrrelevant, Note: "Assuming the character is alphanumeric")
1841 // The locale-specific range.
1842 // No post-condition. We are completely unaware of
1843 // locale-specific return values.
1844 .Case(CS: {ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})},
1845 ErrnoC: ErrnoIrrelevant)
1846 .Case(
1847 CS: {ArgumentCondition(
1848 0U, OutOfRange,
1849 {{'0', '9'}, {'A', 'Z'}, {'a', 'z'}, {128, UCharRangeMax}}),
1850 ReturnValueCondition(WithinRange, SingleValue(0))},
1851 ErrnoC: ErrnoIrrelevant, Note: "Assuming the character is non-alphanumeric")
1852 .ArgConstraint(VC: ArgumentCondition(0U, WithinRange,
1853 {{EOFv, EOFv}, {0, UCharRangeMax}},
1854 "an unsigned char value or EOF")));
1855 addToFunctionSummaryMap(
1856 "isalpha", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1857 Summary(EvalCallAsPure)
1858 .Case(CS: {ArgumentCondition(0U, WithinRange, {{'A', 'Z'}, {'a', 'z'}}),
1859 ReturnValueCondition(OutOfRange, SingleValue(0))},
1860 ErrnoC: ErrnoIrrelevant, Note: "Assuming the character is alphabetical")
1861 // The locale-specific range.
1862 .Case(CS: {ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})},
1863 ErrnoC: ErrnoIrrelevant)
1864 .Case(CS: {ArgumentCondition(
1865 0U, OutOfRange,
1866 {{'A', 'Z'}, {'a', 'z'}, {128, UCharRangeMax}}),
1867 ReturnValueCondition(WithinRange, SingleValue(0))},
1868 ErrnoC: ErrnoIrrelevant, Note: "Assuming the character is non-alphabetical"));
1869 addToFunctionSummaryMap(
1870 "isascii", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1871 Summary(EvalCallAsPure)
1872 .Case(CS: {ArgumentCondition(0U, WithinRange, Range(0, 127)),
1873 ReturnValueCondition(OutOfRange, SingleValue(0))},
1874 ErrnoC: ErrnoIrrelevant, Note: "Assuming the character is an ASCII character")
1875 .Case(CS: {ArgumentCondition(0U, OutOfRange, Range(0, 127)),
1876 ReturnValueCondition(WithinRange, SingleValue(0))},
1877 ErrnoC: ErrnoIrrelevant,
1878 Note: "Assuming the character is not an ASCII character"));
1879 addToFunctionSummaryMap(
1880 "isblank", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1881 Summary(EvalCallAsPure)
1882 .Case(CS: {ArgumentCondition(0U, WithinRange, {{'\t', '\t'}, {' ', ' '}}),
1883 ReturnValueCondition(OutOfRange, SingleValue(0))},
1884 ErrnoC: ErrnoIrrelevant, Note: "Assuming the character is a blank character")
1885 .Case(CS: {ArgumentCondition(0U, OutOfRange, {{'\t', '\t'}, {' ', ' '}}),
1886 ReturnValueCondition(WithinRange, SingleValue(0))},
1887 ErrnoC: ErrnoIrrelevant,
1888 Note: "Assuming the character is not a blank character"));
1889 addToFunctionSummaryMap(
1890 "iscntrl", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1891 Summary(EvalCallAsPure)
1892 .Case(CS: {ArgumentCondition(0U, WithinRange, {{0, 32}, {127, 127}}),
1893 ReturnValueCondition(OutOfRange, SingleValue(0))},
1894 ErrnoC: ErrnoIrrelevant,
1895 Note: "Assuming the character is a control character")
1896 .Case(CS: {ArgumentCondition(0U, OutOfRange, {{0, 32}, {127, 127}}),
1897 ReturnValueCondition(WithinRange, SingleValue(0))},
1898 ErrnoC: ErrnoIrrelevant,
1899 Note: "Assuming the character is not a control character"));
1900 addToFunctionSummaryMap(
1901 "isdigit", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1902 Summary(EvalCallAsPure)
1903 .Case(CS: {ArgumentCondition(0U, WithinRange, Range('0', '9')),
1904 ReturnValueCondition(OutOfRange, SingleValue(0))},
1905 ErrnoC: ErrnoIrrelevant, Note: "Assuming the character is a digit")
1906 .Case(CS: {ArgumentCondition(0U, OutOfRange, Range('0', '9')),
1907 ReturnValueCondition(WithinRange, SingleValue(0))},
1908 ErrnoC: ErrnoIrrelevant, Note: "Assuming the character is not a digit"));
1909 addToFunctionSummaryMap(
1910 "isgraph", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1911 Summary(EvalCallAsPure)
1912 .Case(CS: {ArgumentCondition(0U, WithinRange, Range(33, 126)),
1913 ReturnValueCondition(OutOfRange, SingleValue(0))},
1914 ErrnoC: ErrnoIrrelevant,
1915 Note: "Assuming the character has graphical representation")
1916 .Case(
1917 CS: {ArgumentCondition(0U, OutOfRange, Range(33, 126)),
1918 ReturnValueCondition(WithinRange, SingleValue(0))},
1919 ErrnoC: ErrnoIrrelevant,
1920 Note: "Assuming the character does not have graphical representation"));
1921 addToFunctionSummaryMap(
1922 "islower", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1923 Summary(EvalCallAsPure)
1924 // Is certainly lowercase.
1925 .Case(CS: {ArgumentCondition(0U, WithinRange, Range('a', 'z')),
1926 ReturnValueCondition(OutOfRange, SingleValue(0))},
1927 ErrnoC: ErrnoIrrelevant, Note: "Assuming the character is a lowercase letter")
1928 // Is ascii but not lowercase.
1929 .Case(CS: {ArgumentCondition(0U, WithinRange, Range(0, 127)),
1930 ArgumentCondition(0U, OutOfRange, Range('a', 'z')),
1931 ReturnValueCondition(WithinRange, SingleValue(0))},
1932 ErrnoC: ErrnoIrrelevant,
1933 Note: "Assuming the character is not a lowercase letter")
1934 // The locale-specific range.
1935 .Case(CS: {ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})},
1936 ErrnoC: ErrnoIrrelevant)
1937 // Is not an unsigned char.
1938 .Case(CS: {ArgumentCondition(0U, OutOfRange, Range(0, UCharRangeMax)),
1939 ReturnValueCondition(WithinRange, SingleValue(0))},
1940 ErrnoC: ErrnoIrrelevant));
1941 addToFunctionSummaryMap(
1942 "isprint", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1943 Summary(EvalCallAsPure)
1944 .Case(CS: {ArgumentCondition(0U, WithinRange, Range(32, 126)),
1945 ReturnValueCondition(OutOfRange, SingleValue(0))},
1946 ErrnoC: ErrnoIrrelevant, Note: "Assuming the character is printable")
1947 .Case(CS: {ArgumentCondition(0U, OutOfRange, Range(32, 126)),
1948 ReturnValueCondition(WithinRange, SingleValue(0))},
1949 ErrnoC: ErrnoIrrelevant, Note: "Assuming the character is non-printable"));
1950 addToFunctionSummaryMap(
1951 "ispunct", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1952 Summary(EvalCallAsPure)
1953 .Case(CS: {ArgumentCondition(
1954 0U, WithinRange,
1955 {{'!', '/'}, {':', '@'}, {'[', '`'}, {'{', '~'}}),
1956 ReturnValueCondition(OutOfRange, SingleValue(0))},
1957 ErrnoC: ErrnoIrrelevant, Note: "Assuming the character is a punctuation mark")
1958 .Case(CS: {ArgumentCondition(
1959 0U, OutOfRange,
1960 {{'!', '/'}, {':', '@'}, {'[', '`'}, {'{', '~'}}),
1961 ReturnValueCondition(WithinRange, SingleValue(0))},
1962 ErrnoC: ErrnoIrrelevant,
1963 Note: "Assuming the character is not a punctuation mark"));
1964 addToFunctionSummaryMap(
1965 "isspace", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1966 Summary(EvalCallAsPure)
1967 // Space, '\f', '\n', '\r', '\t', '\v'.
1968 .Case(CS: {ArgumentCondition(0U, WithinRange, {{9, 13}, {' ', ' '}}),
1969 ReturnValueCondition(OutOfRange, SingleValue(0))},
1970 ErrnoC: ErrnoIrrelevant,
1971 Note: "Assuming the character is a whitespace character")
1972 // The locale-specific range.
1973 .Case(CS: {ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})},
1974 ErrnoC: ErrnoIrrelevant)
1975 .Case(CS: {ArgumentCondition(0U, OutOfRange,
1976 {{9, 13}, {' ', ' '}, {128, UCharRangeMax}}),
1977 ReturnValueCondition(WithinRange, SingleValue(0))},
1978 ErrnoC: ErrnoIrrelevant,
1979 Note: "Assuming the character is not a whitespace character"));
1980 addToFunctionSummaryMap(
1981 "isupper", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1982 Summary(EvalCallAsPure)
1983 // Is certainly uppercase.
1984 .Case(CS: {ArgumentCondition(0U, WithinRange, Range('A', 'Z')),
1985 ReturnValueCondition(OutOfRange, SingleValue(0))},
1986 ErrnoC: ErrnoIrrelevant,
1987 Note: "Assuming the character is an uppercase letter")
1988 // The locale-specific range.
1989 .Case(CS: {ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})},
1990 ErrnoC: ErrnoIrrelevant)
1991 // Other.
1992 .Case(CS: {ArgumentCondition(0U, OutOfRange,
1993 {{'A', 'Z'}, {128, UCharRangeMax}}),
1994 ReturnValueCondition(WithinRange, SingleValue(0))},
1995 ErrnoC: ErrnoIrrelevant,
1996 Note: "Assuming the character is not an uppercase letter"));
1997 addToFunctionSummaryMap(
1998 "isxdigit", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1999 Summary(EvalCallAsPure)
2000 .Case(CS: {ArgumentCondition(0U, WithinRange,
2001 {{'0', '9'}, {'A', 'F'}, {'a', 'f'}}),
2002 ReturnValueCondition(OutOfRange, SingleValue(0))},
2003 ErrnoC: ErrnoIrrelevant,
2004 Note: "Assuming the character is a hexadecimal digit")
2005 .Case(CS: {ArgumentCondition(0U, OutOfRange,
2006 {{'0', '9'}, {'A', 'F'}, {'a', 'f'}}),
2007 ReturnValueCondition(WithinRange, SingleValue(0))},
2008 ErrnoC: ErrnoIrrelevant,
2009 Note: "Assuming the character is not a hexadecimal digit"));
2010 addToFunctionSummaryMap(
2011 "toupper", Signature(ArgTypes{IntTy}, RetType{IntTy}),
2012 Summary(EvalCallAsPure)
2013 .ArgConstraint(VC: ArgumentCondition(0U, WithinRange,
2014 {{EOFv, EOFv}, {0, UCharRangeMax}},
2015 "an unsigned char value or EOF")));
2016 addToFunctionSummaryMap(
2017 "tolower", Signature(ArgTypes{IntTy}, RetType{IntTy}),
2018 Summary(EvalCallAsPure)
2019 .ArgConstraint(VC: ArgumentCondition(0U, WithinRange,
2020 {{EOFv, EOFv}, {0, UCharRangeMax}},
2021 "an unsigned char value or EOF")));
2022 addToFunctionSummaryMap(
2023 "toascii", Signature(ArgTypes{IntTy}, RetType{IntTy}),
2024 Summary(EvalCallAsPure)
2025 .ArgConstraint(VC: ArgumentCondition(0U, WithinRange,
2026 {{EOFv, EOFv}, {0, UCharRangeMax}},
2027 "an unsigned char value or EOF")));
2028
2029 addToFunctionSummaryMap(
2030 "getchar", Signature(ArgTypes{}, RetType{IntTy}),
2031 Summary(NoEvalCall)
2032 .Case(CS: {ReturnValueCondition(WithinRange,
2033 {{EOFv, EOFv}, {0, UCharRangeMax}})},
2034 ErrnoC: ErrnoIrrelevant));
2035
2036 // read()-like functions that never return more than buffer size.
2037 auto FreadSummary =
2038 Summary(NoEvalCall)
2039 .Case(CS: {ArgumentCondition(1U, WithinRange, Range(1, SizeMax)),
2040 ArgumentCondition(2U, WithinRange, Range(1, SizeMax)),
2041 ReturnValueCondition(BO_LT, ArgNo(2)),
2042 ReturnValueCondition(WithinRange, Range(0, SizeMax))},
2043 ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
2044 .Case(CS: {ArgumentCondition(1U, WithinRange, Range(1, SizeMax)),
2045 ReturnValueCondition(BO_EQ, ArgNo(2)),
2046 ReturnValueCondition(WithinRange, Range(0, SizeMax))},
2047 ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
2048 .Case(CS: {ArgumentCondition(1U, WithinRange, SingleValue(0)),
2049 ReturnValueCondition(WithinRange, SingleValue(0))},
2050 ErrnoC: ErrnoMustNotBeChecked,
2051 Note: "Assuming that argument 'size' to '{0}' is 0")
2052 .ArgConstraint(VC: NotNullBuffer(ArgNo(0), ArgNo(1), ArgNo(2)))
2053 .ArgConstraint(VC: NotNull(ArgNo(3)))
2054 .ArgConstraint(VC: BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1),
2055 /*BufSizeMultiplier=*/ArgNo(2)));
2056
2057 // size_t fread(void *restrict ptr, size_t size, size_t nitems,
2058 // FILE *restrict stream);
2059 addToFunctionSummaryMap("fread",
2060 Signature(ArgTypes{VoidPtrRestrictTy, SizeTyCanonTy,
2061 SizeTyCanonTy, FilePtrRestrictTy},
2062 RetType{SizeTyCanonTy}),
2063 FreadSummary);
2064 // size_t fwrite(const void *restrict ptr, size_t size, size_t nitems,
2065 // FILE *restrict stream);
2066 addToFunctionSummaryMap(
2067 "fwrite",
2068 Signature(ArgTypes{ConstVoidPtrRestrictTy, SizeTyCanonTy, SizeTyCanonTy,
2069 FilePtrRestrictTy},
2070 RetType{SizeTyCanonTy}),
2071 FreadSummary);
2072
2073 std::optional<QualType> Ssize_tTy = lookupTy("ssize_t");
2074 std::optional<RangeInt> Ssize_tMax = getMaxValue(Ssize_tTy);
2075
2076 auto ReadSummary =
2077 Summary(NoEvalCall)
2078 .Case(CS: {ReturnValueCondition(LessThanOrEq, ArgNo(2)),
2079 ReturnValueCondition(WithinRange, Range(-1, Ssize_tMax))},
2080 ErrnoC: ErrnoIrrelevant);
2081
2082 // FIXME these are actually defined by POSIX and not by the C standard, we
2083 // should handle them together with the rest of the POSIX functions.
2084 // ssize_t read(int fildes, void *buf, size_t nbyte);
2085 addToFunctionSummaryMap(
2086 "read",
2087 Signature(ArgTypes{IntTy, VoidPtrTy, SizeTyCanonTy}, RetType{Ssize_tTy}),
2088 ReadSummary);
2089 // ssize_t write(int fildes, const void *buf, size_t nbyte);
2090 addToFunctionSummaryMap(
2091 "write",
2092 Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTyCanonTy},
2093 RetType{Ssize_tTy}),
2094 ReadSummary);
2095
2096 auto GetLineSummary =
2097 Summary(NoEvalCall)
2098 .Case(CS: {ReturnValueCondition(WithinRange,
2099 Range({-1, -1}, {1, Ssize_tMax}))},
2100 ErrnoC: ErrnoIrrelevant);
2101
2102 QualType CharPtrPtrRestrictTy = getRestrictTy(getPointerTy(CharPtrTy));
2103
2104 // getline()-like functions either fail or read at least the delimiter.
2105 // FIXME these are actually defined by POSIX and not by the C standard, we
2106 // should handle them together with the rest of the POSIX functions.
2107 // ssize_t getline(char **restrict lineptr, size_t *restrict n,
2108 // FILE *restrict stream);
2109 addToFunctionSummaryMap(
2110 "getline",
2111 Signature(
2112 ArgTypes{CharPtrPtrRestrictTy, SizePtrRestrictTy, FilePtrRestrictTy},
2113 RetType{Ssize_tTy}),
2114 GetLineSummary);
2115 // ssize_t getdelim(char **restrict lineptr, size_t *restrict n,
2116 // int delimiter, FILE *restrict stream);
2117 addToFunctionSummaryMap(
2118 "getdelim",
2119 Signature(ArgTypes{CharPtrPtrRestrictTy, SizePtrRestrictTy, IntTy,
2120 FilePtrRestrictTy},
2121 RetType{Ssize_tTy}),
2122 GetLineSummary);
2123
2124 {
2125 Summary GetenvSummary =
2126 Summary(NoEvalCall)
2127 .ArgConstraint(VC: NotNull(ArgNo(0)))
2128 .Case(CS: {NotNull(Ret)}, ErrnoC: ErrnoIrrelevant,
2129 Note: "Assuming the environment variable exists");
2130 // In untrusted environments the envvar might not exist.
2131 if (!ShouldAssumeControlledEnvironment)
2132 GetenvSummary.Case(CS: {NotNull(Ret)->negate()}, ErrnoC: ErrnoIrrelevant,
2133 Note: "Assuming the environment variable does not exist");
2134
2135 // char *getenv(const char *name);
2136 addToFunctionSummaryMap(
2137 "getenv", Signature(ArgTypes{ConstCharPtrTy}, RetType{CharPtrTy}),
2138 std::move(GetenvSummary));
2139 }
2140
2141 if (!ModelPOSIX) {
2142 // Without POSIX use of 'errno' is not specified (in these cases).
2143 // Add these functions without 'errno' checks.
2144 addToFunctionSummaryMap(
2145 {"getc", "fgetc"}, Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
2146 Summary(NoEvalCall)
2147 .Case(CS: {ReturnValueCondition(WithinRange,
2148 {{EOFv, EOFv}, {0, UCharRangeMax}})},
2149 ErrnoC: ErrnoIrrelevant)
2150 .ArgConstraint(VC: NotNull(ArgNo(0))));
2151 } else {
2152 const auto ReturnsZero =
2153 ConstraintSet{ReturnValueCondition(WithinRange, SingleValue(0))};
2154 const auto ReturnsMinusOne =
2155 ConstraintSet{ReturnValueCondition(WithinRange, SingleValue(-1))};
2156 const auto ReturnsEOF =
2157 ConstraintSet{ReturnValueCondition(WithinRange, SingleValue(EOFv))};
2158 const auto ReturnsNonnegative =
2159 ConstraintSet{ReturnValueCondition(WithinRange, Range(0, IntMax))};
2160 const auto ReturnsNonZero =
2161 ConstraintSet{ReturnValueCondition(OutOfRange, SingleValue(0))};
2162 const auto &ReturnsValidFileDescriptor = ReturnsNonnegative;
2163
2164 auto ValidFileDescriptorOrAtFdcwd = [&](ArgNo ArgN) {
2165 return std::make_shared<RangeConstraint>(
2166 args&: ArgN, args: WithinRange, args: Range({AT_FDCWDv, AT_FDCWDv}, {0, IntMax}),
2167 args: "a valid file descriptor or AT_FDCWD");
2168 };
2169
2170 // FILE *fopen(const char *restrict pathname, const char *restrict mode);
2171 addToFunctionSummaryMap(
2172 "fopen",
2173 Signature(ArgTypes{ConstCharPtrRestrictTy, ConstCharPtrRestrictTy},
2174 RetType{FilePtrTy}),
2175 Summary(NoEvalCall)
2176 .Case(CS: {NotNull(Ret)}, ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
2177 .Case(CS: {IsNull(Ret)}, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
2178 .ArgConstraint(VC: NotNull(ArgNo(0)))
2179 .ArgConstraint(VC: NotNull(ArgNo(1))));
2180
2181 // FILE *fdopen(int fd, const char *mode);
2182 addToFunctionSummaryMap(
2183 "fdopen",
2184 Signature(ArgTypes{IntTy, ConstCharPtrTy}, RetType{FilePtrTy}),
2185 Summary(NoEvalCall)
2186 .Case(CS: {NotNull(Ret)}, ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
2187 .Case(CS: {IsNull(Ret)}, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
2188 .ArgConstraint(VC: ArgumentCondition(0, WithinRange, Range(0, IntMax)))
2189 .ArgConstraint(VC: NotNull(ArgNo(1))));
2190
2191 // FILE *tmpfile(void);
2192 addToFunctionSummaryMap(
2193 "tmpfile", Signature(ArgTypes{}, RetType{FilePtrTy}),
2194 Summary(NoEvalCall)
2195 .Case(CS: {NotNull(Ret)}, ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
2196 .Case(CS: {IsNull(Ret)}, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg));
2197
2198 // FILE *freopen(const char *restrict pathname, const char *restrict mode,
2199 // FILE *restrict stream);
2200 addToFunctionSummaryMap(
2201 "freopen",
2202 Signature(ArgTypes{ConstCharPtrRestrictTy, ConstCharPtrRestrictTy,
2203 FilePtrRestrictTy},
2204 RetType{FilePtrTy}),
2205 Summary(NoEvalCall)
2206 .Case(CS: {ReturnValueCondition(BO_EQ, ArgNo(2))},
2207 ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
2208 .Case(CS: {IsNull(Ret)}, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
2209 .ArgConstraint(VC: NotNull(ArgNo(1)))
2210 .ArgConstraint(VC: NotNull(ArgNo(2))));
2211
2212 // FILE *popen(const char *command, const char *type);
2213 addToFunctionSummaryMap(
2214 "popen",
2215 Signature(ArgTypes{ConstCharPtrTy, ConstCharPtrTy}, RetType{FilePtrTy}),
2216 Summary(NoEvalCall)
2217 .Case(CS: {NotNull(Ret)}, ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
2218 .Case(CS: {IsNull(Ret)}, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
2219 .ArgConstraint(VC: NotNull(ArgNo(0)))
2220 .ArgConstraint(VC: NotNull(ArgNo(1))));
2221
2222 // int fclose(FILE *stream);
2223 addToFunctionSummaryMap(
2224 "fclose", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
2225 Summary(NoEvalCall)
2226 .Case(CS: ReturnsZero, ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
2227 .Case(CS: ReturnsEOF, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
2228 .ArgConstraint(VC: NotNull(ArgNo(0))));
2229
2230 // int pclose(FILE *stream);
2231 addToFunctionSummaryMap(
2232 "pclose", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
2233 Summary(NoEvalCall)
2234 .Case(CS: {ReturnValueCondition(WithinRange, {{0, IntMax}})},
2235 ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
2236 .Case(CS: ReturnsMinusOne, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
2237 .ArgConstraint(VC: NotNull(ArgNo(0))));
2238
2239 std::optional<QualType> Off_tTy = lookupTy("off_t");
2240 std::optional<RangeInt> Off_tMax = getMaxValue(Off_tTy);
2241
2242 // int fgetc(FILE *stream);
2243 // 'getc' is the same as 'fgetc' but may be a macro
2244 addToFunctionSummaryMap(
2245 {"getc", "fgetc"}, Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
2246 Summary(NoEvalCall)
2247 .Case(CS: {ReturnValueCondition(WithinRange, {{0, UCharRangeMax}})},
2248 ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
2249 .Case(CS: {ReturnValueCondition(WithinRange, SingleValue(EOFv))},
2250 ErrnoC: ErrnoIrrelevant, Note: GenericFailureMsg)
2251 .ArgConstraint(VC: NotNull(ArgNo(0))));
2252
2253 // int fputc(int c, FILE *stream);
2254 // 'putc' is the same as 'fputc' but may be a macro
2255 addToFunctionSummaryMap(
2256 {"putc", "fputc"},
2257 Signature(ArgTypes{IntTy, FilePtrTy}, RetType{IntTy}),
2258 Summary(NoEvalCall)
2259 .Case(CS: {ArgumentCondition(0, WithinRange, Range(0, UCharRangeMax)),
2260 ReturnValueCondition(BO_EQ, ArgNo(0))},
2261 ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
2262 .Case(CS: {ArgumentCondition(0, OutOfRange, Range(0, UCharRangeMax)),
2263 ReturnValueCondition(WithinRange, Range(0, UCharRangeMax))},
2264 ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
2265 .Case(CS: {ReturnValueCondition(WithinRange, SingleValue(EOFv))},
2266 ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
2267 .ArgConstraint(VC: NotNull(ArgNo(1))));
2268
2269 // char *fgets(char *restrict s, int n, FILE *restrict stream);
2270 addToFunctionSummaryMap(
2271 "fgets",
2272 Signature(ArgTypes{CharPtrRestrictTy, IntTy, FilePtrRestrictTy},
2273 RetType{CharPtrTy}),
2274 Summary(NoEvalCall)
2275 .Case(CS: {NotNull(Ret), ReturnValueCondition(BO_EQ, ArgNo(0))},
2276 ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
2277 .Case(CS: {IsNull(Ret)}, ErrnoC: ErrnoIrrelevant, Note: GenericFailureMsg)
2278 .ArgConstraint(VC: NotNull(ArgNo(0)))
2279 .ArgConstraint(VC: ArgumentCondition(1, WithinRange, Range(0, IntMax)))
2280 .ArgConstraint(
2281 VC: BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1)))
2282 .ArgConstraint(VC: NotNull(ArgNo(2))));
2283
2284 // int fputs(const char *restrict s, FILE *restrict stream);
2285 addToFunctionSummaryMap(
2286 "fputs",
2287 Signature(ArgTypes{ConstCharPtrRestrictTy, FilePtrRestrictTy},
2288 RetType{IntTy}),
2289 Summary(NoEvalCall)
2290 .Case(CS: ReturnsNonnegative, ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
2291 .Case(CS: {ReturnValueCondition(WithinRange, SingleValue(EOFv))},
2292 ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
2293 .ArgConstraint(VC: NotNull(ArgNo(0)))
2294 .ArgConstraint(VC: NotNull(ArgNo(1))));
2295
2296 // int ungetc(int c, FILE *stream);
2297 addToFunctionSummaryMap(
2298 "ungetc", Signature(ArgTypes{IntTy, FilePtrTy}, RetType{IntTy}),
2299 Summary(NoEvalCall)
2300 .Case(CS: {ReturnValueCondition(BO_EQ, ArgNo(0)),
2301 ArgumentCondition(0, WithinRange, {{0, UCharRangeMax}})},
2302 ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
2303 .Case(CS: {ReturnValueCondition(WithinRange, SingleValue(EOFv)),
2304 ArgumentCondition(0, WithinRange, SingleValue(EOFv))},
2305 ErrnoC: ErrnoNEZeroIrrelevant,
2306 Note: "Assuming that 'ungetc' fails because EOF was passed as "
2307 "character")
2308 .Case(CS: {ReturnValueCondition(WithinRange, SingleValue(EOFv)),
2309 ArgumentCondition(0, WithinRange, {{0, UCharRangeMax}})},
2310 ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
2311 .ArgConstraint(VC: ArgumentCondition(
2312 0, WithinRange, {{EOFv, EOFv}, {0, UCharRangeMax}}))
2313 .ArgConstraint(VC: NotNull(ArgNo(1))));
2314
2315 // int fseek(FILE *stream, long offset, int whence);
2316 // FIXME: It can be possible to get the 'SEEK_' values (like EOFv) and use
2317 // these for condition of arg 2.
2318 // Now the range [0,2] is used (the `SEEK_*` constants are usually 0,1,2).
2319 addToFunctionSummaryMap(
2320 "fseek", Signature(ArgTypes{FilePtrTy, LongTy, IntTy}, RetType{IntTy}),
2321 Summary(NoEvalCall)
2322 .Case(CS: ReturnsZero, ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
2323 .Case(CS: ReturnsMinusOne, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
2324 .ArgConstraint(VC: NotNull(ArgNo(0)))
2325 .ArgConstraint(VC: ArgumentCondition(2, WithinRange, {{0, 2}})));
2326
2327 // int fseeko(FILE *stream, off_t offset, int whence);
2328 addToFunctionSummaryMap(
2329 "fseeko",
2330 Signature(ArgTypes{FilePtrTy, Off_tTy, IntTy}, RetType{IntTy}),
2331 Summary(NoEvalCall)
2332 .Case(CS: ReturnsZero, ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
2333 .Case(CS: ReturnsMinusOne, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
2334 .ArgConstraint(VC: NotNull(ArgNo(0)))
2335 .ArgConstraint(VC: ArgumentCondition(2, WithinRange, {{0, 2}})));
2336
2337 // int fgetpos(FILE *restrict stream, fpos_t *restrict pos);
2338 // From 'The Open Group Base Specifications Issue 7, 2018 edition':
2339 // "The fgetpos() function shall not change the setting of errno if
2340 // successful."
2341 addToFunctionSummaryMap(
2342 "fgetpos",
2343 Signature(ArgTypes{FilePtrRestrictTy, FPosTPtrRestrictTy},
2344 RetType{IntTy}),
2345 Summary(NoEvalCall)
2346 .Case(CS: ReturnsZero, ErrnoC: ErrnoUnchanged, Note: GenericSuccessMsg)
2347 .Case(CS: ReturnsNonZero, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
2348 .ArgConstraint(VC: NotNull(ArgNo(0)))
2349 .ArgConstraint(VC: NotNull(ArgNo(1))));
2350
2351 // int fsetpos(FILE *stream, const fpos_t *pos);
2352 // From 'The Open Group Base Specifications Issue 7, 2018 edition':
2353 // "The fsetpos() function shall not change the setting of errno if
2354 // successful."
2355 addToFunctionSummaryMap(
2356 "fsetpos",
2357 Signature(ArgTypes{FilePtrTy, ConstFPosTPtrTy}, RetType{IntTy}),
2358 Summary(NoEvalCall)
2359 .Case(CS: ReturnsZero, ErrnoC: ErrnoUnchanged, Note: GenericSuccessMsg)
2360 .Case(CS: ReturnsNonZero, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
2361 .ArgConstraint(VC: NotNull(ArgNo(0)))
2362 .ArgConstraint(VC: NotNull(ArgNo(1))));
2363
2364 // int fflush(FILE *stream);
2365 addToFunctionSummaryMap(
2366 "fflush", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
2367 Summary(NoEvalCall)
2368 .Case(CS: ReturnsZero, ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
2369 .Case(CS: ReturnsEOF, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg));
2370
2371 // long ftell(FILE *stream);
2372 // From 'The Open Group Base Specifications Issue 7, 2018 edition':
2373 // "The ftell() function shall not change the setting of errno if
2374 // successful."
2375 addToFunctionSummaryMap(
2376 "ftell", Signature(ArgTypes{FilePtrTy}, RetType{LongTy}),
2377 Summary(NoEvalCall)
2378 .Case(CS: {ReturnValueCondition(WithinRange, Range(0, LongMax))},
2379 ErrnoC: ErrnoUnchanged, Note: GenericSuccessMsg)
2380 .Case(CS: ReturnsMinusOne, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
2381 .ArgConstraint(VC: NotNull(ArgNo(0))));
2382
2383 // off_t ftello(FILE *stream);
2384 addToFunctionSummaryMap(
2385 "ftello", Signature(ArgTypes{FilePtrTy}, RetType{Off_tTy}),
2386 Summary(NoEvalCall)
2387 .Case(CS: {ReturnValueCondition(WithinRange, Range(0, Off_tMax))},
2388 ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
2389 .Case(CS: ReturnsMinusOne, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
2390 .ArgConstraint(VC: NotNull(ArgNo(0))));
2391
2392 // int fileno(FILE *stream);
2393 // According to POSIX 'fileno' may fail and set 'errno'.
2394 // But in Linux it may fail only if the specified file pointer is invalid.
2395 // At many places 'fileno' is used without check for failure and a failure
2396 // case here would produce a large amount of likely false positive warnings.
2397 // To avoid this, we assume here that it does not fail.
2398 addToFunctionSummaryMap(
2399 "fileno", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
2400 Summary(NoEvalCall)
2401 .Case(CS: ReturnsValidFileDescriptor, ErrnoC: ErrnoUnchanged, Note: GenericSuccessMsg)
2402 .ArgConstraint(VC: NotNull(ArgNo(0))));
2403
2404 // void rewind(FILE *stream);
2405 // This function indicates error only by setting of 'errno'.
2406 addToFunctionSummaryMap("rewind",
2407 Signature(ArgTypes{FilePtrTy}, RetType{VoidTy}),
2408 Summary(NoEvalCall)
2409 .Case(CS: {}, ErrnoC: ErrnoMustBeChecked)
2410 .ArgConstraint(VC: NotNull(ArgNo(0))));
2411
2412 // void clearerr(FILE *stream);
2413 addToFunctionSummaryMap(
2414 "clearerr", Signature(ArgTypes{FilePtrTy}, RetType{VoidTy}),
2415 Summary(NoEvalCall).ArgConstraint(VC: NotNull(ArgNo(0))));
2416
2417 // int feof(FILE *stream);
2418 addToFunctionSummaryMap(
2419 "feof", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
2420 Summary(NoEvalCall).ArgConstraint(VC: NotNull(ArgNo(0))));
2421
2422 // int ferror(FILE *stream);
2423 addToFunctionSummaryMap(
2424 "ferror", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
2425 Summary(NoEvalCall).ArgConstraint(VC: NotNull(ArgNo(0))));
2426
2427 // long a64l(const char *str64);
2428 addToFunctionSummaryMap(
2429 "a64l", Signature(ArgTypes{ConstCharPtrTy}, RetType{LongTy}),
2430 Summary(NoEvalCall).ArgConstraint(VC: NotNull(ArgNo(0))));
2431
2432 // char *l64a(long value);
2433 addToFunctionSummaryMap("l64a",
2434 Signature(ArgTypes{LongTy}, RetType{CharPtrTy}),
2435 Summary(NoEvalCall)
2436 .ArgConstraint(VC: ArgumentCondition(
2437 0, WithinRange, Range(0, LongMax))));
2438
2439 // int open(const char *path, int oflag, ...);
2440 addToFunctionSummaryMap(
2441 "open", Signature(ArgTypes{ConstCharPtrTy, IntTy}, RetType{IntTy}),
2442 Summary(NoEvalCall)
2443 .Case(CS: ReturnsValidFileDescriptor, ErrnoC: ErrnoMustNotBeChecked,
2444 Note: GenericSuccessMsg)
2445 .Case(CS: ReturnsMinusOne, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
2446 .ArgConstraint(VC: NotNull(ArgNo(0))));
2447
2448 // int openat(int fd, const char *path, int oflag, ...);
2449 addToFunctionSummaryMap(
2450 "openat",
2451 Signature(ArgTypes{IntTy, ConstCharPtrTy, IntTy}, RetType{IntTy}),
2452 Summary(NoEvalCall)
2453 .Case(CS: ReturnsValidFileDescriptor, ErrnoC: ErrnoMustNotBeChecked,
2454 Note: GenericSuccessMsg)
2455 .Case(CS: ReturnsMinusOne, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
2456 .ArgConstraint(VC: ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2457 .ArgConstraint(VC: NotNull(ArgNo(1))));
2458
2459 // int access(const char *pathname, int amode);
2460 addToFunctionSummaryMap(
2461 "access", Signature(ArgTypes{ConstCharPtrTy, IntTy}, RetType{IntTy}),
2462 Summary(NoEvalCall)
2463 .Case(CS: ReturnsZero, ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
2464 .Case(CS: ReturnsMinusOne, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
2465 .ArgConstraint(VC: NotNull(ArgNo(0))));
2466
2467 // int faccessat(int dirfd, const char *pathname, int mode, int flags);
2468 addToFunctionSummaryMap(
2469 "faccessat",
2470 Signature(ArgTypes{IntTy, ConstCharPtrTy, IntTy, IntTy},
2471 RetType{IntTy}),
2472 Summary(NoEvalCall)
2473 .Case(CS: ReturnsZero, ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
2474 .Case(CS: ReturnsMinusOne, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
2475 .ArgConstraint(VC: ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2476 .ArgConstraint(VC: NotNull(ArgNo(1))));
2477
2478 // int dup(int fildes);
2479 addToFunctionSummaryMap(
2480 "dup", Signature(ArgTypes{IntTy}, RetType{IntTy}),
2481 Summary(NoEvalCall)
2482 .Case(CS: ReturnsValidFileDescriptor, ErrnoC: ErrnoMustNotBeChecked,
2483 Note: GenericSuccessMsg)
2484 .Case(CS: ReturnsMinusOne, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
2485 .ArgConstraint(
2486 VC: ArgumentCondition(0, WithinRange, Range(0, IntMax))));
2487
2488 // int dup2(int fildes1, int filedes2);
2489 addToFunctionSummaryMap(
2490 "dup2", Signature(ArgTypes{IntTy, IntTy}, RetType{IntTy}),
2491 Summary(NoEvalCall)
2492 .Case(CS: ReturnsValidFileDescriptor, ErrnoC: ErrnoMustNotBeChecked,
2493 Note: GenericSuccessMsg)
2494 .Case(CS: ReturnsMinusOne, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
2495 .ArgConstraint(VC: ArgumentCondition(0, WithinRange, Range(0, IntMax)))
2496 .ArgConstraint(
2497 VC: ArgumentCondition(1, WithinRange, Range(0, IntMax))));
2498
2499 // int fdatasync(int fildes);
2500 addToFunctionSummaryMap(
2501 "fdatasync", Signature(ArgTypes{IntTy}, RetType{IntTy}),
2502 Summary(NoEvalCall)
2503 .Case(CS: ReturnsZero, ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
2504 .Case(CS: ReturnsMinusOne, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
2505 .ArgConstraint(
2506 VC: ArgumentCondition(0, WithinRange, Range(0, IntMax))));
2507
2508 // int fnmatch(const char *pattern, const char *string, int flags);
2509 addToFunctionSummaryMap(
2510 "fnmatch",
2511 Signature(ArgTypes{ConstCharPtrTy, ConstCharPtrTy, IntTy},
2512 RetType{IntTy}),
2513 Summary(NoEvalCall)
2514 .ArgConstraint(VC: NotNull(ArgNo(0)))
2515 .ArgConstraint(VC: NotNull(ArgNo(1))));
2516
2517 // int fsync(int fildes);
2518 addToFunctionSummaryMap(
2519 "fsync", Signature(ArgTypes{IntTy}, RetType{IntTy}),
2520 Summary(NoEvalCall)
2521 .Case(CS: ReturnsZero, ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
2522 .Case(CS: ReturnsMinusOne, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
2523 .ArgConstraint(
2524 VC: ArgumentCondition(0, WithinRange, Range(0, IntMax))));
2525
2526 // int truncate(const char *path, off_t length);
2527 addToFunctionSummaryMap(
2528 "truncate",
2529 Signature(ArgTypes{ConstCharPtrTy, Off_tTy}, RetType{IntTy}),
2530 Summary(NoEvalCall)
2531 .Case(CS: ReturnsZero, ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
2532 .Case(CS: ReturnsMinusOne, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
2533 .ArgConstraint(VC: NotNull(ArgNo(0))));
2534
2535 // int symlink(const char *oldpath, const char *newpath);
2536 addToFunctionSummaryMap(
2537 "symlink",
2538 Signature(ArgTypes{ConstCharPtrTy, ConstCharPtrTy}, RetType{IntTy}),
2539 Summary(NoEvalCall)
2540 .Case(CS: ReturnsZero, ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
2541 .Case(CS: ReturnsMinusOne, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
2542 .ArgConstraint(VC: NotNull(ArgNo(0)))
2543 .ArgConstraint(VC: NotNull(ArgNo(1))));
2544
2545 // int symlinkat(const char *oldpath, int newdirfd, const char *newpath);
2546 addToFunctionSummaryMap(
2547 "symlinkat",
2548 Signature(ArgTypes{ConstCharPtrTy, IntTy, ConstCharPtrTy},
2549 RetType{IntTy}),
2550 Summary(NoEvalCall)
2551 .Case(CS: ReturnsZero, ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
2552 .Case(CS: ReturnsMinusOne, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
2553 .ArgConstraint(VC: NotNull(ArgNo(0)))
2554 .ArgConstraint(VC: ValidFileDescriptorOrAtFdcwd(ArgNo(1)))
2555 .ArgConstraint(VC: NotNull(ArgNo(2))));
2556
2557 // int lockf(int fd, int cmd, off_t len);
2558 addToFunctionSummaryMap(
2559 "lockf", Signature(ArgTypes{IntTy, IntTy, Off_tTy}, RetType{IntTy}),
2560 Summary(NoEvalCall)
2561 .Case(CS: ReturnsZero, ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
2562 .Case(CS: ReturnsMinusOne, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
2563 .ArgConstraint(
2564 VC: ArgumentCondition(0, WithinRange, Range(0, IntMax))));
2565
2566 std::optional<QualType> Mode_tTy = lookupTy("mode_t");
2567
2568 // int creat(const char *pathname, mode_t mode);
2569 addToFunctionSummaryMap(
2570 "creat", Signature(ArgTypes{ConstCharPtrTy, Mode_tTy}, RetType{IntTy}),
2571 Summary(NoEvalCall)
2572 .Case(CS: ReturnsValidFileDescriptor, ErrnoC: ErrnoMustNotBeChecked,
2573 Note: GenericSuccessMsg)
2574 .Case(CS: ReturnsMinusOne, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
2575 .ArgConstraint(VC: NotNull(ArgNo(0))));
2576
2577 // unsigned int sleep(unsigned int seconds);
2578 addToFunctionSummaryMap(
2579 "sleep", Signature(ArgTypes{UnsignedIntTy}, RetType{UnsignedIntTy}),
2580 Summary(NoEvalCall)
2581 .ArgConstraint(
2582 VC: ArgumentCondition(0, WithinRange, Range(0, UnsignedIntMax))));
2583
2584 std::optional<QualType> DirTy = lookupTy("DIR");
2585 std::optional<QualType> DirPtrTy = getPointerTy(DirTy);
2586
2587 // int dirfd(DIR *dirp);
2588 addToFunctionSummaryMap(
2589 "dirfd", Signature(ArgTypes{DirPtrTy}, RetType{IntTy}),
2590 Summary(NoEvalCall)
2591 .Case(CS: ReturnsValidFileDescriptor, ErrnoC: ErrnoMustNotBeChecked,
2592 Note: GenericSuccessMsg)
2593 .Case(CS: ReturnsMinusOne, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
2594 .ArgConstraint(VC: NotNull(ArgNo(0))));
2595
2596 // unsigned int alarm(unsigned int seconds);
2597 addToFunctionSummaryMap(
2598 "alarm", Signature(ArgTypes{UnsignedIntTy}, RetType{UnsignedIntTy}),
2599 Summary(NoEvalCall)
2600 .ArgConstraint(
2601 VC: ArgumentCondition(0, WithinRange, Range(0, UnsignedIntMax))));
2602
2603 // int closedir(DIR *dir);
2604 addToFunctionSummaryMap(
2605 "closedir", Signature(ArgTypes{DirPtrTy}, RetType{IntTy}),
2606 Summary(NoEvalCall)
2607 .Case(CS: ReturnsZero, ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
2608 .Case(CS: ReturnsMinusOne, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
2609 .ArgConstraint(VC: NotNull(ArgNo(0))));
2610
2611 // char *strdup(const char *s);
2612 addToFunctionSummaryMap(
2613 "strdup", Signature(ArgTypes{ConstCharPtrTy}, RetType{CharPtrTy}),
2614 Summary(NoEvalCall).ArgConstraint(VC: NotNull(ArgNo(0))));
2615
2616 // char *strndup(const char *s, size_t n);
2617 addToFunctionSummaryMap(
2618 "strndup",
2619 Signature(ArgTypes{ConstCharPtrTy, SizeTyCanonTy}, RetType{CharPtrTy}),
2620 Summary(NoEvalCall)
2621 .ArgConstraint(VC: NotNull(ArgNo(0)))
2622 .ArgConstraint(
2623 VC: ArgumentCondition(1, WithinRange, Range(0, SizeMax))));
2624
2625 // wchar_t *wcsdup(const wchar_t *s);
2626 addToFunctionSummaryMap(
2627 "wcsdup", Signature(ArgTypes{ConstWchar_tPtrTy}, RetType{Wchar_tPtrTy}),
2628 Summary(NoEvalCall).ArgConstraint(VC: NotNull(ArgNo(0))));
2629
2630 // int mkstemp(char *template);
2631 addToFunctionSummaryMap(
2632 "mkstemp", Signature(ArgTypes{CharPtrTy}, RetType{IntTy}),
2633 Summary(NoEvalCall)
2634 .Case(CS: ReturnsValidFileDescriptor, ErrnoC: ErrnoMustNotBeChecked,
2635 Note: GenericSuccessMsg)
2636 .Case(CS: ReturnsMinusOne, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
2637 .ArgConstraint(VC: NotNull(ArgNo(0))));
2638
2639 // char *mkdtemp(char *template);
2640 addToFunctionSummaryMap(
2641 "mkdtemp", Signature(ArgTypes{CharPtrTy}, RetType{CharPtrTy}),
2642 Summary(NoEvalCall)
2643 .Case(CS: {NotNull(Ret), ReturnValueCondition(BO_EQ, ArgNo(0))},
2644 ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
2645 .Case(CS: {IsNull(Ret)}, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
2646 .ArgConstraint(VC: NotNull(ArgNo(0))));
2647
2648 // char *getcwd(char *buf, size_t size);
2649 addToFunctionSummaryMap(
2650 "getcwd",
2651 Signature(ArgTypes{CharPtrTy, SizeTyCanonTy}, RetType{CharPtrTy}),
2652 Summary(NoEvalCall)
2653 .Case(CS: {NotNull(0),
2654 ArgumentCondition(1, WithinRange, Range(1, SizeMax)),
2655 ReturnValueCondition(BO_EQ, ArgNo(0)), NotNull(Ret)},
2656 ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
2657 .Case(CS: {NotNull(0),
2658 ArgumentCondition(1, WithinRange, SingleValue(0)),
2659 IsNull(Ret)},
2660 ErrnoC: ErrnoNEZeroIrrelevant, Note: "Assuming that argument 'size' is 0")
2661 .Case(CS: {NotNull(0),
2662 ArgumentCondition(1, WithinRange, Range(1, SizeMax)),
2663 IsNull(Ret)},
2664 ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
2665 .Case(CS: {IsNull(0), NotNull(Ret)}, ErrnoC: ErrnoMustNotBeChecked,
2666 Note: GenericSuccessMsg)
2667 .Case(CS: {IsNull(0), IsNull(Ret)}, ErrnoC: ErrnoNEZeroIrrelevant,
2668 Note: GenericFailureMsg)
2669 .ArgConstraint(
2670 VC: BufferSize(/*Buffer*/ ArgNo(0), /*BufSize*/ ArgNo(1)))
2671 .ArgConstraint(
2672 VC: ArgumentCondition(1, WithinRange, Range(0, SizeMax))));
2673
2674 // int mkdir(const char *pathname, mode_t mode);
2675 addToFunctionSummaryMap(
2676 "mkdir", Signature(ArgTypes{ConstCharPtrTy, Mode_tTy}, RetType{IntTy}),
2677 Summary(NoEvalCall)
2678 .Case(CS: ReturnsZero, ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
2679 .Case(CS: ReturnsMinusOne, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
2680 .ArgConstraint(VC: NotNull(ArgNo(0))));
2681
2682 // int mkdirat(int dirfd, const char *pathname, mode_t mode);
2683 addToFunctionSummaryMap(
2684 "mkdirat",
2685 Signature(ArgTypes{IntTy, ConstCharPtrTy, Mode_tTy}, RetType{IntTy}),
2686 Summary(NoEvalCall)
2687 .Case(CS: ReturnsZero, ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
2688 .Case(CS: ReturnsMinusOne, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
2689 .ArgConstraint(VC: ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2690 .ArgConstraint(VC: NotNull(ArgNo(1))));
2691
2692 std::optional<QualType> Dev_tTy = lookupTy("dev_t");
2693
2694 // int mknod(const char *pathname, mode_t mode, dev_t dev);
2695 addToFunctionSummaryMap(
2696 "mknod",
2697 Signature(ArgTypes{ConstCharPtrTy, Mode_tTy, Dev_tTy}, RetType{IntTy}),
2698 Summary(NoEvalCall)
2699 .Case(CS: ReturnsZero, ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
2700 .Case(CS: ReturnsMinusOne, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
2701 .ArgConstraint(VC: NotNull(ArgNo(0))));
2702
2703 // int mknodat(int dirfd, const char *pathname, mode_t mode, dev_t dev);
2704 addToFunctionSummaryMap(
2705 "mknodat",
2706 Signature(ArgTypes{IntTy, ConstCharPtrTy, Mode_tTy, Dev_tTy},
2707 RetType{IntTy}),
2708 Summary(NoEvalCall)
2709 .Case(CS: ReturnsZero, ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
2710 .Case(CS: ReturnsMinusOne, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
2711 .ArgConstraint(VC: ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2712 .ArgConstraint(VC: NotNull(ArgNo(1))));
2713
2714 // int chmod(const char *path, mode_t mode);
2715 addToFunctionSummaryMap(
2716 "chmod", Signature(ArgTypes{ConstCharPtrTy, Mode_tTy}, RetType{IntTy}),
2717 Summary(NoEvalCall)
2718 .Case(CS: ReturnsZero, ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
2719 .Case(CS: ReturnsMinusOne, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
2720 .ArgConstraint(VC: NotNull(ArgNo(0))));
2721
2722 // int fchmodat(int dirfd, const char *pathname, mode_t mode, int flags);
2723 addToFunctionSummaryMap(
2724 "fchmodat",
2725 Signature(ArgTypes{IntTy, ConstCharPtrTy, Mode_tTy, IntTy},
2726 RetType{IntTy}),
2727 Summary(NoEvalCall)
2728 .Case(CS: ReturnsZero, ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
2729 .Case(CS: ReturnsMinusOne, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
2730 .ArgConstraint(VC: ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2731 .ArgConstraint(VC: NotNull(ArgNo(1))));
2732
2733 // int fchmod(int fildes, mode_t mode);
2734 addToFunctionSummaryMap(
2735 "fchmod", Signature(ArgTypes{IntTy, Mode_tTy}, RetType{IntTy}),
2736 Summary(NoEvalCall)
2737 .Case(CS: ReturnsZero, ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
2738 .Case(CS: ReturnsMinusOne, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
2739 .ArgConstraint(
2740 VC: ArgumentCondition(0, WithinRange, Range(0, IntMax))));
2741
2742 std::optional<QualType> Uid_tTy = lookupTy("uid_t");
2743 std::optional<QualType> Gid_tTy = lookupTy("gid_t");
2744
2745 // int fchownat(int dirfd, const char *pathname, uid_t owner, gid_t group,
2746 // int flags);
2747 addToFunctionSummaryMap(
2748 "fchownat",
2749 Signature(ArgTypes{IntTy, ConstCharPtrTy, Uid_tTy, Gid_tTy, IntTy},
2750 RetType{IntTy}),
2751 Summary(NoEvalCall)
2752 .Case(CS: ReturnsZero, ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
2753 .Case(CS: ReturnsMinusOne, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
2754 .ArgConstraint(VC: ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2755 .ArgConstraint(VC: NotNull(ArgNo(1))));
2756
2757 // int chown(const char *path, uid_t owner, gid_t group);
2758 addToFunctionSummaryMap(
2759 "chown",
2760 Signature(ArgTypes{ConstCharPtrTy, Uid_tTy, Gid_tTy}, RetType{IntTy}),
2761 Summary(NoEvalCall)
2762 .Case(CS: ReturnsZero, ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
2763 .Case(CS: ReturnsMinusOne, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
2764 .ArgConstraint(VC: NotNull(ArgNo(0))));
2765
2766 // int lchown(const char *path, uid_t owner, gid_t group);
2767 addToFunctionSummaryMap(
2768 "lchown",
2769 Signature(ArgTypes{ConstCharPtrTy, Uid_tTy, Gid_tTy}, RetType{IntTy}),
2770 Summary(NoEvalCall)
2771 .Case(CS: ReturnsZero, ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
2772 .Case(CS: ReturnsMinusOne, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
2773 .ArgConstraint(VC: NotNull(ArgNo(0))));
2774
2775 // int fchown(int fildes, uid_t owner, gid_t group);
2776 addToFunctionSummaryMap(
2777 "fchown", Signature(ArgTypes{IntTy, Uid_tTy, Gid_tTy}, RetType{IntTy}),
2778 Summary(NoEvalCall)
2779 .Case(CS: ReturnsZero, ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
2780 .Case(CS: ReturnsMinusOne, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
2781 .ArgConstraint(
2782 VC: ArgumentCondition(0, WithinRange, Range(0, IntMax))));
2783
2784 // int rmdir(const char *pathname);
2785 addToFunctionSummaryMap(
2786 "rmdir", Signature(ArgTypes{ConstCharPtrTy}, RetType{IntTy}),
2787 Summary(NoEvalCall)
2788 .Case(CS: ReturnsZero, ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
2789 .Case(CS: ReturnsMinusOne, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
2790 .ArgConstraint(VC: NotNull(ArgNo(0))));
2791
2792 // int chdir(const char *path);
2793 addToFunctionSummaryMap(
2794 "chdir", Signature(ArgTypes{ConstCharPtrTy}, RetType{IntTy}),
2795 Summary(NoEvalCall)
2796 .Case(CS: ReturnsZero, ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
2797 .Case(CS: ReturnsMinusOne, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
2798 .ArgConstraint(VC: NotNull(ArgNo(0))));
2799
2800 // int link(const char *oldpath, const char *newpath);
2801 addToFunctionSummaryMap(
2802 "link",
2803 Signature(ArgTypes{ConstCharPtrTy, ConstCharPtrTy}, RetType{IntTy}),
2804 Summary(NoEvalCall)
2805 .Case(CS: ReturnsZero, ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
2806 .Case(CS: ReturnsMinusOne, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
2807 .ArgConstraint(VC: NotNull(ArgNo(0)))
2808 .ArgConstraint(VC: NotNull(ArgNo(1))));
2809
2810 // int linkat(int fd1, const char *path1, int fd2, const char *path2,
2811 // int flag);
2812 addToFunctionSummaryMap(
2813 "linkat",
2814 Signature(ArgTypes{IntTy, ConstCharPtrTy, IntTy, ConstCharPtrTy, IntTy},
2815 RetType{IntTy}),
2816 Summary(NoEvalCall)
2817 .Case(CS: ReturnsZero, ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
2818 .Case(CS: ReturnsMinusOne, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
2819 .ArgConstraint(VC: ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2820 .ArgConstraint(VC: NotNull(ArgNo(1)))
2821 .ArgConstraint(VC: ValidFileDescriptorOrAtFdcwd(ArgNo(2)))
2822 .ArgConstraint(VC: NotNull(ArgNo(3))));
2823
2824 // int unlink(const char *pathname);
2825 addToFunctionSummaryMap(
2826 "unlink", Signature(ArgTypes{ConstCharPtrTy}, RetType{IntTy}),
2827 Summary(NoEvalCall)
2828 .Case(CS: ReturnsZero, ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
2829 .Case(CS: ReturnsMinusOne, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
2830 .ArgConstraint(VC: NotNull(ArgNo(0))));
2831
2832 // int unlinkat(int fd, const char *path, int flag);
2833 addToFunctionSummaryMap(
2834 "unlinkat",
2835 Signature(ArgTypes{IntTy, ConstCharPtrTy, IntTy}, RetType{IntTy}),
2836 Summary(NoEvalCall)
2837 .Case(CS: ReturnsZero, ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
2838 .Case(CS: ReturnsMinusOne, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
2839 .ArgConstraint(VC: ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2840 .ArgConstraint(VC: NotNull(ArgNo(1))));
2841
2842 std::optional<QualType> StructStatTy = lookupTy("stat");
2843 std::optional<QualType> StructStatPtrTy = getPointerTy(StructStatTy);
2844 std::optional<QualType> StructStatPtrRestrictTy =
2845 getRestrictTy(StructStatPtrTy);
2846
2847 // int fstat(int fd, struct stat *statbuf);
2848 addToFunctionSummaryMap(
2849 "fstat", Signature(ArgTypes{IntTy, StructStatPtrTy}, RetType{IntTy}),
2850 Summary(NoEvalCall)
2851 .Case(CS: ReturnsZero, ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
2852 .Case(CS: ReturnsMinusOne, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
2853 .ArgConstraint(VC: ArgumentCondition(0, WithinRange, Range(0, IntMax)))
2854 .ArgConstraint(VC: NotNull(ArgNo(1))));
2855
2856 // int stat(const char *restrict path, struct stat *restrict buf);
2857 addToFunctionSummaryMap(
2858 "stat",
2859 Signature(ArgTypes{ConstCharPtrRestrictTy, StructStatPtrRestrictTy},
2860 RetType{IntTy}),
2861 Summary(NoEvalCall)
2862 .Case(CS: ReturnsZero, ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
2863 .Case(CS: ReturnsMinusOne, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
2864 .ArgConstraint(VC: NotNull(ArgNo(0)))
2865 .ArgConstraint(VC: NotNull(ArgNo(1))));
2866
2867 // int lstat(const char *restrict path, struct stat *restrict buf);
2868 addToFunctionSummaryMap(
2869 "lstat",
2870 Signature(ArgTypes{ConstCharPtrRestrictTy, StructStatPtrRestrictTy},
2871 RetType{IntTy}),
2872 Summary(NoEvalCall)
2873 .Case(CS: ReturnsZero, ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
2874 .Case(CS: ReturnsMinusOne, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
2875 .ArgConstraint(VC: NotNull(ArgNo(0)))
2876 .ArgConstraint(VC: NotNull(ArgNo(1))));
2877
2878 // int fstatat(int fd, const char *restrict path,
2879 // struct stat *restrict buf, int flag);
2880 addToFunctionSummaryMap(
2881 "fstatat",
2882 Signature(ArgTypes{IntTy, ConstCharPtrRestrictTy,
2883 StructStatPtrRestrictTy, IntTy},
2884 RetType{IntTy}),
2885 Summary(NoEvalCall)
2886 .Case(CS: ReturnsZero, ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
2887 .Case(CS: ReturnsMinusOne, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
2888 .ArgConstraint(VC: ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2889 .ArgConstraint(VC: NotNull(ArgNo(1)))
2890 .ArgConstraint(VC: NotNull(ArgNo(2))));
2891
2892 // DIR *opendir(const char *name);
2893 addToFunctionSummaryMap(
2894 "opendir", Signature(ArgTypes{ConstCharPtrTy}, RetType{DirPtrTy}),
2895 Summary(NoEvalCall)
2896 .Case(CS: {NotNull(Ret)}, ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
2897 .Case(CS: {IsNull(Ret)}, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
2898 .ArgConstraint(VC: NotNull(ArgNo(0))));
2899
2900 // DIR *fdopendir(int fd);
2901 addToFunctionSummaryMap(
2902 "fdopendir", Signature(ArgTypes{IntTy}, RetType{DirPtrTy}),
2903 Summary(NoEvalCall)
2904 .Case(CS: {NotNull(Ret)}, ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
2905 .Case(CS: {IsNull(Ret)}, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
2906 .ArgConstraint(
2907 VC: ArgumentCondition(0, WithinRange, Range(0, IntMax))));
2908
2909 // int isatty(int fildes);
2910 addToFunctionSummaryMap(
2911 "isatty", Signature(ArgTypes{IntTy}, RetType{IntTy}),
2912 Summary(NoEvalCall)
2913 .Case(CS: {ReturnValueCondition(WithinRange, Range(0, 1))},
2914 ErrnoC: ErrnoIrrelevant)
2915 .ArgConstraint(
2916 VC: ArgumentCondition(0, WithinRange, Range(0, IntMax))));
2917
2918 // int close(int fildes);
2919 addToFunctionSummaryMap(
2920 "close", Signature(ArgTypes{IntTy}, RetType{IntTy}),
2921 Summary(NoEvalCall)
2922 .Case(CS: ReturnsZero, ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
2923 .Case(CS: ReturnsMinusOne, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
2924 .ArgConstraint(
2925 VC: ArgumentCondition(0, WithinRange, Range(-1, IntMax))));
2926
2927 // long fpathconf(int fildes, int name);
2928 addToFunctionSummaryMap("fpathconf",
2929 Signature(ArgTypes{IntTy, IntTy}, RetType{LongTy}),
2930 Summary(NoEvalCall)
2931 .ArgConstraint(VC: ArgumentCondition(
2932 0, WithinRange, Range(0, IntMax))));
2933
2934 // long pathconf(const char *path, int name);
2935 addToFunctionSummaryMap(
2936 "pathconf", Signature(ArgTypes{ConstCharPtrTy, IntTy}, RetType{LongTy}),
2937 Summary(NoEvalCall).ArgConstraint(VC: NotNull(ArgNo(0))));
2938
2939 // void rewinddir(DIR *dir);
2940 addToFunctionSummaryMap(
2941 "rewinddir", Signature(ArgTypes{DirPtrTy}, RetType{VoidTy}),
2942 Summary(NoEvalCall).ArgConstraint(VC: NotNull(ArgNo(0))));
2943
2944 // void seekdir(DIR *dirp, long loc);
2945 addToFunctionSummaryMap(
2946 "seekdir", Signature(ArgTypes{DirPtrTy, LongTy}, RetType{VoidTy}),
2947 Summary(NoEvalCall).ArgConstraint(VC: NotNull(ArgNo(0))));
2948
2949 // int rand_r(unsigned int *seedp);
2950 addToFunctionSummaryMap(
2951 "rand_r", Signature(ArgTypes{UnsignedIntPtrTy}, RetType{IntTy}),
2952 Summary(NoEvalCall).ArgConstraint(VC: NotNull(ArgNo(0))));
2953
2954 // void *mmap(void *addr, size_t length, int prot, int flags, int fd,
2955 // off_t offset);
2956 // FIXME: Improve for errno modeling.
2957 addToFunctionSummaryMap(
2958 "mmap",
2959 Signature(
2960 ArgTypes{VoidPtrTy, SizeTyCanonTy, IntTy, IntTy, IntTy, Off_tTy},
2961 RetType{VoidPtrTy}),
2962 Summary(NoEvalCall)
2963 .ArgConstraint(VC: ArgumentCondition(1, WithinRange, Range(1, SizeMax)))
2964 .ArgConstraint(
2965 VC: ArgumentCondition(4, WithinRange, Range(-1, IntMax))));
2966
2967 std::optional<QualType> Off64_tTy = lookupTy("off64_t");
2968 // void *mmap64(void *addr, size_t length, int prot, int flags, int fd,
2969 // off64_t offset);
2970 // FIXME: Improve for errno modeling.
2971 addToFunctionSummaryMap(
2972 "mmap64",
2973 Signature(
2974 ArgTypes{VoidPtrTy, SizeTyCanonTy, IntTy, IntTy, IntTy, Off64_tTy},
2975 RetType{VoidPtrTy}),
2976 Summary(NoEvalCall)
2977 .ArgConstraint(VC: ArgumentCondition(1, WithinRange, Range(1, SizeMax)))
2978 .ArgConstraint(
2979 VC: ArgumentCondition(4, WithinRange, Range(-1, IntMax))));
2980
2981 // int pipe(int fildes[2]);
2982 addToFunctionSummaryMap(
2983 "pipe", Signature(ArgTypes{IntPtrTy}, RetType{IntTy}),
2984 Summary(NoEvalCall)
2985 .Case(CS: ReturnsZero, ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
2986 .Case(CS: ReturnsMinusOne, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
2987 .ArgConstraint(VC: NotNull(ArgNo(0))));
2988
2989 // off_t lseek(int fildes, off_t offset, int whence);
2990 // In the first case we can not tell for sure if it failed or not.
2991 // A return value different from of the expected offset (that is unknown
2992 // here) may indicate failure. For this reason we do not enforce the errno
2993 // check (can cause false positive).
2994 addToFunctionSummaryMap(
2995 "lseek", Signature(ArgTypes{IntTy, Off_tTy, IntTy}, RetType{Off_tTy}),
2996 Summary(NoEvalCall)
2997 .Case(CS: ReturnsNonnegative, ErrnoC: ErrnoIrrelevant)
2998 .Case(CS: ReturnsMinusOne, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
2999 .ArgConstraint(
3000 VC: ArgumentCondition(0, WithinRange, Range(0, IntMax))));
3001
3002 // ssize_t readlink(const char *restrict path, char *restrict buf,
3003 // size_t bufsize);
3004 addToFunctionSummaryMap(
3005 "readlink",
3006 Signature(
3007 ArgTypes{ConstCharPtrRestrictTy, CharPtrRestrictTy, SizeTyCanonTy},
3008 RetType{Ssize_tTy}),
3009 Summary(NoEvalCall)
3010 .Case(CS: {ArgumentCondition(2, WithinRange, Range(1, IntMax)),
3011 ReturnValueCondition(LessThanOrEq, ArgNo(2)),
3012 ReturnValueCondition(WithinRange, Range(1, Ssize_tMax))},
3013 ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
3014 .Case(CS: {ArgumentCondition(2, WithinRange, SingleValue(0)),
3015 ReturnValueCondition(WithinRange, SingleValue(0))},
3016 ErrnoC: ErrnoMustNotBeChecked,
3017 Note: "Assuming that argument 'bufsize' is 0")
3018 .Case(CS: ReturnsMinusOne, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
3019 .ArgConstraint(VC: NotNull(ArgNo(0)))
3020 .ArgConstraint(VC: NotNull(ArgNo(1)))
3021 .ArgConstraint(VC: BufferSize(/*Buffer=*/ArgNo(1),
3022 /*BufSize=*/ArgNo(2)))
3023 .ArgConstraint(
3024 VC: ArgumentCondition(2, WithinRange, Range(0, SizeMax))));
3025
3026 // ssize_t readlinkat(int fd, const char *restrict path,
3027 // char *restrict buf, size_t bufsize);
3028 addToFunctionSummaryMap(
3029 "readlinkat",
3030 Signature(ArgTypes{IntTy, ConstCharPtrRestrictTy, CharPtrRestrictTy,
3031 SizeTyCanonTy},
3032 RetType{Ssize_tTy}),
3033 Summary(NoEvalCall)
3034 .Case(CS: {ArgumentCondition(3, WithinRange, Range(1, IntMax)),
3035 ReturnValueCondition(LessThanOrEq, ArgNo(3)),
3036 ReturnValueCondition(WithinRange, Range(1, Ssize_tMax))},
3037 ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
3038 .Case(CS: {ArgumentCondition(3, WithinRange, SingleValue(0)),
3039 ReturnValueCondition(WithinRange, SingleValue(0))},
3040 ErrnoC: ErrnoMustNotBeChecked,
3041 Note: "Assuming that argument 'bufsize' is 0")
3042 .Case(CS: ReturnsMinusOne, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
3043 .ArgConstraint(VC: ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
3044 .ArgConstraint(VC: NotNull(ArgNo(1)))
3045 .ArgConstraint(VC: NotNull(ArgNo(2)))
3046 .ArgConstraint(VC: BufferSize(/*Buffer=*/ArgNo(2),
3047 /*BufSize=*/ArgNo(3)))
3048 .ArgConstraint(
3049 VC: ArgumentCondition(3, WithinRange, Range(0, SizeMax))));
3050
3051 // int renameat(int olddirfd, const char *oldpath, int newdirfd, const char
3052 // *newpath);
3053 addToFunctionSummaryMap(
3054 "renameat",
3055 Signature(ArgTypes{IntTy, ConstCharPtrTy, IntTy, ConstCharPtrTy},
3056 RetType{IntTy}),
3057 Summary(NoEvalCall)
3058 .Case(CS: ReturnsZero, ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
3059 .Case(CS: ReturnsMinusOne, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
3060 .ArgConstraint(VC: ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
3061 .ArgConstraint(VC: NotNull(ArgNo(1)))
3062 .ArgConstraint(VC: ValidFileDescriptorOrAtFdcwd(ArgNo(2)))
3063 .ArgConstraint(VC: NotNull(ArgNo(3))));
3064
3065 // char *realpath(const char *restrict file_name,
3066 // char *restrict resolved_name);
3067 // FIXME: If the argument 'resolved_name' is not NULL, macro 'PATH_MAX'
3068 // should be defined in "limits.h" to guarrantee a success.
3069 addToFunctionSummaryMap(
3070 "realpath",
3071 Signature(ArgTypes{ConstCharPtrRestrictTy, CharPtrRestrictTy},
3072 RetType{CharPtrTy}),
3073 Summary(NoEvalCall)
3074 .Case(CS: {NotNull(Ret)}, ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
3075 .Case(CS: {IsNull(Ret)}, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
3076 .ArgConstraint(VC: NotNull(ArgNo(0))));
3077
3078 QualType CharPtrConstPtr = getPointerTy(getConstTy(CharPtrTy));
3079
3080 // int execv(const char *path, char *const argv[]);
3081 addToFunctionSummaryMap(
3082 "execv",
3083 Signature(ArgTypes{ConstCharPtrTy, CharPtrConstPtr}, RetType{IntTy}),
3084 Summary(NoEvalCall)
3085 .Case(CS: ReturnsMinusOne, ErrnoC: ErrnoNEZeroIrrelevant)
3086 .ArgConstraint(VC: NotNull(ArgNo(0))));
3087
3088 // int execvp(const char *file, char *const argv[]);
3089 addToFunctionSummaryMap(
3090 "execvp",
3091 Signature(ArgTypes{ConstCharPtrTy, CharPtrConstPtr}, RetType{IntTy}),
3092 Summary(NoEvalCall)
3093 .Case(CS: ReturnsMinusOne, ErrnoC: ErrnoNEZeroIrrelevant)
3094 .ArgConstraint(VC: NotNull(ArgNo(0))));
3095
3096 // int getopt(int argc, char * const argv[], const char *optstring);
3097 addToFunctionSummaryMap(
3098 "getopt",
3099 Signature(ArgTypes{IntTy, CharPtrConstPtr, ConstCharPtrTy},
3100 RetType{IntTy}),
3101 Summary(NoEvalCall)
3102 .Case(CS: {ReturnValueCondition(WithinRange, Range(-1, UCharRangeMax))},
3103 ErrnoC: ErrnoIrrelevant)
3104 .ArgConstraint(VC: ArgumentCondition(0, WithinRange, Range(0, IntMax)))
3105 .ArgConstraint(VC: NotNull(ArgNo(1)))
3106 .ArgConstraint(VC: NotNull(ArgNo(2))));
3107
3108 std::optional<QualType> StructSockaddrTy = lookupTy("sockaddr");
3109 std::optional<QualType> StructSockaddrPtrTy =
3110 getPointerTy(StructSockaddrTy);
3111 std::optional<QualType> ConstStructSockaddrPtrTy =
3112 getPointerTy(getConstTy(StructSockaddrTy));
3113 std::optional<QualType> StructSockaddrPtrRestrictTy =
3114 getRestrictTy(StructSockaddrPtrTy);
3115 std::optional<QualType> ConstStructSockaddrPtrRestrictTy =
3116 getRestrictTy(ConstStructSockaddrPtrTy);
3117 std::optional<QualType> Socklen_tTy = lookupTy("socklen_t");
3118 std::optional<QualType> Socklen_tPtrTy = getPointerTy(Socklen_tTy);
3119 std::optional<QualType> Socklen_tPtrRestrictTy =
3120 getRestrictTy(Socklen_tPtrTy);
3121 std::optional<RangeInt> Socklen_tMax = getMaxValue(Socklen_tTy);
3122
3123 // In 'socket.h' of some libc implementations with C99, sockaddr parameter
3124 // is a transparent union of the underlying sockaddr_ family of pointers
3125 // instead of being a pointer to struct sockaddr. In these cases, the
3126 // standardized signature will not match, thus we try to match with another
3127 // signature that has the joker Irrelevant type. We also remove those
3128 // constraints which require pointer types for the sockaddr param.
3129
3130 // int socket(int domain, int type, int protocol);
3131 addToFunctionSummaryMap(
3132 "socket", Signature(ArgTypes{IntTy, IntTy, IntTy}, RetType{IntTy}),
3133 Summary(NoEvalCall)
3134 .Case(CS: ReturnsValidFileDescriptor, ErrnoC: ErrnoMustNotBeChecked,
3135 Note: GenericSuccessMsg)
3136 .Case(CS: ReturnsMinusOne, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg));
3137
3138 auto Accept =
3139 Summary(NoEvalCall)
3140 .Case(CS: ReturnsValidFileDescriptor, ErrnoC: ErrnoMustNotBeChecked,
3141 Note: GenericSuccessMsg)
3142 .Case(CS: ReturnsMinusOne, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
3143 .ArgConstraint(VC: ArgumentCondition(0, WithinRange, Range(0, IntMax)));
3144 if (!addToFunctionSummaryMap(
3145 "accept",
3146 // int accept(int socket, struct sockaddr *restrict address,
3147 // socklen_t *restrict address_len);
3148 Signature(ArgTypes{IntTy, StructSockaddrPtrRestrictTy,
3149 Socklen_tPtrRestrictTy},
3150 RetType{IntTy}),
3151 Accept))
3152 addToFunctionSummaryMap(
3153 "accept",
3154 Signature(ArgTypes{IntTy, Irrelevant, Socklen_tPtrRestrictTy},
3155 RetType{IntTy}),
3156 Accept);
3157
3158 // int bind(int socket, const struct sockaddr *address, socklen_t
3159 // address_len);
3160 if (!addToFunctionSummaryMap(
3161 "bind",
3162 Signature(ArgTypes{IntTy, ConstStructSockaddrPtrTy, Socklen_tTy},
3163 RetType{IntTy}),
3164 Summary(NoEvalCall)
3165 .Case(CS: ReturnsZero, ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
3166 .Case(CS: ReturnsMinusOne, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
3167 .ArgConstraint(
3168 VC: ArgumentCondition(0, WithinRange, Range(0, IntMax)))
3169 .ArgConstraint(VC: NotNull(ArgNo(1)))
3170 .ArgConstraint(
3171 VC: BufferSize(/*Buffer=*/ArgNo(1), /*BufSize=*/ArgNo(2)))
3172 .ArgConstraint(
3173 VC: ArgumentCondition(2, WithinRange, Range(0, Socklen_tMax)))))
3174 // Do not add constraints on sockaddr.
3175 addToFunctionSummaryMap(
3176 "bind",
3177 Signature(ArgTypes{IntTy, Irrelevant, Socklen_tTy}, RetType{IntTy}),
3178 Summary(NoEvalCall)
3179 .Case(CS: ReturnsZero, ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
3180 .Case(CS: ReturnsMinusOne, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
3181 .ArgConstraint(
3182 VC: ArgumentCondition(0, WithinRange, Range(0, IntMax)))
3183 .ArgConstraint(
3184 VC: ArgumentCondition(2, WithinRange, Range(0, Socklen_tMax))));
3185
3186 // int getpeername(int socket, struct sockaddr *restrict address,
3187 // socklen_t *restrict address_len);
3188 if (!addToFunctionSummaryMap(
3189 "getpeername",
3190 Signature(ArgTypes{IntTy, StructSockaddrPtrRestrictTy,
3191 Socklen_tPtrRestrictTy},
3192 RetType{IntTy}),
3193 Summary(NoEvalCall)
3194 .Case(CS: ReturnsZero, ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
3195 .Case(CS: ReturnsMinusOne, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
3196 .ArgConstraint(
3197 VC: ArgumentCondition(0, WithinRange, Range(0, IntMax)))
3198 .ArgConstraint(VC: NotNull(ArgNo(1)))
3199 .ArgConstraint(VC: NotNull(ArgNo(2)))))
3200 addToFunctionSummaryMap(
3201 "getpeername",
3202 Signature(ArgTypes{IntTy, Irrelevant, Socklen_tPtrRestrictTy},
3203 RetType{IntTy}),
3204 Summary(NoEvalCall)
3205 .Case(CS: ReturnsZero, ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
3206 .Case(CS: ReturnsMinusOne, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
3207 .ArgConstraint(
3208 VC: ArgumentCondition(0, WithinRange, Range(0, IntMax))));
3209
3210 // int getsockname(int socket, struct sockaddr *restrict address,
3211 // socklen_t *restrict address_len);
3212 if (!addToFunctionSummaryMap(
3213 "getsockname",
3214 Signature(ArgTypes{IntTy, StructSockaddrPtrRestrictTy,
3215 Socklen_tPtrRestrictTy},
3216 RetType{IntTy}),
3217 Summary(NoEvalCall)
3218 .Case(CS: ReturnsZero, ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
3219 .Case(CS: ReturnsMinusOne, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
3220 .ArgConstraint(
3221 VC: ArgumentCondition(0, WithinRange, Range(0, IntMax)))
3222 .ArgConstraint(VC: NotNull(ArgNo(1)))
3223 .ArgConstraint(VC: NotNull(ArgNo(2)))))
3224 addToFunctionSummaryMap(
3225 "getsockname",
3226 Signature(ArgTypes{IntTy, Irrelevant, Socklen_tPtrRestrictTy},
3227 RetType{IntTy}),
3228 Summary(NoEvalCall)
3229 .Case(CS: ReturnsZero, ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
3230 .Case(CS: ReturnsMinusOne, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
3231 .ArgConstraint(
3232 VC: ArgumentCondition(0, WithinRange, Range(0, IntMax))));
3233
3234 // int connect(int socket, const struct sockaddr *address, socklen_t
3235 // address_len);
3236 if (!addToFunctionSummaryMap(
3237 "connect",
3238 Signature(ArgTypes{IntTy, ConstStructSockaddrPtrTy, Socklen_tTy},
3239 RetType{IntTy}),
3240 Summary(NoEvalCall)
3241 .Case(CS: ReturnsZero, ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
3242 .Case(CS: ReturnsMinusOne, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
3243 .ArgConstraint(
3244 VC: ArgumentCondition(0, WithinRange, Range(0, IntMax)))
3245 .ArgConstraint(VC: NotNull(ArgNo(1)))))
3246 addToFunctionSummaryMap(
3247 "connect",
3248 Signature(ArgTypes{IntTy, Irrelevant, Socklen_tTy}, RetType{IntTy}),
3249 Summary(NoEvalCall)
3250 .Case(CS: ReturnsZero, ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
3251 .Case(CS: ReturnsMinusOne, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
3252 .ArgConstraint(
3253 VC: ArgumentCondition(0, WithinRange, Range(0, IntMax))));
3254
3255 auto Recvfrom =
3256 Summary(NoEvalCall)
3257 .Case(CS: {ReturnValueCondition(LessThanOrEq, ArgNo(2)),
3258 ReturnValueCondition(WithinRange, Range(1, Ssize_tMax))},
3259 ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
3260 .Case(CS: {ReturnValueCondition(WithinRange, SingleValue(0)),
3261 ArgumentCondition(2, WithinRange, SingleValue(0))},
3262 ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
3263 .Case(CS: ReturnsMinusOne, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
3264 .ArgConstraint(VC: ArgumentCondition(0, WithinRange, Range(0, IntMax)))
3265 .ArgConstraint(VC: BufferSize(/*Buffer=*/ArgNo(1),
3266 /*BufSize=*/ArgNo(2)));
3267 if (!addToFunctionSummaryMap(
3268 "recvfrom",
3269 // ssize_t recvfrom(int socket, void *restrict buffer,
3270 // size_t length,
3271 // int flags, struct sockaddr *restrict address,
3272 // socklen_t *restrict address_len);
3273 Signature(ArgTypes{IntTy, VoidPtrRestrictTy, SizeTyCanonTy, IntTy,
3274 StructSockaddrPtrRestrictTy,
3275 Socklen_tPtrRestrictTy},
3276 RetType{Ssize_tTy}),
3277 Recvfrom))
3278 addToFunctionSummaryMap(
3279 "recvfrom",
3280 Signature(ArgTypes{IntTy, VoidPtrRestrictTy, SizeTyCanonTy, IntTy,
3281 Irrelevant, Socklen_tPtrRestrictTy},
3282 RetType{Ssize_tTy}),
3283 Recvfrom);
3284
3285 auto Sendto =
3286 Summary(NoEvalCall)
3287 .Case(CS: {ReturnValueCondition(LessThanOrEq, ArgNo(2)),
3288 ReturnValueCondition(WithinRange, Range(1, Ssize_tMax))},
3289 ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
3290 .Case(CS: {ReturnValueCondition(WithinRange, SingleValue(0)),
3291 ArgumentCondition(2, WithinRange, SingleValue(0))},
3292 ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
3293 .Case(CS: ReturnsMinusOne, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
3294 .ArgConstraint(VC: ArgumentCondition(0, WithinRange, Range(0, IntMax)))
3295 .ArgConstraint(VC: BufferSize(/*Buffer=*/ArgNo(1),
3296 /*BufSize=*/ArgNo(2)));
3297 if (!addToFunctionSummaryMap(
3298 "sendto",
3299 // ssize_t sendto(int socket, const void *message, size_t length,
3300 // int flags, const struct sockaddr *dest_addr,
3301 // socklen_t dest_len);
3302 Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTyCanonTy, IntTy,
3303 ConstStructSockaddrPtrTy, Socklen_tTy},
3304 RetType{Ssize_tTy}),
3305 Sendto))
3306 addToFunctionSummaryMap(
3307 "sendto",
3308 Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTyCanonTy, IntTy,
3309 Irrelevant, Socklen_tTy},
3310 RetType{Ssize_tTy}),
3311 Sendto);
3312
3313 // int listen(int sockfd, int backlog);
3314 addToFunctionSummaryMap(
3315 "listen", Signature(ArgTypes{IntTy, IntTy}, RetType{IntTy}),
3316 Summary(NoEvalCall)
3317 .Case(CS: ReturnsZero, ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
3318 .Case(CS: ReturnsMinusOne, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
3319 .ArgConstraint(
3320 VC: ArgumentCondition(0, WithinRange, Range(0, IntMax))));
3321
3322 // ssize_t recv(int sockfd, void *buf, size_t len, int flags);
3323 addToFunctionSummaryMap(
3324 "recv",
3325 Signature(ArgTypes{IntTy, VoidPtrTy, SizeTyCanonTy, IntTy},
3326 RetType{Ssize_tTy}),
3327 Summary(NoEvalCall)
3328 .Case(CS: {ReturnValueCondition(LessThanOrEq, ArgNo(2)),
3329 ReturnValueCondition(WithinRange, Range(1, Ssize_tMax))},
3330 ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
3331 .Case(CS: {ReturnValueCondition(WithinRange, SingleValue(0)),
3332 ArgumentCondition(2, WithinRange, SingleValue(0))},
3333 ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
3334 .Case(CS: ReturnsMinusOne, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
3335 .ArgConstraint(VC: ArgumentCondition(0, WithinRange, Range(0, IntMax)))
3336 .ArgConstraint(VC: BufferSize(/*Buffer=*/ArgNo(1),
3337 /*BufSize=*/ArgNo(2))));
3338
3339 std::optional<QualType> StructMsghdrTy = lookupTy("msghdr");
3340 std::optional<QualType> StructMsghdrPtrTy = getPointerTy(StructMsghdrTy);
3341 std::optional<QualType> ConstStructMsghdrPtrTy =
3342 getPointerTy(getConstTy(StructMsghdrTy));
3343
3344 // ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);
3345 addToFunctionSummaryMap(
3346 "recvmsg",
3347 Signature(ArgTypes{IntTy, StructMsghdrPtrTy, IntTy},
3348 RetType{Ssize_tTy}),
3349 Summary(NoEvalCall)
3350 .Case(CS: {ReturnValueCondition(WithinRange, Range(1, Ssize_tMax))},
3351 ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
3352 .Case(CS: ReturnsMinusOne, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
3353 .ArgConstraint(
3354 VC: ArgumentCondition(0, WithinRange, Range(0, IntMax))));
3355
3356 // ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
3357 addToFunctionSummaryMap(
3358 "sendmsg",
3359 Signature(ArgTypes{IntTy, ConstStructMsghdrPtrTy, IntTy},
3360 RetType{Ssize_tTy}),
3361 Summary(NoEvalCall)
3362 .Case(CS: {ReturnValueCondition(WithinRange, Range(1, Ssize_tMax))},
3363 ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
3364 .Case(CS: ReturnsMinusOne, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
3365 .ArgConstraint(
3366 VC: ArgumentCondition(0, WithinRange, Range(0, IntMax))));
3367
3368 // int setsockopt(int socket, int level, int option_name,
3369 // const void *option_value, socklen_t option_len);
3370 addToFunctionSummaryMap(
3371 "setsockopt",
3372 Signature(ArgTypes{IntTy, IntTy, IntTy, ConstVoidPtrTy, Socklen_tTy},
3373 RetType{IntTy}),
3374 Summary(NoEvalCall)
3375 .Case(CS: ReturnsZero, ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
3376 .Case(CS: ReturnsMinusOne, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
3377 .ArgConstraint(VC: NotNullBuffer(ArgNo(3), ArgNo(4)))
3378 .ArgConstraint(
3379 VC: BufferSize(/*Buffer=*/ArgNo(3), /*BufSize=*/ArgNo(4)))
3380 .ArgConstraint(
3381 VC: ArgumentCondition(4, WithinRange, Range(0, Socklen_tMax))));
3382
3383 // int getsockopt(int socket, int level, int option_name,
3384 // void *restrict option_value,
3385 // socklen_t *restrict option_len);
3386 addToFunctionSummaryMap(
3387 "getsockopt",
3388 Signature(ArgTypes{IntTy, IntTy, IntTy, VoidPtrRestrictTy,
3389 Socklen_tPtrRestrictTy},
3390 RetType{IntTy}),
3391 Summary(NoEvalCall)
3392 .Case(CS: ReturnsZero, ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
3393 .Case(CS: ReturnsMinusOne, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
3394 .ArgConstraint(VC: NotNull(ArgNo(3)))
3395 .ArgConstraint(VC: NotNull(ArgNo(4))));
3396
3397 // ssize_t send(int sockfd, const void *buf, size_t len, int flags);
3398 addToFunctionSummaryMap(
3399 "send",
3400 Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTyCanonTy, IntTy},
3401 RetType{Ssize_tTy}),
3402 Summary(NoEvalCall)
3403 .Case(CS: {ReturnValueCondition(LessThanOrEq, ArgNo(2)),
3404 ReturnValueCondition(WithinRange, Range(1, Ssize_tMax))},
3405 ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
3406 .Case(CS: {ReturnValueCondition(WithinRange, SingleValue(0)),
3407 ArgumentCondition(2, WithinRange, SingleValue(0))},
3408 ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
3409 .Case(CS: ReturnsMinusOne, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
3410 .ArgConstraint(VC: ArgumentCondition(0, WithinRange, Range(0, IntMax)))
3411 .ArgConstraint(VC: BufferSize(/*Buffer=*/ArgNo(1),
3412 /*BufSize=*/ArgNo(2))));
3413
3414 // int socketpair(int domain, int type, int protocol, int sv[2]);
3415 addToFunctionSummaryMap(
3416 "socketpair",
3417 Signature(ArgTypes{IntTy, IntTy, IntTy, IntPtrTy}, RetType{IntTy}),
3418 Summary(NoEvalCall)
3419 .Case(CS: ReturnsZero, ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
3420 .Case(CS: ReturnsMinusOne, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
3421 .ArgConstraint(VC: NotNull(ArgNo(3))));
3422
3423 // int shutdown(int socket, int how);
3424 addToFunctionSummaryMap(
3425 "shutdown", Signature(ArgTypes{IntTy, IntTy}, RetType{IntTy}),
3426 Summary(NoEvalCall)
3427 .Case(CS: ReturnsZero, ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
3428 .Case(CS: ReturnsMinusOne, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
3429 .ArgConstraint(
3430 VC: ArgumentCondition(0, WithinRange, Range(0, IntMax))));
3431
3432 // int getnameinfo(const struct sockaddr *restrict sa, socklen_t salen,
3433 // char *restrict node, socklen_t nodelen,
3434 // char *restrict service,
3435 // socklen_t servicelen, int flags);
3436 //
3437 // This is defined in netdb.h. And contrary to 'socket.h', the sockaddr
3438 // parameter is never handled as a transparent union in netdb.h
3439 addToFunctionSummaryMap(
3440 "getnameinfo",
3441 Signature(ArgTypes{ConstStructSockaddrPtrRestrictTy, Socklen_tTy,
3442 CharPtrRestrictTy, Socklen_tTy, CharPtrRestrictTy,
3443 Socklen_tTy, IntTy},
3444 RetType{IntTy}),
3445 Summary(NoEvalCall)
3446 .ArgConstraint(
3447 VC: BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1)))
3448 .ArgConstraint(
3449 VC: ArgumentCondition(1, WithinRange, Range(0, Socklen_tMax)))
3450 .ArgConstraint(
3451 VC: BufferSize(/*Buffer=*/ArgNo(2), /*BufSize=*/ArgNo(3)))
3452 .ArgConstraint(
3453 VC: ArgumentCondition(3, WithinRange, Range(0, Socklen_tMax)))
3454 .ArgConstraint(
3455 VC: BufferSize(/*Buffer=*/ArgNo(4), /*BufSize=*/ArgNo(5)))
3456 .ArgConstraint(
3457 VC: ArgumentCondition(5, WithinRange, Range(0, Socklen_tMax))));
3458
3459 std::optional<QualType> StructUtimbufTy = lookupTy("utimbuf");
3460 std::optional<QualType> StructUtimbufPtrTy = getPointerTy(StructUtimbufTy);
3461
3462 // int utime(const char *filename, struct utimbuf *buf);
3463 addToFunctionSummaryMap(
3464 "utime",
3465 Signature(ArgTypes{ConstCharPtrTy, StructUtimbufPtrTy}, RetType{IntTy}),
3466 Summary(NoEvalCall)
3467 .Case(CS: ReturnsZero, ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
3468 .Case(CS: ReturnsMinusOne, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
3469 .ArgConstraint(VC: NotNull(ArgNo(0))));
3470
3471 std::optional<QualType> StructTimespecTy = lookupTy("timespec");
3472 std::optional<QualType> StructTimespecPtrTy =
3473 getPointerTy(StructTimespecTy);
3474 std::optional<QualType> ConstStructTimespecPtrTy =
3475 getPointerTy(getConstTy(StructTimespecTy));
3476
3477 // int futimens(int fd, const struct timespec times[2]);
3478 addToFunctionSummaryMap(
3479 "futimens",
3480 Signature(ArgTypes{IntTy, ConstStructTimespecPtrTy}, RetType{IntTy}),
3481 Summary(NoEvalCall)
3482 .Case(CS: ReturnsZero, ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
3483 .Case(CS: ReturnsMinusOne, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
3484 .ArgConstraint(
3485 VC: ArgumentCondition(0, WithinRange, Range(0, IntMax))));
3486
3487 // int utimensat(int dirfd, const char *pathname,
3488 // const struct timespec times[2], int flags);
3489 addToFunctionSummaryMap(
3490 "utimensat",
3491 Signature(
3492 ArgTypes{IntTy, ConstCharPtrTy, ConstStructTimespecPtrTy, IntTy},
3493 RetType{IntTy}),
3494 Summary(NoEvalCall)
3495 .Case(CS: ReturnsZero, ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
3496 .Case(CS: ReturnsMinusOne, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
3497 .ArgConstraint(VC: NotNull(ArgNo(1))));
3498
3499 std::optional<QualType> StructTimevalTy = lookupTy("timeval");
3500 std::optional<QualType> ConstStructTimevalPtrTy =
3501 getPointerTy(getConstTy(StructTimevalTy));
3502
3503 // int utimes(const char *filename, const struct timeval times[2]);
3504 addToFunctionSummaryMap(
3505 "utimes",
3506 Signature(ArgTypes{ConstCharPtrTy, ConstStructTimevalPtrTy},
3507 RetType{IntTy}),
3508 Summary(NoEvalCall)
3509 .Case(CS: ReturnsZero, ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
3510 .Case(CS: ReturnsMinusOne, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
3511 .ArgConstraint(VC: NotNull(ArgNo(0))));
3512
3513 // int nanosleep(const struct timespec *rqtp, struct timespec *rmtp);
3514 addToFunctionSummaryMap(
3515 "nanosleep",
3516 Signature(ArgTypes{ConstStructTimespecPtrTy, StructTimespecPtrTy},
3517 RetType{IntTy}),
3518 Summary(NoEvalCall)
3519 .Case(CS: ReturnsZero, ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
3520 .Case(CS: ReturnsMinusOne, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
3521 .ArgConstraint(VC: NotNull(ArgNo(0))));
3522
3523 std::optional<QualType> Time_tTy = lookupTy("time_t");
3524 std::optional<QualType> ConstTime_tPtrTy =
3525 getPointerTy(getConstTy(Time_tTy));
3526 std::optional<QualType> ConstTime_tPtrRestrictTy =
3527 getRestrictTy(ConstTime_tPtrTy);
3528
3529 std::optional<QualType> StructTmTy = lookupTy("tm");
3530 std::optional<QualType> StructTmPtrTy = getPointerTy(StructTmTy);
3531 std::optional<QualType> StructTmPtrRestrictTy =
3532 getRestrictTy(StructTmPtrTy);
3533 std::optional<QualType> ConstStructTmPtrTy =
3534 getPointerTy(getConstTy(StructTmTy));
3535 std::optional<QualType> ConstStructTmPtrRestrictTy =
3536 getRestrictTy(ConstStructTmPtrTy);
3537
3538 // struct tm * localtime(const time_t *tp);
3539 addToFunctionSummaryMap(
3540 "localtime",
3541 Signature(ArgTypes{ConstTime_tPtrTy}, RetType{StructTmPtrTy}),
3542 Summary(NoEvalCall).ArgConstraint(VC: NotNull(ArgNo(0))));
3543
3544 // struct tm *localtime_r(const time_t *restrict timer,
3545 // struct tm *restrict result);
3546 addToFunctionSummaryMap(
3547 "localtime_r",
3548 Signature(ArgTypes{ConstTime_tPtrRestrictTy, StructTmPtrRestrictTy},
3549 RetType{StructTmPtrTy}),
3550 Summary(NoEvalCall)
3551 .ArgConstraint(VC: NotNull(ArgNo(0)))
3552 .ArgConstraint(VC: NotNull(ArgNo(1))));
3553
3554 // char *asctime_r(const struct tm *restrict tm, char *restrict buf);
3555 addToFunctionSummaryMap(
3556 "asctime_r",
3557 Signature(ArgTypes{ConstStructTmPtrRestrictTy, CharPtrRestrictTy},
3558 RetType{CharPtrTy}),
3559 Summary(NoEvalCall)
3560 .ArgConstraint(VC: NotNull(ArgNo(0)))
3561 .ArgConstraint(VC: NotNull(ArgNo(1)))
3562 .ArgConstraint(VC: BufferSize(/*Buffer=*/ArgNo(1),
3563 /*MinBufSize=*/BVF.getValue(X: 26, T: IntTy))));
3564
3565 // char *ctime_r(const time_t *timep, char *buf);
3566 addToFunctionSummaryMap(
3567 "ctime_r",
3568 Signature(ArgTypes{ConstTime_tPtrTy, CharPtrTy}, RetType{CharPtrTy}),
3569 Summary(NoEvalCall)
3570 .ArgConstraint(VC: NotNull(ArgNo(0)))
3571 .ArgConstraint(VC: NotNull(ArgNo(1)))
3572 .ArgConstraint(VC: BufferSize(
3573 /*Buffer=*/ArgNo(1),
3574 /*MinBufSize=*/BVF.getValue(X: 26, T: IntTy))));
3575
3576 // struct tm *gmtime_r(const time_t *restrict timer,
3577 // struct tm *restrict result);
3578 addToFunctionSummaryMap(
3579 "gmtime_r",
3580 Signature(ArgTypes{ConstTime_tPtrRestrictTy, StructTmPtrRestrictTy},
3581 RetType{StructTmPtrTy}),
3582 Summary(NoEvalCall)
3583 .ArgConstraint(VC: NotNull(ArgNo(0)))
3584 .ArgConstraint(VC: NotNull(ArgNo(1))));
3585
3586 // struct tm * gmtime(const time_t *tp);
3587 addToFunctionSummaryMap(
3588 "gmtime", Signature(ArgTypes{ConstTime_tPtrTy}, RetType{StructTmPtrTy}),
3589 Summary(NoEvalCall).ArgConstraint(VC: NotNull(ArgNo(0))));
3590
3591 std::optional<QualType> Clockid_tTy = lookupTy("clockid_t");
3592
3593 // int clock_gettime(clockid_t clock_id, struct timespec *tp);
3594 addToFunctionSummaryMap(
3595 "clock_gettime",
3596 Signature(ArgTypes{Clockid_tTy, StructTimespecPtrTy}, RetType{IntTy}),
3597 Summary(NoEvalCall)
3598 .Case(CS: ReturnsZero, ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
3599 .Case(CS: ReturnsMinusOne, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
3600 .ArgConstraint(VC: NotNull(ArgNo(1))));
3601
3602 std::optional<QualType> StructItimervalTy = lookupTy("itimerval");
3603 std::optional<QualType> StructItimervalPtrTy =
3604 getPointerTy(StructItimervalTy);
3605
3606 // int getitimer(int which, struct itimerval *curr_value);
3607 addToFunctionSummaryMap(
3608 "getitimer",
3609 Signature(ArgTypes{IntTy, StructItimervalPtrTy}, RetType{IntTy}),
3610 Summary(NoEvalCall)
3611 .Case(CS: ReturnsZero, ErrnoC: ErrnoMustNotBeChecked, Note: GenericSuccessMsg)
3612 .Case(CS: ReturnsMinusOne, ErrnoC: ErrnoNEZeroIrrelevant, Note: GenericFailureMsg)
3613 .ArgConstraint(VC: NotNull(ArgNo(1))));
3614
3615 std::optional<QualType> Pthread_cond_tTy = lookupTy("pthread_cond_t");
3616 std::optional<QualType> Pthread_cond_tPtrTy =
3617 getPointerTy(Pthread_cond_tTy);
3618 std::optional<QualType> Pthread_tTy = lookupTy("pthread_t");
3619 std::optional<QualType> Pthread_tPtrTy = getPointerTy(Pthread_tTy);
3620 std::optional<QualType> Pthread_tPtrRestrictTy =
3621 getRestrictTy(Pthread_tPtrTy);
3622 std::optional<QualType> Pthread_mutex_tTy = lookupTy("pthread_mutex_t");
3623 std::optional<QualType> Pthread_mutex_tPtrTy =
3624 getPointerTy(Pthread_mutex_tTy);
3625 std::optional<QualType> Pthread_mutex_tPtrRestrictTy =
3626 getRestrictTy(Pthread_mutex_tPtrTy);
3627 std::optional<QualType> Pthread_attr_tTy = lookupTy("pthread_attr_t");
3628 std::optional<QualType> Pthread_attr_tPtrTy =
3629 getPointerTy(Pthread_attr_tTy);
3630 std::optional<QualType> ConstPthread_attr_tPtrTy =
3631 getPointerTy(getConstTy(Pthread_attr_tTy));
3632 std::optional<QualType> ConstPthread_attr_tPtrRestrictTy =
3633 getRestrictTy(ConstPthread_attr_tPtrTy);
3634 std::optional<QualType> Pthread_mutexattr_tTy =
3635 lookupTy("pthread_mutexattr_t");
3636 std::optional<QualType> ConstPthread_mutexattr_tPtrTy =
3637 getPointerTy(getConstTy(Pthread_mutexattr_tTy));
3638 std::optional<QualType> ConstPthread_mutexattr_tPtrRestrictTy =
3639 getRestrictTy(ConstPthread_mutexattr_tPtrTy);
3640
3641 QualType PthreadStartRoutineTy = getPointerTy(
3642 ACtx.getFunctionType(/*ResultTy=*/VoidPtrTy, /*Args=*/VoidPtrTy,
3643 EPI: FunctionProtoType::ExtProtoInfo()));
3644
3645 // int pthread_cond_signal(pthread_cond_t *cond);
3646 // int pthread_cond_broadcast(pthread_cond_t *cond);
3647 addToFunctionSummaryMap(
3648 {"pthread_cond_signal", "pthread_cond_broadcast"},
3649 Signature(ArgTypes{Pthread_cond_tPtrTy}, RetType{IntTy}),
3650 Summary(NoEvalCall).ArgConstraint(VC: NotNull(ArgNo(0))));
3651
3652 // int pthread_create(pthread_t *restrict thread,
3653 // const pthread_attr_t *restrict attr,
3654 // void *(*start_routine)(void*), void *restrict arg);
3655 addToFunctionSummaryMap(
3656 "pthread_create",
3657 Signature(ArgTypes{Pthread_tPtrRestrictTy,
3658 ConstPthread_attr_tPtrRestrictTy,
3659 PthreadStartRoutineTy, VoidPtrRestrictTy},
3660 RetType{IntTy}),
3661 Summary(NoEvalCall)
3662 .ArgConstraint(VC: NotNull(ArgNo(0)))
3663 .ArgConstraint(VC: NotNull(ArgNo(2))));
3664
3665 // int pthread_attr_destroy(pthread_attr_t *attr);
3666 // int pthread_attr_init(pthread_attr_t *attr);
3667 addToFunctionSummaryMap(
3668 {"pthread_attr_destroy", "pthread_attr_init"},
3669 Signature(ArgTypes{Pthread_attr_tPtrTy}, RetType{IntTy}),
3670 Summary(NoEvalCall).ArgConstraint(VC: NotNull(ArgNo(0))));
3671
3672 // int pthread_attr_getstacksize(const pthread_attr_t *restrict attr,
3673 // size_t *restrict stacksize);
3674 // int pthread_attr_getguardsize(const pthread_attr_t *restrict attr,
3675 // size_t *restrict guardsize);
3676 addToFunctionSummaryMap(
3677 {"pthread_attr_getstacksize", "pthread_attr_getguardsize"},
3678 Signature(ArgTypes{ConstPthread_attr_tPtrRestrictTy, SizePtrRestrictTy},
3679 RetType{IntTy}),
3680 Summary(NoEvalCall)
3681 .ArgConstraint(VC: NotNull(ArgNo(0)))
3682 .ArgConstraint(VC: NotNull(ArgNo(1))));
3683
3684 // int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize);
3685 // int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize);
3686 addToFunctionSummaryMap(
3687 {"pthread_attr_setstacksize", "pthread_attr_setguardsize"},
3688 Signature(ArgTypes{Pthread_attr_tPtrTy, SizeTyCanonTy}, RetType{IntTy}),
3689 Summary(NoEvalCall)
3690 .ArgConstraint(VC: NotNull(ArgNo(0)))
3691 .ArgConstraint(
3692 VC: ArgumentCondition(1, WithinRange, Range(0, SizeMax))));
3693
3694 // int pthread_mutex_init(pthread_mutex_t *restrict mutex, const
3695 // pthread_mutexattr_t *restrict attr);
3696 addToFunctionSummaryMap(
3697 "pthread_mutex_init",
3698 Signature(ArgTypes{Pthread_mutex_tPtrRestrictTy,
3699 ConstPthread_mutexattr_tPtrRestrictTy},
3700 RetType{IntTy}),
3701 Summary(NoEvalCall).ArgConstraint(VC: NotNull(ArgNo(0))));
3702
3703 // int pthread_mutex_destroy(pthread_mutex_t *mutex);
3704 // int pthread_mutex_lock(pthread_mutex_t *mutex);
3705 // int pthread_mutex_trylock(pthread_mutex_t *mutex);
3706 // int pthread_mutex_unlock(pthread_mutex_t *mutex);
3707 addToFunctionSummaryMap(
3708 {"pthread_mutex_destroy", "pthread_mutex_lock", "pthread_mutex_trylock",
3709 "pthread_mutex_unlock"},
3710 Signature(ArgTypes{Pthread_mutex_tPtrTy}, RetType{IntTy}),
3711 Summary(NoEvalCall).ArgConstraint(VC: NotNull(ArgNo(0))));
3712 }
3713
3714 // Functions for testing.
3715 if (AddTestFunctions) {
3716 const RangeInt IntMin = BVF.getMinValue(T: IntTy)->getLimitedValue();
3717
3718 addToFunctionSummaryMap(
3719 "__not_null", Signature(ArgTypes{IntPtrTy}, RetType{IntTy}),
3720 Summary(EvalCallAsPure).ArgConstraint(VC: NotNull(ArgNo(0))));
3721
3722 addToFunctionSummaryMap(
3723 "__not_null_buffer",
3724 Signature(ArgTypes{VoidPtrTy, IntTy, IntTy}, RetType{IntTy}),
3725 Summary(EvalCallAsPure)
3726 .ArgConstraint(VC: NotNullBuffer(ArgNo(0), ArgNo(1), ArgNo(2))));
3727
3728 // Test inside range constraints.
3729 addToFunctionSummaryMap(
3730 "__single_val_0", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3731 Summary(EvalCallAsPure)
3732 .ArgConstraint(VC: ArgumentCondition(0U, WithinRange, SingleValue(0))));
3733 addToFunctionSummaryMap(
3734 "__single_val_1", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3735 Summary(EvalCallAsPure)
3736 .ArgConstraint(VC: ArgumentCondition(0U, WithinRange, SingleValue(1))));
3737 addToFunctionSummaryMap(
3738 "__range_1_2", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3739 Summary(EvalCallAsPure)
3740 .ArgConstraint(VC: ArgumentCondition(0U, WithinRange, Range(1, 2))));
3741 addToFunctionSummaryMap(
3742 "__range_m1_1", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3743 Summary(EvalCallAsPure)
3744 .ArgConstraint(VC: ArgumentCondition(0U, WithinRange, Range(-1, 1))));
3745 addToFunctionSummaryMap(
3746 "__range_m2_m1", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3747 Summary(EvalCallAsPure)
3748 .ArgConstraint(VC: ArgumentCondition(0U, WithinRange, Range(-2, -1))));
3749 addToFunctionSummaryMap(
3750 "__range_m10_10", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3751 Summary(EvalCallAsPure)
3752 .ArgConstraint(VC: ArgumentCondition(0U, WithinRange, Range(-10, 10))));
3753 addToFunctionSummaryMap("__range_m1_inf",
3754 Signature(ArgTypes{IntTy}, RetType{IntTy}),
3755 Summary(EvalCallAsPure)
3756 .ArgConstraint(VC: ArgumentCondition(
3757 0U, WithinRange, Range(-1, IntMax))));
3758 addToFunctionSummaryMap("__range_0_inf",
3759 Signature(ArgTypes{IntTy}, RetType{IntTy}),
3760 Summary(EvalCallAsPure)
3761 .ArgConstraint(VC: ArgumentCondition(
3762 0U, WithinRange, Range(0, IntMax))));
3763 addToFunctionSummaryMap("__range_1_inf",
3764 Signature(ArgTypes{IntTy}, RetType{IntTy}),
3765 Summary(EvalCallAsPure)
3766 .ArgConstraint(VC: ArgumentCondition(
3767 0U, WithinRange, Range(1, IntMax))));
3768 addToFunctionSummaryMap("__range_minf_m1",
3769 Signature(ArgTypes{IntTy}, RetType{IntTy}),
3770 Summary(EvalCallAsPure)
3771 .ArgConstraint(VC: ArgumentCondition(
3772 0U, WithinRange, Range(IntMin, -1))));
3773 addToFunctionSummaryMap("__range_minf_0",
3774 Signature(ArgTypes{IntTy}, RetType{IntTy}),
3775 Summary(EvalCallAsPure)
3776 .ArgConstraint(VC: ArgumentCondition(
3777 0U, WithinRange, Range(IntMin, 0))));
3778 addToFunctionSummaryMap("__range_minf_1",
3779 Signature(ArgTypes{IntTy}, RetType{IntTy}),
3780 Summary(EvalCallAsPure)
3781 .ArgConstraint(VC: ArgumentCondition(
3782 0U, WithinRange, Range(IntMin, 1))));
3783 addToFunctionSummaryMap("__range_1_2__4_6",
3784 Signature(ArgTypes{IntTy}, RetType{IntTy}),
3785 Summary(EvalCallAsPure)
3786 .ArgConstraint(VC: ArgumentCondition(
3787 0U, WithinRange, Range({1, 2}, {4, 6}))));
3788 addToFunctionSummaryMap(
3789 "__range_1_2__4_inf", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3790 Summary(EvalCallAsPure)
3791 .ArgConstraint(VC: ArgumentCondition(0U, WithinRange,
3792 Range({1, 2}, {4, IntMax}))));
3793
3794 // Test out of range constraints.
3795 addToFunctionSummaryMap(
3796 "__single_val_out_0", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3797 Summary(EvalCallAsPure)
3798 .ArgConstraint(VC: ArgumentCondition(0U, OutOfRange, SingleValue(0))));
3799 addToFunctionSummaryMap(
3800 "__single_val_out_1", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3801 Summary(EvalCallAsPure)
3802 .ArgConstraint(VC: ArgumentCondition(0U, OutOfRange, SingleValue(1))));
3803 addToFunctionSummaryMap(
3804 "__range_out_1_2", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3805 Summary(EvalCallAsPure)
3806 .ArgConstraint(VC: ArgumentCondition(0U, OutOfRange, Range(1, 2))));
3807 addToFunctionSummaryMap(
3808 "__range_out_m1_1", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3809 Summary(EvalCallAsPure)
3810 .ArgConstraint(VC: ArgumentCondition(0U, OutOfRange, Range(-1, 1))));
3811 addToFunctionSummaryMap(
3812 "__range_out_m2_m1", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3813 Summary(EvalCallAsPure)
3814 .ArgConstraint(VC: ArgumentCondition(0U, OutOfRange, Range(-2, -1))));
3815 addToFunctionSummaryMap(
3816 "__range_out_m10_10", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3817 Summary(EvalCallAsPure)
3818 .ArgConstraint(VC: ArgumentCondition(0U, OutOfRange, Range(-10, 10))));
3819 addToFunctionSummaryMap("__range_out_m1_inf",
3820 Signature(ArgTypes{IntTy}, RetType{IntTy}),
3821 Summary(EvalCallAsPure)
3822 .ArgConstraint(VC: ArgumentCondition(
3823 0U, OutOfRange, Range(-1, IntMax))));
3824 addToFunctionSummaryMap("__range_out_0_inf",
3825 Signature(ArgTypes{IntTy}, RetType{IntTy}),
3826 Summary(EvalCallAsPure)
3827 .ArgConstraint(VC: ArgumentCondition(
3828 0U, OutOfRange, Range(0, IntMax))));
3829 addToFunctionSummaryMap("__range_out_1_inf",
3830 Signature(ArgTypes{IntTy}, RetType{IntTy}),
3831 Summary(EvalCallAsPure)
3832 .ArgConstraint(VC: ArgumentCondition(
3833 0U, OutOfRange, Range(1, IntMax))));
3834 addToFunctionSummaryMap("__range_out_minf_m1",
3835 Signature(ArgTypes{IntTy}, RetType{IntTy}),
3836 Summary(EvalCallAsPure)
3837 .ArgConstraint(VC: ArgumentCondition(
3838 0U, OutOfRange, Range(IntMin, -1))));
3839 addToFunctionSummaryMap("__range_out_minf_0",
3840 Signature(ArgTypes{IntTy}, RetType{IntTy}),
3841 Summary(EvalCallAsPure)
3842 .ArgConstraint(VC: ArgumentCondition(
3843 0U, OutOfRange, Range(IntMin, 0))));
3844 addToFunctionSummaryMap("__range_out_minf_1",
3845 Signature(ArgTypes{IntTy}, RetType{IntTy}),
3846 Summary(EvalCallAsPure)
3847 .ArgConstraint(VC: ArgumentCondition(
3848 0U, OutOfRange, Range(IntMin, 1))));
3849 addToFunctionSummaryMap("__range_out_1_2__4_6",
3850 Signature(ArgTypes{IntTy}, RetType{IntTy}),
3851 Summary(EvalCallAsPure)
3852 .ArgConstraint(VC: ArgumentCondition(
3853 0U, OutOfRange, Range({1, 2}, {4, 6}))));
3854 addToFunctionSummaryMap(
3855 "__range_out_1_2__4_inf", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3856 Summary(EvalCallAsPure)
3857 .ArgConstraint(
3858 VC: ArgumentCondition(0U, OutOfRange, Range({1, 2}, {4, IntMax}))));
3859
3860 // Test range kind.
3861 addToFunctionSummaryMap(
3862 "__within", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3863 Summary(EvalCallAsPure)
3864 .ArgConstraint(VC: ArgumentCondition(0U, WithinRange, SingleValue(1))));
3865 addToFunctionSummaryMap(
3866 "__out_of", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3867 Summary(EvalCallAsPure)
3868 .ArgConstraint(VC: ArgumentCondition(0U, OutOfRange, SingleValue(1))));
3869
3870 addToFunctionSummaryMap(
3871 "__two_constrained_args",
3872 Signature(ArgTypes{IntTy, IntTy}, RetType{IntTy}),
3873 Summary(EvalCallAsPure)
3874 .ArgConstraint(VC: ArgumentCondition(0U, WithinRange, SingleValue(1)))
3875 .ArgConstraint(VC: ArgumentCondition(1U, WithinRange, SingleValue(1))));
3876 addToFunctionSummaryMap(
3877 "__arg_constrained_twice", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3878 Summary(EvalCallAsPure)
3879 .ArgConstraint(VC: ArgumentCondition(0U, OutOfRange, SingleValue(1)))
3880 .ArgConstraint(VC: ArgumentCondition(0U, OutOfRange, SingleValue(2))));
3881 addToFunctionSummaryMap(
3882 "__defaultparam",
3883 Signature(ArgTypes{Irrelevant, IntTy}, RetType{IntTy}),
3884 Summary(EvalCallAsPure).ArgConstraint(VC: NotNull(ArgNo(0))));
3885 addToFunctionSummaryMap(
3886 "__variadic",
3887 Signature(ArgTypes{VoidPtrTy, ConstCharPtrTy}, RetType{IntTy}),
3888 Summary(EvalCallAsPure)
3889 .ArgConstraint(VC: NotNull(ArgNo(0)))
3890 .ArgConstraint(VC: NotNull(ArgNo(1))));
3891 addToFunctionSummaryMap(
3892 "__buf_size_arg_constraint",
3893 Signature(ArgTypes{ConstVoidPtrTy, SizeTyCanonTy}, RetType{IntTy}),
3894 Summary(EvalCallAsPure)
3895 .ArgConstraint(
3896 VC: BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1))));
3897 addToFunctionSummaryMap(
3898 "__buf_size_arg_constraint_mul",
3899 Signature(ArgTypes{ConstVoidPtrTy, SizeTyCanonTy, SizeTyCanonTy},
3900 RetType{IntTy}),
3901 Summary(EvalCallAsPure)
3902 .ArgConstraint(VC: BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1),
3903 /*BufSizeMultiplier=*/ArgNo(2))));
3904 addToFunctionSummaryMap(
3905 "__buf_size_arg_constraint_concrete",
3906 Signature(ArgTypes{ConstVoidPtrTy}, RetType{IntTy}),
3907 Summary(EvalCallAsPure)
3908 .ArgConstraint(VC: BufferSize(/*Buffer=*/ArgNo(0),
3909 /*BufSize=*/BVF.getValue(X: 10, T: IntTy))));
3910 addToFunctionSummaryMap(
3911 {"__test_restrict_param_0", "__test_restrict_param_1",
3912 "__test_restrict_param_2"},
3913 Signature(ArgTypes{VoidPtrRestrictTy}, RetType{VoidTy}),
3914 Summary(EvalCallAsPure));
3915
3916 // Test the application of cases.
3917 addToFunctionSummaryMap(
3918 "__test_case_note", Signature(ArgTypes{}, RetType{IntTy}),
3919 Summary(EvalCallAsPure)
3920 .Case(CS: {ReturnValueCondition(WithinRange, SingleValue(0))},
3921 ErrnoC: ErrnoIrrelevant, Note: "Function returns 0")
3922 .Case(CS: {ReturnValueCondition(WithinRange, SingleValue(1))},
3923 ErrnoC: ErrnoIrrelevant, Note: "Function returns 1"));
3924 addToFunctionSummaryMap(
3925 "__test_case_range_1_2__4_6",
3926 Signature(ArgTypes{IntTy}, RetType{IntTy}),
3927 Summary(EvalCallAsPure)
3928 .Case(CS: {ArgumentCondition(0U, WithinRange,
3929 IntRangeVector{{IntMin, 0}, {3, 3}}),
3930 ReturnValueCondition(WithinRange, SingleValue(1))},
3931 ErrnoC: ErrnoIrrelevant)
3932 .Case(CS: {ArgumentCondition(0U, WithinRange,
3933 IntRangeVector{{3, 3}, {7, IntMax}}),
3934 ReturnValueCondition(WithinRange, SingleValue(2))},
3935 ErrnoC: ErrnoIrrelevant)
3936 .Case(CS: {ArgumentCondition(0U, WithinRange,
3937 IntRangeVector{{IntMin, 0}, {7, IntMax}}),
3938 ReturnValueCondition(WithinRange, SingleValue(3))},
3939 ErrnoC: ErrnoIrrelevant)
3940 .Case(CS: {ArgumentCondition(
3941 0U, WithinRange,
3942 IntRangeVector{{IntMin, 0}, {3, 3}, {7, IntMax}}),
3943 ReturnValueCondition(WithinRange, SingleValue(4))},
3944 ErrnoC: ErrnoIrrelevant));
3945 }
3946}
3947
3948void ento::registerStdCLibraryFunctionsChecker(CheckerManager &mgr) {
3949 auto *Checker = mgr.registerChecker<StdLibraryFunctionsChecker>();
3950 Checker->CheckName = mgr.getCurrentCheckerName();
3951 const AnalyzerOptions &Opts = mgr.getAnalyzerOptions();
3952 Checker->DisplayLoadedSummaries =
3953 Opts.getCheckerBooleanOption(C: Checker, OptionName: "DisplayLoadedSummaries");
3954 Checker->ModelPOSIX = Opts.getCheckerBooleanOption(C: Checker, OptionName: "ModelPOSIX");
3955 Checker->ShouldAssumeControlledEnvironment =
3956 Opts.ShouldAssumeControlledEnvironment;
3957}
3958
3959bool ento::shouldRegisterStdCLibraryFunctionsChecker(
3960 const CheckerManager &mgr) {
3961 return true;
3962}
3963
3964void ento::registerStdCLibraryFunctionsTesterChecker(CheckerManager &mgr) {
3965 auto *Checker = mgr.getChecker<StdLibraryFunctionsChecker>();
3966 Checker->AddTestFunctions = true;
3967}
3968
3969bool ento::shouldRegisterStdCLibraryFunctionsTesterChecker(
3970 const CheckerManager &mgr) {
3971 return true;
3972}
3973