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