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