1 //=== StdLibraryFunctionsChecker.cpp - Model standard functions -*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 // This checker improves modeling of a few simple library functions.
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.
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.
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.
38 // Non-pure functions, for which only partial improvement over the default
39 // behavior is expected, are modeled via check::PostCall, non-intrusively.
41 //===----------------------------------------------------------------------===//
43 #include "ErrnoModeling.h"
44 #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
45 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
46 #include "clang/StaticAnalyzer/Core/Checker.h"
47 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
48 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
49 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
50 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h"
51 #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicExtent.h"
52 #include "llvm/ADT/STLExtras.h"
53 #include "llvm/ADT/SmallString.h"
54 #include "llvm/ADT/StringExtras.h"
55 #include "llvm/Support/FormatVariadic.h"
60 using namespace clang
;
61 using namespace clang::ento
;
64 class StdLibraryFunctionsChecker
65 : public Checker
<check::PreCall
, check::PostCall
, eval::Call
> {
69 /// Specify how much the analyzer engine should entrust modeling this function
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.
75 /// The function is modeled completely in this checker.
79 /// Given a range, should the argument stay inside or outside this range?
80 enum RangeKind
{ OutOfRange
, WithinRange
};
82 static RangeKind
negateKind(RangeKind K
) {
89 llvm_unreachable("Unknown range kind");
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
;
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
;
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
;
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
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
122 static void appendOutOfRangeDesc(llvm::APSInt RMin
, llvm::APSInt RMax
,
123 QualType ArgT
, BasicValueFactory
&BVF
,
124 llvm::raw_ostream
&Out
);
126 class ValueConstraint
;
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
>;
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
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
{
149 ValueConstraint(ArgNo ArgN
) : ArgN(ArgN
) {}
150 virtual ~ValueConstraint() {}
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;
158 /// Represents that in which context do we require a description of the
160 enum DescriptionKind
{
161 /// Describe a constraint that was violated.
162 /// Description should start with something like "should be".
164 /// Describe a constraint that was assumed to be true.
165 /// This can be used when a precondition is satisfied, or when a summary
167 /// Description should start with something like "is".
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.
183 "Description not implemented for summary case constraints");
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,
196 /// See StdLibraryFunctionsChecker::reportBug about how this function is
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()) {
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
216 /// The "return value" argument number can not occur as returned value.
217 virtual std::vector
<ArgNo
> getArgsToTrack() const { return {ArgN
}; }
219 /// Get a constraint that represents exactly the opposite of the current.
220 virtual ValueConstraintPtr
negate() const {
221 llvm_unreachable("Not implemented");
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!");
234 // Subclasses may further refine the validation.
235 return checkSpecificValidity(FD
);
238 /// Return the argument number (may be placeholder for "return value").
239 ArgNo
getArgNo() const { return ArgN
; }
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
245 /// Every constraint is assigned to one main argument, even if other
246 /// arguments are involved.
249 /// Do constraint-specific validation check.
250 virtual bool checkSpecificValidity(const FunctionDecl
*FD
) const {
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.
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).
271 /// A set of intervals.
272 IntRangeVector Ranges
;
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
;
280 RangeConstraint(ArgNo ArgN
, RangeKind Kind
, const IntRangeVector
&Ranges
,
282 : ValueConstraint(ArgN
), Kind(Kind
), Ranges(Ranges
), Description(Desc
) {
285 const IntRangeVector
&getRanges() const { return Ranges
; }
287 ProgramStateRef
apply(ProgramStateRef State
, const CallEvent
&Call
,
288 const Summary
&Summary
,
289 CheckerContext
&C
) const override
;
291 void describe(DescriptionKind DK
, const CallEvent
&Call
,
292 ProgramStateRef State
, const Summary
&Summary
,
293 llvm::raw_ostream
&Out
) const override
;
295 bool describeArgumentValue(const CallEvent
&Call
, ProgramStateRef State
,
296 const Summary
&Summary
,
297 llvm::raw_ostream
&Out
) const override
;
299 ValueConstraintPtr
negate() const override
{
300 RangeConstraint
Tmp(*this);
301 Tmp
.Kind
= negateKind(Kind
);
302 return std::make_shared
<RangeConstraint
>(Tmp
);
306 bool checkSpecificValidity(const FunctionDecl
*FD
) const override
{
307 const bool ValidArg
=
308 getArgType(FD
, ArgN
)->isIntegralType(FD
->getASTContext());
310 "This constraint should be applied on an integral type");
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
)>;
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]
330 /// -------+--------+------------------+------------+----------->
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
340 void applyOnRange(RangeKind Kind
, BasicValueFactory
&BVF
, QualType ArgT
,
341 const RangeApplyFunction
&F
) const {
344 applyOnOutOfRange(BVF
, ArgT
, F
);
347 applyOnWithinRange(BVF
, ArgT
, F
);
353 /// Check relation of an argument to another.
354 class ComparisonConstraint
: public ValueConstraint
{
355 BinaryOperator::Opcode Opcode
;
359 ComparisonConstraint(ArgNo ArgN
, BinaryOperator::Opcode Opcode
,
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
;
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;
376 NotNullConstraint(ArgNo ArgN
, bool CannotBeNull
= true)
377 : ValueConstraint(ArgN
), CannotBeNull(CannotBeNull
) {}
379 ProgramStateRef
apply(ProgramStateRef State
, const CallEvent
&Call
,
380 const Summary
&Summary
,
381 CheckerContext
&C
) const override
;
383 void describe(DescriptionKind DK
, const CallEvent
&Call
,
384 ProgramStateRef State
, const Summary
&Summary
,
385 llvm::raw_ostream
&Out
) const override
;
387 bool describeArgumentValue(const CallEvent
&Call
, ProgramStateRef State
,
388 const Summary
&Summary
,
389 llvm::raw_ostream
&Out
) const override
;
391 ValueConstraintPtr
negate() const override
{
392 NotNullConstraint
Tmp(*this);
393 Tmp
.CannotBeNull
= !this->CannotBeNull
;
394 return std::make_shared
<NotNullConstraint
>(Tmp
);
398 bool checkSpecificValidity(const FunctionDecl
*FD
) const override
{
399 const bool ValidArg
= getArgType(FD
, ArgN
)->isPointerType();
401 "This constraint should be applied only on a pointer type");
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
412 class NotNullBufferConstraint
: public ValueConstraint
{
413 using ValueConstraint::ValueConstraint
;
415 std::optional
<ArgNo
> SizeArg2N
;
416 // This variable has a role when we negate the constraint.
417 bool CannotBeNull
= true;
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
) {}
426 ProgramStateRef
apply(ProgramStateRef State
, const CallEvent
&Call
,
427 const Summary
&Summary
,
428 CheckerContext
&C
) const override
;
430 void describe(DescriptionKind DK
, const CallEvent
&Call
,
431 ProgramStateRef State
, const Summary
&Summary
,
432 llvm::raw_ostream
&Out
) const override
;
434 bool describeArgumentValue(const CallEvent
&Call
, ProgramStateRef State
,
435 const Summary
&Summary
,
436 llvm::raw_ostream
&Out
) const override
;
438 ValueConstraintPtr
negate() const override
{
439 NotNullBufferConstraint
Tmp(*this);
440 Tmp
.CannotBeNull
= !this->CannotBeNull
;
441 return std::make_shared
<NotNullBufferConstraint
>(Tmp
);
445 bool checkSpecificValidity(const FunctionDecl
*FD
) const override
{
446 const bool ValidArg
= getArgType(FD
, ArgN
)->isPointerType();
448 "This constraint should be applied only on a pointer type");
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
471 std::optional
<ArgNo
> SizeMultiplierArgN
;
472 // The operator we use in apply. This is negated in negate().
473 BinaryOperator::Opcode Op
= BO_LE
;
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
) {}
484 ProgramStateRef
apply(ProgramStateRef State
, const CallEvent
&Call
,
485 const Summary
&Summary
,
486 CheckerContext
&C
) const override
;
488 void describe(DescriptionKind DK
, const CallEvent
&Call
,
489 ProgramStateRef State
, const Summary
&Summary
,
490 llvm::raw_ostream
&Out
) const override
;
492 bool describeArgumentValue(const CallEvent
&Call
, ProgramStateRef State
,
493 const Summary
&Summary
,
494 llvm::raw_ostream
&Out
) const override
;
496 std::vector
<ArgNo
> getArgsToTrack() const override
{
497 std::vector
<ArgNo
> Result
{ArgN
};
499 Result
.push_back(*SizeArgN
);
500 if (SizeMultiplierArgN
)
501 Result
.push_back(*SizeMultiplierArgN
);
505 ValueConstraintPtr
negate() const override
{
506 BufferSizeConstraint
Tmp(*this);
507 Tmp
.Op
= BinaryOperator::negateComparisonOp(Op
);
508 return std::make_shared
<BufferSizeConstraint
>(Tmp
);
512 bool checkSpecificValidity(const FunctionDecl
*FD
) const override
{
513 const bool ValidArg
= getArgType(FD
, ArgN
)->isPointerType();
515 "This constraint should be applied only on a pointer type");
520 /// The complete list of constraints that defines a single branch.
521 using ConstraintSet
= std::vector
<ValueConstraintPtr
>;
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
530 class ErrnoConstraintBase
{
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 ""; }
542 virtual ~ErrnoConstraintBase() {}
545 ErrnoConstraintBase() = default;
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).
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
{
557 ProgramStateRef
apply(ProgramStateRef State
, const CallEvent
&Call
,
558 const Summary
&Summary
,
559 CheckerContext
&C
) const override
{
560 return errno_modeling::setErrnoState(State
, errno_modeling::Irrelevant
);
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
568 class NoErrnoConstraint
: public ErrnoConstraintBase
{
570 ProgramStateRef
apply(ProgramStateRef State
, const CallEvent
&Call
,
571 const Summary
&Summary
,
572 CheckerContext
&C
) const override
{
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
581 class FailureErrnoConstraint
: public ErrnoConstraintBase
{
583 ProgramStateRef
apply(ProgramStateRef State
, const CallEvent
&Call
,
584 const Summary
&Summary
,
585 CheckerContext
&C
) const override
{
586 SValBuilder
&SVB
= C
.getSValBuilder();
588 SVB
.conjureSymbolVal(&Tag
, Call
.getOriginExpr(),
589 C
.getLocationContext(), C
.getASTContext().IntTy
,
592 return errno_modeling::setErrnoForStdFailure(State
, C
, ErrnoSVal
);
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
601 class SuccessErrnoConstraint
: public ErrnoConstraintBase
{
603 ProgramStateRef
apply(ProgramStateRef State
, const CallEvent
&Call
,
604 const Summary
&Summary
,
605 CheckerContext
&C
) const override
{
606 return errno_modeling::setErrnoForStdSuccess(State
, C
);
609 const std::string
describe(CheckerContext
&C
) const override
{
610 return "'errno' becomes undefined after the call";
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
{
620 ProgramStateRef
apply(ProgramStateRef State
, const CallEvent
&Call
,
621 const Summary
&Summary
,
622 CheckerContext
&C
) const override
{
623 return errno_modeling::setErrnoStdMustBeChecked(State
, C
,
624 Call
.getOriginExpr());
627 const std::string
describe(CheckerContext
&C
) const override
{
628 return "reading 'errno' is required to find out if the call has failed";
632 /// A single branch of a function summary.
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.
644 /// For example, consider the branches in `isalpha(x)`:
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"
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".
654 ConstraintSet Constraints
;
655 const ErrnoConstraintBase
&ErrnoConstraint
;
659 SummaryCase(ConstraintSet
&&Constraints
, const ErrnoConstraintBase
&ErrnoC
,
661 : Constraints(std::move(Constraints
)), ErrnoConstraint(ErrnoC
),
664 SummaryCase(const ConstraintSet
&Constraints
,
665 const ErrnoConstraintBase
&ErrnoC
, StringRef Note
)
666 : Constraints(Constraints
), ErrnoConstraint(ErrnoC
), Note(Note
) {}
668 const ConstraintSet
&getConstraints() const { return Constraints
; }
669 const ErrnoConstraintBase
&getErrnoConstraint() const {
670 return ErrnoConstraint
;
672 StringRef
getNote() const { return Note
; }
675 using ArgTypes
= ArrayRef
<std::optional
<QualType
>>;
676 using RetType
= std::optional
<QualType
>;
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(); }
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.
688 using ArgQualTypes
= std::vector
<QualType
>;
691 // True if any component type is not found by lookup.
692 bool Invalid
= false;
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
) {
703 assertArgTypeSuitableForSignature(*Arg
);
704 this->ArgTys
.push_back(*Arg
);
711 assertRetTypeSuitableForSignature(*RetTy
);
712 this->RetTy
= *RetTy
;
716 bool isInvalid() const { return Invalid
; }
717 bool matches(const FunctionDecl
*FD
) const;
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");
726 static void assertRetTypeSuitableForSignature(QualType T
) {
727 assert((T
.isNull() || T
.isCanonical()) &&
728 "We should only have canonical types in the spec");
732 static QualType
getArgType(const FunctionDecl
*FD
, ArgNo ArgN
) {
733 assert(FD
&& "Function must be set");
734 QualType T
= (ArgN
== Ret
)
735 ? FD
->getReturnType().getCanonicalType()
736 : FD
->getParamDecl(ArgN
)->getType().getCanonicalType();
740 using SummaryCases
= std::vector
<SummaryCase
>;
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.
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.
759 const InvalidationKind InvalidationKd
;
761 ConstraintSet ArgConstraints
;
763 // The function to which the summary applies. This is set after lookup and
764 // match to the signature.
765 const FunctionDecl
*FD
= nullptr;
768 Summary(InvalidationKind InvalidationKd
) : InvalidationKd(InvalidationKd
) {}
770 Summary
&Case(ConstraintSet
&&CS
, const ErrnoConstraintBase
&ErrnoC
,
771 StringRef Note
= "") {
772 Cases
.push_back(SummaryCase(std::move(CS
), ErrnoC
, Note
));
775 Summary
&Case(const ConstraintSet
&CS
, const ErrnoConstraintBase
&ErrnoC
,
776 StringRef Note
= "") {
777 Cases
.push_back(SummaryCase(CS
, ErrnoC
, Note
));
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
);
787 InvalidationKind
getInvalidationKd() const { return InvalidationKd
; }
788 const SummaryCases
&getCases() const { return Cases
; }
789 const ConstraintSet
&getArgConstraints() const { return ArgConstraints
; }
791 QualType
getArgType(ArgNo ArgN
) const {
792 return StdLibraryFunctionsChecker::getArgType(FD
, ArgN
);
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
);
800 assert(!this->FD
&& "FD must not be set more than once");
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
))
814 for (const ValueConstraintPtr
&Constraint
: ArgConstraints
)
815 if (!Constraint
->checkValidity(FD
))
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
;
826 const BugType BT_InvalidArg
{this, "Function call with invalid argument"};
827 mutable bool SummariesInitialized
= false;
829 static SVal
getArgSVal(const CallEvent
&Call
, ArgNo ArgN
) {
830 return ArgN
== Ret
? Call
.getReturnValue() : Call
.getArgSVal(ArgN
);
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();
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;
843 CheckerNameRef CheckName
;
844 bool AddTestFunctions
= false;
846 bool DisplayLoadedSummaries
= false;
847 bool ModelPOSIX
= false;
848 bool ShouldAssumeControlledEnvironment
= false;
851 std::optional
<Summary
> findFunctionSummary(const FunctionDecl
*FD
,
852 CheckerContext
&C
) const;
853 std::optional
<Summary
> findFunctionSummary(const CallEvent
&Call
,
854 CheckerContext
&C
) const;
856 void initFunctionSummaries(CheckerContext
&C
) const;
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");
863 SmallString
<256> Msg
;
864 llvm::raw_svector_ostream
MsgOs(Msg
);
867 printArgDesc(VC
->getArgNo(), MsgOs
);
868 MsgOs
<< " to '" << getFunctionName(Call
) << "' ";
870 NegatedVC
->describeArgumentValue(Call
, N
->getState(), Summary
, MsgOs
);
874 MsgOs
<< "is out of the accepted range; It ";
875 VC
->describe(ValueConstraint::Violation
, Call
, C
.getState(), Summary
,
877 Msg
[0] = toupper(Msg
[0]);
878 auto R
= std::make_unique
<PathSensitiveBugReport
>(BT_InvalidArg
, Msg
, N
);
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
));
887 C
.emitReport(std::move(R
));
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
{};
902 int StdLibraryFunctionsChecker::ErrnoConstraintBase::Tag
= 0;
904 const StdLibraryFunctionsChecker::ArgNo
StdLibraryFunctionsChecker::Ret
=
905 std::numeric_limits
<ArgNo
>::max();
907 static BasicValueFactory
&getBVF(ProgramStateRef State
) {
908 ProgramStateManager
&Mgr
= State
->getStateManager();
909 SValBuilder
&SVB
= Mgr
.getSValBuilder();
910 return SVB
.getBasicValueFactory();
913 } // end of anonymous namespace
915 void StdLibraryFunctionsChecker::printArgDesc(
916 StdLibraryFunctionsChecker::ArgNo ArgN
, llvm::raw_ostream
&Out
) {
917 Out
<< std::to_string(ArgN
+ 1);
918 Out
<< llvm::getOrdinalSuffix(ArgN
+ 1);
922 void 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
<< ")";
932 void StdLibraryFunctionsChecker::appendInsideRangeDesc(llvm::APSInt RMin
,
935 BasicValueFactory
&BVF
,
936 llvm::raw_ostream
&Out
) {
937 if (RMin
.isZero() && RMax
.isZero())
939 else if (RMin
== RMax
)
941 else if (RMin
== BVF
.getMinValue(ArgT
)) {
945 Out
<< "<= " << RMax
;
946 } else if (RMax
== BVF
.getMaxValue(ArgT
)) {
950 Out
<< ">= " << RMin
;
951 } else if (RMin
.isNegative() == RMax
.isNegative() &&
952 RMin
.getLimitedValue() == RMax
.getLimitedValue() - 1) {
953 Out
<< RMin
<< " or " << RMax
;
955 Out
<< "between " << RMin
<< " and " << RMax
;
959 void StdLibraryFunctionsChecker::appendOutOfRangeDesc(llvm::APSInt RMin
,
962 BasicValueFactory
&BVF
,
963 llvm::raw_ostream
&Out
) {
964 if (RMin
.isZero() && RMax
.isZero())
966 else if (RMin
== RMax
) {
967 Out
<< "not equal to " << RMin
;
968 } else if (RMin
== BVF
.getMinValue(ArgT
)) {
973 } else if (RMax
== BVF
.getMaxValue(ArgT
)) {
978 } else if (RMin
.isNegative() == RMax
.isNegative() &&
979 RMin
.getLimitedValue() == RMax
.getLimitedValue() - 1) {
980 Out
<< "not " << RMin
<< " and not " << RMax
;
982 Out
<< "not between " << RMin
<< " and " << RMax
;
986 void StdLibraryFunctionsChecker::RangeConstraint::applyOnWithinRange(
987 BasicValueFactory
&BVF
, QualType ArgT
, const RangeApplyFunction
&F
) const {
991 for (auto [Start
, End
] : getRanges()) {
992 const llvm::APSInt
&Min
= BVF
.getValue(Start
, ArgT
);
993 const llvm::APSInt
&Max
= BVF
.getValue(End
, ArgT
);
1000 void StdLibraryFunctionsChecker::RangeConstraint::applyOnOutOfRange(
1001 BasicValueFactory
&BVF
, QualType ArgT
, const RangeApplyFunction
&F
) const {
1005 const IntRangeVector
&R
= getRanges();
1006 size_t E
= R
.size();
1008 const llvm::APSInt
&MinusInf
= BVF
.getMinValue(ArgT
);
1009 const llvm::APSInt
&PlusInf
= BVF
.getMaxValue(ArgT
);
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
);
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
);
1023 // Check the interval [T_MIN, min(R) - 1].
1024 if (RangeLeft
!= PlusInf
) {
1025 assert(MinusInf
<= RangeLeft
);
1026 if (!F(MinusInf
, RangeLeft
))
1029 // Check the interval [max(R) + 1, T_MAX],
1030 if (RangeRight
!= MinusInf
) {
1031 assert(RangeRight
<= PlusInf
);
1032 if (!F(RangeRight
, PlusInf
))
1037 ProgramStateRef
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());
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
);
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
);
1059 void StdLibraryFunctionsChecker::RangeConstraint::describe(
1060 DescriptionKind DK
, const CallEvent
&Call
, ProgramStateRef State
,
1061 const Summary
&Summary
, llvm::raw_ostream
&Out
) const {
1063 BasicValueFactory
&BVF
= getBVF(State
);
1064 QualType T
= Summary
.getArgType(getArgNo());
1066 Out
<< ((DK
== Violation
) ? "should be " : "is ");
1067 if (!Description
.empty()) {
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
);
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
);
1089 bool 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;
1095 ProgramStateManager
&Mgr
= State
->getStateManager();
1096 BasicValueFactory
&BVF
= Mgr
.getSValBuilder().getBasicValueFactory();
1097 ConstraintManager
&CM
= Mgr
.getConstraintManager();
1098 SVal V
= getArgSVal(Call
, getArgNo());
1100 if (auto N
= V
.getAs
<NonLoc
>()) {
1101 if (const llvm::APSInt
*Int
= N
->getAsInteger()) {
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)) {
1112 MoreInfoOs
<< " or ";
1113 appendInsideRangeDesc(Min
, Max
, T
, BVF
, MoreInfoOs
);
1116 HaveAllRanges
= false;
1121 applyOnRange(Kind
, BVF
, T
, ApplyF
);
1122 assert(NRanges
> 0);
1123 if (!HaveAllRanges
|| NRanges
== 1) {
1132 ProgramStateRef
StdLibraryFunctionsChecker::ComparisonConstraint::apply(
1133 ProgramStateRef State
, const CallEvent
&Call
, const Summary
&Summary
,
1134 CheckerContext
&C
) const {
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());
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
)
1149 .getAs
<DefinedOrUnknownSVal
>())
1150 State
= State
->assume(*CompV
, true);
1154 ProgramStateRef
StdLibraryFunctionsChecker::NotNullConstraint::apply(
1155 ProgramStateRef State
, const CallEvent
&Call
, const Summary
&Summary
,
1156 CheckerContext
&C
) const {
1157 SVal V
= getArgSVal(Call
, getArgNo());
1161 DefinedOrUnknownSVal L
= V
.castAs
<DefinedOrUnknownSVal
>();
1165 return State
->assume(L
, CannotBeNull
);
1168 void 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";
1176 Out
<< "is not NULL";
1179 bool 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");
1187 ProgramStateRef
StdLibraryFunctionsChecker::NotNullBufferConstraint::apply(
1188 ProgramStateRef State
, const CallEvent
&Call
, const Summary
&Summary
,
1189 CheckerContext
&C
) const {
1190 SVal V
= getArgSVal(Call
, getArgNo());
1193 DefinedOrUnknownSVal L
= V
.castAs
<DefinedOrUnknownSVal
>();
1197 std::optional
<DefinedOrUnknownSVal
> SizeArg1
=
1198 getArgSVal(Call
, SizeArg1N
).getAs
<DefinedOrUnknownSVal
>();
1199 std::optional
<DefinedOrUnknownSVal
> SizeArg2
;
1201 SizeArg2
= getArgSVal(Call
, *SizeArg2N
).getAs
<DefinedOrUnknownSVal
>();
1203 auto IsArgZero
= [State
](std::optional
<DefinedOrUnknownSVal
> Val
) {
1206 auto [IsNonNull
, IsNull
] = State
->assume(*Val
);
1207 return IsNull
&& !IsNonNull
;
1210 if (IsArgZero(SizeArg1
) || IsArgZero(SizeArg2
))
1213 return State
->assume(L
, CannotBeNull
);
1216 void 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";
1224 Out
<< "is not NULL";
1227 bool 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");
1235 ProgramStateRef
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());
1242 // Get the size constraint.
1243 const SVal SizeV
= [this, &State
, &Call
, &Summary
, &SvalBuilder
]() {
1245 return SVal(SvalBuilder
.makeIntVal(*ConcreteSize
));
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
));
1260 // The dynamic size of the buffer argument, got from the analyzer engine.
1261 SVal BufDynSize
= getDynamicExtentWithOffset(State
, BufV
);
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);
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");
1277 void 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 ";
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
);
1296 bool 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
,
1304 Out
<< "is a buffer with size " << *Val
;
1310 void StdLibraryFunctionsChecker::checkPreCall(const CallEvent
&Call
,
1311 CheckerContext
&C
) const {
1312 std::optional
<Summary
> FoundSummary
= findFunctionSummary(Call
, C
);
1316 const Summary
&Summary
= *FoundSummary
;
1317 ProgramStateRef State
= C
.getState();
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
,
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.
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
);
1345 Os
<< getFunctionName(Call
);
1347 Constraint
->describe(ValueConstraint::Assumption
, Call
, NewState
, Summary
,
1349 const auto ArgSVal
= Call
.getArgSVal(Constraint
->getArgNo());
1350 NewNode
= C
.addTransition(
1352 C
.getNoteTag([Msg
= std::move(Msg
), ArgSVal
](
1353 PathSensitiveBugReport
&BR
, llvm::raw_ostream
&OS
) {
1354 if (BR
.isInteresting(ArgSVal
))
1361 void StdLibraryFunctionsChecker::checkPostCall(const CallEvent
&Call
,
1362 CheckerContext
&C
) const {
1363 std::optional
<Summary
> FoundSummary
= findFunctionSummary(Call
, C
);
1367 // Now apply the constraints.
1368 const Summary
&Summary
= *FoundSummary
;
1369 ProgramStateRef State
= C
.getState();
1370 ExplodedNode
*Node
= C
.getPredecessor();
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
);
1382 NewState
= Case
.getErrnoConstraint().apply(NewState
, Call
, Summary
, C
);
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.
1393 ExplodedNode
*Pred
= Node
;
1394 DeclarationName FunctionName
=
1395 cast
<NamedDecl
>(Call
.getDecl())->getDeclName();
1397 std::string ErrnoNote
= Case
.getErrnoConstraint().describe(C
);
1398 std::string CaseNote
;
1399 if (Case
.getNote().empty()) {
1400 if (!ErrnoNote
.empty())
1402 llvm::formatv("After calling '{0}' {1}", FunctionName
, ErrnoNote
);
1404 // Disable formatv() validation as the case note may not always have the
1405 // {0} placeholder for function name.
1407 llvm::formatv(false, Case
.getNote().str().c_str(), FunctionName
);
1409 const SVal RV
= Call
.getReturnValue();
1411 if (Summary
.getInvalidationKd() == EvalCallAsPure
) {
1412 // Do not expect that errno is interesting (the "pure" functions do not
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)
1431 Pred
= C
.addTransition(NewState
, Pred
, Tag
);
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
1442 // If only the return value is interesting, show only the case
1444 std::optional
<Loc
> ErrnoLoc
=
1445 errno_modeling::getErrnoLoc(BR
.getErrorNode()->getState());
1446 bool ErrnoImportant
= !ErrnoNote
.empty() && ErrnoLoc
&&
1447 BR
.isInteresting(ErrnoLoc
->getAsRegion());
1448 if (ErrnoImportant
) {
1449 BR
.markNotInteresting(ErrnoLoc
->getAsRegion());
1450 if (CaseNote
.empty())
1452 return llvm::formatv("{0}; {1}", CaseNote
, ErrnoNote
);
1454 if (BR
.isInteresting(RV
))
1459 Pred
= C
.addTransition(NewState
, Pred
, Tag
);
1463 // Add the transition if no note tag was added.
1464 if (Pred
== Node
&& NewState
!= State
)
1465 C
.addTransition(NewState
);
1469 bool StdLibraryFunctionsChecker::evalCall(const CallEvent
&Call
,
1470 CheckerContext
&C
) const {
1471 std::optional
<Summary
> FoundSummary
= findFunctionSummary(Call
, C
);
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
);
1485 C
.addTransition(State
);
1490 // Summary tells us to avoid performing eval::Call. The function is possibly
1491 // evaluated by another checker, or evaluated conservatively.
1494 llvm_unreachable("Unknown invalidation kind!");
1497 bool StdLibraryFunctionsChecker::Signature::matches(
1498 const FunctionDecl
*FD
) const {
1499 assert(!isInvalid());
1500 // Check the number of arguments.
1501 if (FD
->param_size() != ArgTys
.size())
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
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();
1517 // Check the return type.
1518 if (!isIrrelevant(RetTy
)) {
1519 QualType FDRetTy
= RemoveRestrict(FD
->getReturnType().getCanonicalType());
1520 if (RetTy
!= FDRetTy
)
1524 // Check the argument types.
1525 for (auto [Idx
, ArgTy
] : llvm::enumerate(ArgTys
)) {
1526 if (isIrrelevant(ArgTy
))
1529 RemoveRestrict(FD
->getParamDecl(Idx
)->getType().getCanonicalType());
1530 if (ArgTy
!= FDArgTy
)
1537 std::optional
<StdLibraryFunctionsChecker::Summary
>
1538 StdLibraryFunctionsChecker::findFunctionSummary(const FunctionDecl
*FD
,
1539 CheckerContext
&C
) const {
1541 return std::nullopt
;
1543 initFunctionSummaries(C
);
1545 auto FSMI
= FunctionSummaryMap
.find(FD
->getCanonicalDecl());
1546 if (FSMI
== FunctionSummaryMap
.end())
1547 return std::nullopt
;
1548 return FSMI
->second
;
1551 std::optional
<StdLibraryFunctionsChecker::Summary
>
1552 StdLibraryFunctionsChecker::findFunctionSummary(const CallEvent
&Call
,
1553 CheckerContext
&C
) const {
1554 const FunctionDecl
*FD
= dyn_cast_or_null
<FunctionDecl
>(Call
.getDecl());
1556 return std::nullopt
;
1557 return findFunctionSummary(FD
, C
);
1560 void StdLibraryFunctionsChecker::initFunctionSummaries(
1561 CheckerContext
&C
) const {
1562 if (SummariesInitialized
)
1564 SummariesInitialized
= true;
1566 SValBuilder
&SVB
= C
.getSValBuilder();
1567 BasicValueFactory
&BVF
= SVB
.getBasicValueFactory();
1568 const ASTContext
&ACtx
= BVF
.getContext();
1569 Preprocessor
&PP
= C
.getPreprocessor();
1571 // Helper class to lookup a type by its name.
1573 const ASTContext
&ACtx
;
1576 LookupType(const ASTContext
&ACtx
) : ACtx(ACtx
) {}
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
;
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();
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
;
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
;
1611 GetRestrictTy(const ASTContext
&ACtx
) : ACtx(ACtx
) {}
1612 QualType
operator()(QualType Ty
) {
1613 return ACtx
.getLangOpts().C99
? ACtx
.getRestrictType(Ty
) : Ty
;
1615 std::optional
<QualType
> operator()(std::optional
<QualType
> Ty
) {
1617 return operator()(*Ty
);
1618 return std::nullopt
;
1620 } getRestrictTy(ACtx
);
1621 class GetPointerTy
{
1622 const ASTContext
&ACtx
;
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
) {
1629 return operator()(*Ty
);
1630 return std::nullopt
;
1632 } getPointerTy(ACtx
);
1635 std::optional
<QualType
> operator()(std::optional
<QualType
> Ty
) {
1636 return Ty
? std::optional
<QualType
>(Ty
->withConst()) : std::nullopt
;
1638 QualType
operator()(QualType Ty
) { return Ty
.withConst(); }
1641 BasicValueFactory
&BVF
;
1644 GetMaxValue(BasicValueFactory
&BVF
) : BVF(BVF
) {}
1645 std::optional
<RangeInt
> operator()(QualType Ty
) {
1646 return BVF
.getMaxValue(Ty
).getLimitedValue();
1648 std::optional
<RangeInt
> operator()(std::optional
<QualType
> Ty
) {
1650 return operator()(*Ty
);
1652 return std::nullopt
;
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();
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
);
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();
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
);
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);
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
) {
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.
1725 // Returns true if the summary has been added, false otherwise.
1726 bool operator()(StringRef Name
, Signature Sign
, Summary Sum
) {
1727 if (Sign
.isInvalid())
1729 IdentifierInfo
&II
= ACtx
.Idents
.get(Name
);
1730 auto LookupRes
= ACtx
.getTranslationUnitDecl()->lookup(&II
);
1731 if (LookupRes
.empty())
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!");
1739 if (DisplayLoadedSummaries
) {
1740 llvm::errs() << "Loaded summary for: ";
1741 FD
->print(llvm::errs());
1742 llvm::errs() << "\n";
1750 // Add the same summary for different names with the Signature explicitly
1752 void operator()(ArrayRef
<StringRef
> Names
, Signature Sign
, Summary Sum
) {
1753 for (StringRef Name
: Names
)
1754 operator()(Name
, Sign
, Sum
);
1756 } addToFunctionSummaryMap(ACtx
, FunctionSummaryMap
, DisplayLoadedSummaries
);
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
);
1763 auto BufferSize
= [](auto... Args
) {
1764 return std::make_shared
<BufferSizeConstraint
>(Args
...);
1767 auto operator()(RangeKind Kind
, IntRangeVector Ranges
) {
1768 return std::make_shared
<RangeConstraint
>(Ret
, Kind
, Ranges
);
1770 auto operator()(BinaryOperator::Opcode Op
, ArgNo OtherArgN
) {
1771 return std::make_shared
<ComparisonConstraint
>(Ret
, Op
, OtherArgN
);
1773 } ReturnValueCondition
;
1775 auto operator()(RangeInt b
, RangeInt e
) {
1776 return IntRangeVector
{std::pair
<RangeInt
, RangeInt
>{b
, e
}};
1778 auto operator()(RangeInt b
, std::optional
<RangeInt
> e
) {
1780 return IntRangeVector
{std::pair
<RangeInt
, RangeInt
>{b
, *e
}};
1781 return IntRangeVector
{};
1783 auto operator()(std::pair
<RangeInt
, RangeInt
> i0
,
1784 std::pair
<RangeInt
, std::optional
<RangeInt
>> i1
) {
1786 return IntRangeVector
{i0
, {i1
.first
, *(i1
.second
)}};
1787 return IntRangeVector
{i0
};
1790 auto SingleValue
= [](RangeInt v
) {
1791 return IntRangeVector
{std::pair
<RangeInt
, RangeInt
>{v
, v
}};
1793 auto LessThanOrEq
= BO_LE
;
1794 auto NotNull
= [&](ArgNo ArgN
) {
1795 return std::make_shared
<NotNullConstraint
>(ArgN
);
1797 auto IsNull
= [&](ArgNo ArgN
) {
1798 return std::make_shared
<NotNullConstraint
>(ArgN
, false);
1800 auto NotNullBuffer
= [&](ArgNo ArgN
, ArgNo SizeArg1N
, ArgNo SizeArg2N
) {
1801 return std::make_shared
<NotNullBufferConstraint
>(ArgN
, SizeArg1N
,
1805 std::optional
<QualType
> FileTy
= lookupTy("FILE");
1806 std::optional
<QualType
> FilePtrTy
= getPointerTy(FileTy
);
1807 std::optional
<QualType
> FilePtrRestrictTy
= getRestrictTy(FilePtrTy
);
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
);
1814 constexpr llvm::StringLiteral
GenericSuccessMsg(
1815 "Assuming that '{0}' is successful");
1816 constexpr llvm::StringLiteral
GenericFailureMsg("Assuming that '{0}' fails");
1818 // We are finally ready to define specifications for all supported functions.
1820 // Argument ranges should always cover all variants. If return value
1821 // is completely unknown, omit it from the respective range set.
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.
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
}})},
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
}})},
1864 .Case({ArgumentCondition(
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))},
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))},
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))},
1895 "Assuming the character is a control character")
1896 .Case({ArgumentCondition(0U, OutOfRange
, {{0, 32}, {127, 127}}),
1897 ReturnValueCondition(WithinRange
, SingleValue(0))},
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))},
1915 "Assuming the character has graphical representation")
1917 {ArgumentCondition(0U, OutOfRange
, Range(33, 126)),
1918 ReturnValueCondition(WithinRange
, SingleValue(0))},
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))},
1933 "Assuming the character is not a lowercase letter")
1934 // The locale-specific range.
1935 .Case({ArgumentCondition(0U, WithinRange
, {{128, UCharRangeMax
}})},
1937 // Is not an unsigned char.
1938 .Case({ArgumentCondition(0U, OutOfRange
, Range(0, UCharRangeMax
)),
1939 ReturnValueCondition(WithinRange
, SingleValue(0))},
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(
1955 {{'!', '/'}, {':', '@'}, {'[', '`'}, {'{', '~'}}),
1956 ReturnValueCondition(OutOfRange
, SingleValue(0))},
1957 ErrnoIrrelevant
, "Assuming the character is a punctuation mark")
1958 .Case({ArgumentCondition(
1960 {{'!', '/'}, {':', '@'}, {'[', '`'}, {'{', '~'}}),
1961 ReturnValueCondition(WithinRange
, SingleValue(0))},
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))},
1971 "Assuming the character is a whitespace character")
1972 // The locale-specific range.
1973 .Case({ArgumentCondition(0U, WithinRange
, {{128, UCharRangeMax
}})},
1975 .Case({ArgumentCondition(0U, OutOfRange
,
1976 {{9, 13}, {' ', ' '}, {128, UCharRangeMax
}}),
1977 ReturnValueCondition(WithinRange
, SingleValue(0))},
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))},
1987 "Assuming the character is an uppercase letter")
1988 // The locale-specific range.
1989 .Case({ArgumentCondition(0U, WithinRange
, {{128, UCharRangeMax
}})},
1992 .Case({ArgumentCondition(0U, OutOfRange
,
1993 {{'A', 'Z'}, {128, UCharRangeMax
}}),
1994 ReturnValueCondition(WithinRange
, SingleValue(0))},
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))},
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))},
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")));
2029 addToFunctionSummaryMap(
2030 "getchar", Signature(ArgTypes
{}, RetType
{IntTy
}),
2032 .Case({ReturnValueCondition(WithinRange
,
2033 {{EOFv
, EOFv
}, {0, UCharRangeMax
}})},
2036 // read()-like functions that never return more than buffer size.
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)));
2057 // size_t fread(void *restrict ptr, size_t size, size_t nitems,
2058 // FILE *restrict stream);
2059 addToFunctionSummaryMap(
2061 Signature(ArgTypes
{VoidPtrRestrictTy
, SizeTy
, SizeTy
, FilePtrRestrictTy
},
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
},
2072 std::optional
<QualType
> Ssize_tTy
= lookupTy("ssize_t");
2073 std::optional
<RangeInt
> Ssize_tMax
= getMaxValue(Ssize_tTy
);
2077 .Case({ReturnValueCondition(LessThanOrEq
, ArgNo(2)),
2078 ReturnValueCondition(WithinRange
, Range(-1, Ssize_tMax
))},
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
}),
2087 // ssize_t write(int fildes, const void *buf, size_t nbyte);
2088 addToFunctionSummaryMap(
2090 Signature(ArgTypes
{IntTy
, ConstVoidPtrTy
, SizeTy
}, RetType
{Ssize_tTy
}),
2093 auto GetLineSummary
=
2095 .Case({ReturnValueCondition(WithinRange
,
2096 Range({-1, -1}, {1, Ssize_tMax
}))},
2099 QualType CharPtrPtrRestrictTy
= getRestrictTy(getPointerTy(CharPtrTy
));
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(
2109 ArgTypes
{CharPtrPtrRestrictTy
, SizePtrRestrictTy
, FilePtrRestrictTy
},
2110 RetType
{Ssize_tTy
}),
2112 // ssize_t getdelim(char **restrict lineptr, size_t *restrict n,
2113 // int delimiter, FILE *restrict stream);
2114 addToFunctionSummaryMap(
2116 Signature(ArgTypes
{CharPtrPtrRestrictTy
, SizePtrRestrictTy
, IntTy
,
2118 RetType
{Ssize_tTy
}),
2122 Summary GetenvSummary
=
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");
2132 // char *getenv(const char *name);
2133 addToFunctionSummaryMap(
2134 "getenv", Signature(ArgTypes
{ConstCharPtrTy
}, RetType
{CharPtrTy
}),
2135 std::move(GetenvSummary
));
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
}),
2144 .Case({ReturnValueCondition(WithinRange
,
2145 {{EOFv
, EOFv
}, {0, UCharRangeMax
}})},
2147 .ArgConstraint(NotNull(ArgNo(0))));
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
;
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");
2171 // FILE *fopen(const char *restrict pathname, const char *restrict mode);
2172 addToFunctionSummaryMap(
2174 Signature(ArgTypes
{ConstCharPtrRestrictTy
, ConstCharPtrRestrictTy
},
2175 RetType
{FilePtrTy
}),
2177 .Case({NotNull(Ret
)}, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2178 .Case({IsNull(Ret
)}, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2179 .ArgConstraint(NotNull(ArgNo(0)))
2180 .ArgConstraint(NotNull(ArgNo(1))));
2182 // FILE *fdopen(int fd, const char *mode);
2183 addToFunctionSummaryMap(
2185 Signature(ArgTypes
{IntTy
, ConstCharPtrTy
}, RetType
{FilePtrTy
}),
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))));
2192 // FILE *tmpfile(void);
2193 addToFunctionSummaryMap(
2194 "tmpfile", Signature(ArgTypes
{}, RetType
{FilePtrTy
}),
2196 .Case({NotNull(Ret
)}, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2197 .Case({IsNull(Ret
)}, ErrnoNEZeroIrrelevant
, GenericFailureMsg
));
2199 // FILE *freopen(const char *restrict pathname, const char *restrict mode,
2200 // FILE *restrict stream);
2201 addToFunctionSummaryMap(
2203 Signature(ArgTypes
{ConstCharPtrRestrictTy
, ConstCharPtrRestrictTy
,
2205 RetType
{FilePtrTy
}),
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))));
2213 // FILE *popen(const char *command, const char *type);
2214 addToFunctionSummaryMap(
2216 Signature(ArgTypes
{ConstCharPtrTy
, ConstCharPtrTy
}, RetType
{FilePtrTy
}),
2218 .Case({NotNull(Ret
)}, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2219 .Case({IsNull(Ret
)}, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2220 .ArgConstraint(NotNull(ArgNo(0)))
2221 .ArgConstraint(NotNull(ArgNo(1))));
2223 // int fclose(FILE *stream);
2224 addToFunctionSummaryMap(
2225 "fclose", Signature(ArgTypes
{FilePtrTy
}, RetType
{IntTy
}),
2227 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2228 .Case(ReturnsEOF
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2229 .ArgConstraint(NotNull(ArgNo(0))));
2231 // int pclose(FILE *stream);
2232 addToFunctionSummaryMap(
2233 "pclose", Signature(ArgTypes
{FilePtrTy
}, RetType
{IntTy
}),
2235 .Case({ReturnValueCondition(WithinRange
, {{0, IntMax
}})},
2236 ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2237 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2238 .ArgConstraint(NotNull(ArgNo(0))));
2240 std::optional
<QualType
> Off_tTy
= lookupTy("off_t");
2241 std::optional
<RangeInt
> Off_tMax
= getMaxValue(Off_tTy
);
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
}),
2248 .Case({ReturnValueCondition(WithinRange
, {{0, UCharRangeMax
}})},
2249 ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2250 .Case({ReturnValueCondition(WithinRange
, SingleValue(EOFv
))},
2251 ErrnoIrrelevant
, GenericFailureMsg
)
2252 .ArgConstraint(NotNull(ArgNo(0))));
2254 // int fputc(int c, FILE *stream);
2255 // 'putc' is the same as 'fputc' but may be a macro
2256 addToFunctionSummaryMap(
2258 Signature(ArgTypes
{IntTy
, FilePtrTy
}, RetType
{IntTy
}),
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))));
2270 // char *fgets(char *restrict s, int n, FILE *restrict stream);
2271 addToFunctionSummaryMap(
2273 Signature(ArgTypes
{CharPtrRestrictTy
, IntTy
, FilePtrRestrictTy
},
2274 RetType
{CharPtrTy
}),
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
)))
2282 BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1)))
2283 .ArgConstraint(NotNull(ArgNo(2))));
2285 // int fputs(const char *restrict s, FILE *restrict stream);
2286 addToFunctionSummaryMap(
2288 Signature(ArgTypes
{ConstCharPtrRestrictTy
, FilePtrRestrictTy
},
2291 .Case(ReturnsNonnegative
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2292 .Case({ReturnValueCondition(WithinRange
, SingleValue(EOFv
))},
2293 ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2294 .ArgConstraint(NotNull(ArgNo(0)))
2295 .ArgConstraint(NotNull(ArgNo(1))));
2297 // int ungetc(int c, FILE *stream);
2298 addToFunctionSummaryMap(
2299 "ungetc", Signature(ArgTypes
{IntTy
, FilePtrTy
}, RetType
{IntTy
}),
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 "
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))));
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
}),
2323 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2324 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2325 .ArgConstraint(NotNull(ArgNo(0)))
2326 .ArgConstraint(ArgumentCondition(2, WithinRange
, {{0, 2}})));
2328 // int fseeko(FILE *stream, off_t offset, int whence);
2329 addToFunctionSummaryMap(
2331 Signature(ArgTypes
{FilePtrTy
, Off_tTy
, IntTy
}, RetType
{IntTy
}),
2333 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2334 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2335 .ArgConstraint(NotNull(ArgNo(0)))
2336 .ArgConstraint(ArgumentCondition(2, WithinRange
, {{0, 2}})));
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
2342 addToFunctionSummaryMap(
2344 Signature(ArgTypes
{FilePtrRestrictTy
, FPosTPtrRestrictTy
},
2347 .Case(ReturnsZero
, ErrnoUnchanged
, GenericSuccessMsg
)
2348 .Case(ReturnsNonZero
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2349 .ArgConstraint(NotNull(ArgNo(0)))
2350 .ArgConstraint(NotNull(ArgNo(1))));
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
2356 addToFunctionSummaryMap(
2358 Signature(ArgTypes
{FilePtrTy
, ConstFPosTPtrTy
}, RetType
{IntTy
}),
2360 .Case(ReturnsZero
, ErrnoUnchanged
, GenericSuccessMsg
)
2361 .Case(ReturnsNonZero
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2362 .ArgConstraint(NotNull(ArgNo(0)))
2363 .ArgConstraint(NotNull(ArgNo(1))));
2365 // int fflush(FILE *stream);
2366 addToFunctionSummaryMap(
2367 "fflush", Signature(ArgTypes
{FilePtrTy
}, RetType
{IntTy
}),
2369 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2370 .Case(ReturnsEOF
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
));
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
2376 addToFunctionSummaryMap(
2377 "ftell", Signature(ArgTypes
{FilePtrTy
}, RetType
{LongTy
}),
2379 .Case({ReturnValueCondition(WithinRange
, Range(0, LongMax
))},
2380 ErrnoUnchanged
, GenericSuccessMsg
)
2381 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2382 .ArgConstraint(NotNull(ArgNo(0))));
2384 // off_t ftello(FILE *stream);
2385 addToFunctionSummaryMap(
2386 "ftello", Signature(ArgTypes
{FilePtrTy
}, RetType
{Off_tTy
}),
2388 .Case({ReturnValueCondition(WithinRange
, Range(0, Off_tMax
))},
2389 ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2390 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2391 .ArgConstraint(NotNull(ArgNo(0))));
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
}),
2402 .Case(ReturnsValidFileDescriptor
, ErrnoUnchanged
, GenericSuccessMsg
)
2403 .ArgConstraint(NotNull(ArgNo(0))));
2405 // void rewind(FILE *stream);
2406 // This function indicates error only by setting of 'errno'.
2407 addToFunctionSummaryMap("rewind",
2408 Signature(ArgTypes
{FilePtrTy
}, RetType
{VoidTy
}),
2410 .Case({}, ErrnoMustBeChecked
)
2411 .ArgConstraint(NotNull(ArgNo(0))));
2413 // void clearerr(FILE *stream);
2414 addToFunctionSummaryMap(
2415 "clearerr", Signature(ArgTypes
{FilePtrTy
}, RetType
{VoidTy
}),
2416 Summary(NoEvalCall
).ArgConstraint(NotNull(ArgNo(0))));
2418 // int feof(FILE *stream);
2419 addToFunctionSummaryMap(
2420 "feof", Signature(ArgTypes
{FilePtrTy
}, RetType
{IntTy
}),
2421 Summary(NoEvalCall
).ArgConstraint(NotNull(ArgNo(0))));
2423 // int ferror(FILE *stream);
2424 addToFunctionSummaryMap(
2425 "ferror", Signature(ArgTypes
{FilePtrTy
}, RetType
{IntTy
}),
2426 Summary(NoEvalCall
).ArgConstraint(NotNull(ArgNo(0))));
2428 // long a64l(const char *str64);
2429 addToFunctionSummaryMap(
2430 "a64l", Signature(ArgTypes
{ConstCharPtrTy
}, RetType
{LongTy
}),
2431 Summary(NoEvalCall
).ArgConstraint(NotNull(ArgNo(0))));
2433 // char *l64a(long value);
2434 addToFunctionSummaryMap("l64a",
2435 Signature(ArgTypes
{LongTy
}, RetType
{CharPtrTy
}),
2437 .ArgConstraint(ArgumentCondition(
2438 0, WithinRange
, Range(0, LongMax
))));
2440 // int open(const char *path, int oflag, ...);
2441 addToFunctionSummaryMap(
2442 "open", Signature(ArgTypes
{ConstCharPtrTy
, IntTy
}, RetType
{IntTy
}),
2444 .Case(ReturnsValidFileDescriptor
, ErrnoMustNotBeChecked
,
2446 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2447 .ArgConstraint(NotNull(ArgNo(0))));
2449 // int openat(int fd, const char *path, int oflag, ...);
2450 addToFunctionSummaryMap(
2452 Signature(ArgTypes
{IntTy
, ConstCharPtrTy
, IntTy
}, RetType
{IntTy
}),
2454 .Case(ReturnsValidFileDescriptor
, ErrnoMustNotBeChecked
,
2456 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2457 .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2458 .ArgConstraint(NotNull(ArgNo(1))));
2460 // int access(const char *pathname, int amode);
2461 addToFunctionSummaryMap(
2462 "access", Signature(ArgTypes
{ConstCharPtrTy
, IntTy
}, RetType
{IntTy
}),
2464 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2465 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2466 .ArgConstraint(NotNull(ArgNo(0))));
2468 // int faccessat(int dirfd, const char *pathname, int mode, int flags);
2469 addToFunctionSummaryMap(
2471 Signature(ArgTypes
{IntTy
, ConstCharPtrTy
, IntTy
, IntTy
},
2474 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2475 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2476 .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2477 .ArgConstraint(NotNull(ArgNo(1))));
2479 // int dup(int fildes);
2480 addToFunctionSummaryMap(
2481 "dup", Signature(ArgTypes
{IntTy
}, RetType
{IntTy
}),
2483 .Case(ReturnsValidFileDescriptor
, ErrnoMustNotBeChecked
,
2485 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2487 ArgumentCondition(0, WithinRange
, Range(0, IntMax
))));
2489 // int dup2(int fildes1, int filedes2);
2490 addToFunctionSummaryMap(
2491 "dup2", Signature(ArgTypes
{IntTy
, IntTy
}, RetType
{IntTy
}),
2493 .Case(ReturnsValidFileDescriptor
, ErrnoMustNotBeChecked
,
2495 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2496 .ArgConstraint(ArgumentCondition(0, WithinRange
, Range(0, IntMax
)))
2498 ArgumentCondition(1, WithinRange
, Range(0, IntMax
))));
2500 // int fdatasync(int fildes);
2501 addToFunctionSummaryMap(
2502 "fdatasync", Signature(ArgTypes
{IntTy
}, RetType
{IntTy
}),
2504 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2505 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2507 ArgumentCondition(0, WithinRange
, Range(0, IntMax
))));
2509 // int fnmatch(const char *pattern, const char *string, int flags);
2510 addToFunctionSummaryMap(
2512 Signature(ArgTypes
{ConstCharPtrTy
, ConstCharPtrTy
, IntTy
},
2515 .ArgConstraint(NotNull(ArgNo(0)))
2516 .ArgConstraint(NotNull(ArgNo(1))));
2518 // int fsync(int fildes);
2519 addToFunctionSummaryMap(
2520 "fsync", Signature(ArgTypes
{IntTy
}, RetType
{IntTy
}),
2522 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2523 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2525 ArgumentCondition(0, WithinRange
, Range(0, IntMax
))));
2527 // int truncate(const char *path, off_t length);
2528 addToFunctionSummaryMap(
2530 Signature(ArgTypes
{ConstCharPtrTy
, Off_tTy
}, RetType
{IntTy
}),
2532 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2533 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2534 .ArgConstraint(NotNull(ArgNo(0))));
2536 // int symlink(const char *oldpath, const char *newpath);
2537 addToFunctionSummaryMap(
2539 Signature(ArgTypes
{ConstCharPtrTy
, ConstCharPtrTy
}, RetType
{IntTy
}),
2541 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2542 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2543 .ArgConstraint(NotNull(ArgNo(0)))
2544 .ArgConstraint(NotNull(ArgNo(1))));
2546 // int symlinkat(const char *oldpath, int newdirfd, const char *newpath);
2547 addToFunctionSummaryMap(
2549 Signature(ArgTypes
{ConstCharPtrTy
, IntTy
, ConstCharPtrTy
},
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))));
2558 // int lockf(int fd, int cmd, off_t len);
2559 addToFunctionSummaryMap(
2560 "lockf", Signature(ArgTypes
{IntTy
, IntTy
, Off_tTy
}, RetType
{IntTy
}),
2562 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2563 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2565 ArgumentCondition(0, WithinRange
, Range(0, IntMax
))));
2567 std::optional
<QualType
> Mode_tTy
= lookupTy("mode_t");
2569 // int creat(const char *pathname, mode_t mode);
2570 addToFunctionSummaryMap(
2571 "creat", Signature(ArgTypes
{ConstCharPtrTy
, Mode_tTy
}, RetType
{IntTy
}),
2573 .Case(ReturnsValidFileDescriptor
, ErrnoMustNotBeChecked
,
2575 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2576 .ArgConstraint(NotNull(ArgNo(0))));
2578 // unsigned int sleep(unsigned int seconds);
2579 addToFunctionSummaryMap(
2580 "sleep", Signature(ArgTypes
{UnsignedIntTy
}, RetType
{UnsignedIntTy
}),
2583 ArgumentCondition(0, WithinRange
, Range(0, UnsignedIntMax
))));
2585 std::optional
<QualType
> DirTy
= lookupTy("DIR");
2586 std::optional
<QualType
> DirPtrTy
= getPointerTy(DirTy
);
2588 // int dirfd(DIR *dirp);
2589 addToFunctionSummaryMap(
2590 "dirfd", Signature(ArgTypes
{DirPtrTy
}, RetType
{IntTy
}),
2592 .Case(ReturnsValidFileDescriptor
, ErrnoMustNotBeChecked
,
2594 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2595 .ArgConstraint(NotNull(ArgNo(0))));
2597 // unsigned int alarm(unsigned int seconds);
2598 addToFunctionSummaryMap(
2599 "alarm", Signature(ArgTypes
{UnsignedIntTy
}, RetType
{UnsignedIntTy
}),
2602 ArgumentCondition(0, WithinRange
, Range(0, UnsignedIntMax
))));
2604 // int closedir(DIR *dir);
2605 addToFunctionSummaryMap(
2606 "closedir", Signature(ArgTypes
{DirPtrTy
}, RetType
{IntTy
}),
2608 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2609 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2610 .ArgConstraint(NotNull(ArgNo(0))));
2612 // char *strdup(const char *s);
2613 addToFunctionSummaryMap(
2614 "strdup", Signature(ArgTypes
{ConstCharPtrTy
}, RetType
{CharPtrTy
}),
2615 Summary(NoEvalCall
).ArgConstraint(NotNull(ArgNo(0))));
2617 // char *strndup(const char *s, size_t n);
2618 addToFunctionSummaryMap(
2620 Signature(ArgTypes
{ConstCharPtrTy
, SizeTy
}, RetType
{CharPtrTy
}),
2622 .ArgConstraint(NotNull(ArgNo(0)))
2624 ArgumentCondition(1, WithinRange
, Range(0, SizeMax
))));
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))));
2631 // int mkstemp(char *template);
2632 addToFunctionSummaryMap(
2633 "mkstemp", Signature(ArgTypes
{CharPtrTy
}, RetType
{IntTy
}),
2635 .Case(ReturnsValidFileDescriptor
, ErrnoMustNotBeChecked
,
2637 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2638 .ArgConstraint(NotNull(ArgNo(0))));
2640 // char *mkdtemp(char *template);
2641 addToFunctionSummaryMap(
2642 "mkdtemp", Signature(ArgTypes
{CharPtrTy
}, RetType
{CharPtrTy
}),
2644 .Case({ReturnValueCondition(BO_EQ
, ArgNo(0))},
2645 ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2646 .Case({IsNull(Ret
)}, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2647 .ArgConstraint(NotNull(ArgNo(0))));
2649 // char *getcwd(char *buf, size_t size);
2650 addToFunctionSummaryMap(
2651 "getcwd", Signature(ArgTypes
{CharPtrTy
, SizeTy
}, RetType
{CharPtrTy
}),
2653 .Case({ArgumentCondition(1, WithinRange
, Range(1, SizeMax
)),
2654 ReturnValueCondition(BO_EQ
, ArgNo(0))},
2655 ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2656 .Case({ArgumentCondition(1, WithinRange
, SingleValue(0)),
2658 ErrnoNEZeroIrrelevant
, "Assuming that argument 'size' is 0")
2659 .Case({ArgumentCondition(1, WithinRange
, Range(1, SizeMax
)),
2661 ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2662 .ArgConstraint(NotNull(ArgNo(0)))
2664 BufferSize(/*Buffer*/ ArgNo(0), /*BufSize*/ ArgNo(1)))
2666 ArgumentCondition(1, WithinRange
, Range(0, SizeMax
))));
2668 // int mkdir(const char *pathname, mode_t mode);
2669 addToFunctionSummaryMap(
2670 "mkdir", Signature(ArgTypes
{ConstCharPtrTy
, Mode_tTy
}, RetType
{IntTy
}),
2672 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2673 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2674 .ArgConstraint(NotNull(ArgNo(0))));
2676 // int mkdirat(int dirfd, const char *pathname, mode_t mode);
2677 addToFunctionSummaryMap(
2679 Signature(ArgTypes
{IntTy
, ConstCharPtrTy
, Mode_tTy
}, RetType
{IntTy
}),
2681 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2682 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2683 .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2684 .ArgConstraint(NotNull(ArgNo(1))));
2686 std::optional
<QualType
> Dev_tTy
= lookupTy("dev_t");
2688 // int mknod(const char *pathname, mode_t mode, dev_t dev);
2689 addToFunctionSummaryMap(
2691 Signature(ArgTypes
{ConstCharPtrTy
, Mode_tTy
, Dev_tTy
}, RetType
{IntTy
}),
2693 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2694 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2695 .ArgConstraint(NotNull(ArgNo(0))));
2697 // int mknodat(int dirfd, const char *pathname, mode_t mode, dev_t dev);
2698 addToFunctionSummaryMap(
2700 Signature(ArgTypes
{IntTy
, ConstCharPtrTy
, Mode_tTy
, Dev_tTy
},
2703 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2704 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2705 .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2706 .ArgConstraint(NotNull(ArgNo(1))));
2708 // int chmod(const char *path, mode_t mode);
2709 addToFunctionSummaryMap(
2710 "chmod", Signature(ArgTypes
{ConstCharPtrTy
, Mode_tTy
}, RetType
{IntTy
}),
2712 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2713 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2714 .ArgConstraint(NotNull(ArgNo(0))));
2716 // int fchmodat(int dirfd, const char *pathname, mode_t mode, int flags);
2717 addToFunctionSummaryMap(
2719 Signature(ArgTypes
{IntTy
, ConstCharPtrTy
, Mode_tTy
, IntTy
},
2722 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2723 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2724 .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2725 .ArgConstraint(NotNull(ArgNo(1))));
2727 // int fchmod(int fildes, mode_t mode);
2728 addToFunctionSummaryMap(
2729 "fchmod", Signature(ArgTypes
{IntTy
, Mode_tTy
}, RetType
{IntTy
}),
2731 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2732 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2734 ArgumentCondition(0, WithinRange
, Range(0, IntMax
))));
2736 std::optional
<QualType
> Uid_tTy
= lookupTy("uid_t");
2737 std::optional
<QualType
> Gid_tTy
= lookupTy("gid_t");
2739 // int fchownat(int dirfd, const char *pathname, uid_t owner, gid_t group,
2741 addToFunctionSummaryMap(
2743 Signature(ArgTypes
{IntTy
, ConstCharPtrTy
, Uid_tTy
, Gid_tTy
, IntTy
},
2746 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2747 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2748 .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2749 .ArgConstraint(NotNull(ArgNo(1))));
2751 // int chown(const char *path, uid_t owner, gid_t group);
2752 addToFunctionSummaryMap(
2754 Signature(ArgTypes
{ConstCharPtrTy
, Uid_tTy
, Gid_tTy
}, RetType
{IntTy
}),
2756 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2757 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2758 .ArgConstraint(NotNull(ArgNo(0))));
2760 // int lchown(const char *path, uid_t owner, gid_t group);
2761 addToFunctionSummaryMap(
2763 Signature(ArgTypes
{ConstCharPtrTy
, Uid_tTy
, Gid_tTy
}, RetType
{IntTy
}),
2765 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2766 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2767 .ArgConstraint(NotNull(ArgNo(0))));
2769 // int fchown(int fildes, uid_t owner, gid_t group);
2770 addToFunctionSummaryMap(
2771 "fchown", Signature(ArgTypes
{IntTy
, Uid_tTy
, Gid_tTy
}, RetType
{IntTy
}),
2773 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2774 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2776 ArgumentCondition(0, WithinRange
, Range(0, IntMax
))));
2778 // int rmdir(const char *pathname);
2779 addToFunctionSummaryMap(
2780 "rmdir", Signature(ArgTypes
{ConstCharPtrTy
}, RetType
{IntTy
}),
2782 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2783 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2784 .ArgConstraint(NotNull(ArgNo(0))));
2786 // int chdir(const char *path);
2787 addToFunctionSummaryMap(
2788 "chdir", Signature(ArgTypes
{ConstCharPtrTy
}, RetType
{IntTy
}),
2790 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2791 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2792 .ArgConstraint(NotNull(ArgNo(0))));
2794 // int link(const char *oldpath, const char *newpath);
2795 addToFunctionSummaryMap(
2797 Signature(ArgTypes
{ConstCharPtrTy
, ConstCharPtrTy
}, RetType
{IntTy
}),
2799 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2800 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2801 .ArgConstraint(NotNull(ArgNo(0)))
2802 .ArgConstraint(NotNull(ArgNo(1))));
2804 // int linkat(int fd1, const char *path1, int fd2, const char *path2,
2806 addToFunctionSummaryMap(
2808 Signature(ArgTypes
{IntTy
, ConstCharPtrTy
, IntTy
, ConstCharPtrTy
, IntTy
},
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))));
2818 // int unlink(const char *pathname);
2819 addToFunctionSummaryMap(
2820 "unlink", Signature(ArgTypes
{ConstCharPtrTy
}, RetType
{IntTy
}),
2822 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2823 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2824 .ArgConstraint(NotNull(ArgNo(0))));
2826 // int unlinkat(int fd, const char *path, int flag);
2827 addToFunctionSummaryMap(
2829 Signature(ArgTypes
{IntTy
, ConstCharPtrTy
, IntTy
}, RetType
{IntTy
}),
2831 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2832 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2833 .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2834 .ArgConstraint(NotNull(ArgNo(1))));
2836 std::optional
<QualType
> StructStatTy
= lookupTy("stat");
2837 std::optional
<QualType
> StructStatPtrTy
= getPointerTy(StructStatTy
);
2838 std::optional
<QualType
> StructStatPtrRestrictTy
=
2839 getRestrictTy(StructStatPtrTy
);
2841 // int fstat(int fd, struct stat *statbuf);
2842 addToFunctionSummaryMap(
2843 "fstat", Signature(ArgTypes
{IntTy
, StructStatPtrTy
}, RetType
{IntTy
}),
2845 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2846 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2847 .ArgConstraint(ArgumentCondition(0, WithinRange
, Range(0, IntMax
)))
2848 .ArgConstraint(NotNull(ArgNo(1))));
2850 // int stat(const char *restrict path, struct stat *restrict buf);
2851 addToFunctionSummaryMap(
2853 Signature(ArgTypes
{ConstCharPtrRestrictTy
, StructStatPtrRestrictTy
},
2856 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2857 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2858 .ArgConstraint(NotNull(ArgNo(0)))
2859 .ArgConstraint(NotNull(ArgNo(1))));
2861 // int lstat(const char *restrict path, struct stat *restrict buf);
2862 addToFunctionSummaryMap(
2864 Signature(ArgTypes
{ConstCharPtrRestrictTy
, StructStatPtrRestrictTy
},
2867 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2868 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2869 .ArgConstraint(NotNull(ArgNo(0)))
2870 .ArgConstraint(NotNull(ArgNo(1))));
2872 // int fstatat(int fd, const char *restrict path,
2873 // struct stat *restrict buf, int flag);
2874 addToFunctionSummaryMap(
2876 Signature(ArgTypes
{IntTy
, ConstCharPtrRestrictTy
,
2877 StructStatPtrRestrictTy
, IntTy
},
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))));
2886 // DIR *opendir(const char *name);
2887 addToFunctionSummaryMap(
2888 "opendir", Signature(ArgTypes
{ConstCharPtrTy
}, RetType
{DirPtrTy
}),
2890 .Case({NotNull(Ret
)}, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2891 .Case({IsNull(Ret
)}, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2892 .ArgConstraint(NotNull(ArgNo(0))));
2894 // DIR *fdopendir(int fd);
2895 addToFunctionSummaryMap(
2896 "fdopendir", Signature(ArgTypes
{IntTy
}, RetType
{DirPtrTy
}),
2898 .Case({NotNull(Ret
)}, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2899 .Case({IsNull(Ret
)}, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2901 ArgumentCondition(0, WithinRange
, Range(0, IntMax
))));
2903 // int isatty(int fildes);
2904 addToFunctionSummaryMap(
2905 "isatty", Signature(ArgTypes
{IntTy
}, RetType
{IntTy
}),
2907 .Case({ReturnValueCondition(WithinRange
, Range(0, 1))},
2910 ArgumentCondition(0, WithinRange
, Range(0, IntMax
))));
2912 // int close(int fildes);
2913 addToFunctionSummaryMap(
2914 "close", Signature(ArgTypes
{IntTy
}, RetType
{IntTy
}),
2916 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2917 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2919 ArgumentCondition(0, WithinRange
, Range(-1, IntMax
))));
2921 // long fpathconf(int fildes, int name);
2922 addToFunctionSummaryMap("fpathconf",
2923 Signature(ArgTypes
{IntTy
, IntTy
}, RetType
{LongTy
}),
2925 .ArgConstraint(ArgumentCondition(
2926 0, WithinRange
, Range(0, IntMax
))));
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))));
2933 // void rewinddir(DIR *dir);
2934 addToFunctionSummaryMap(
2935 "rewinddir", Signature(ArgTypes
{DirPtrTy
}, RetType
{VoidTy
}),
2936 Summary(NoEvalCall
).ArgConstraint(NotNull(ArgNo(0))));
2938 // void seekdir(DIR *dirp, long loc);
2939 addToFunctionSummaryMap(
2940 "seekdir", Signature(ArgTypes
{DirPtrTy
, LongTy
}, RetType
{VoidTy
}),
2941 Summary(NoEvalCall
).ArgConstraint(NotNull(ArgNo(0))));
2943 // int rand_r(unsigned int *seedp);
2944 addToFunctionSummaryMap(
2945 "rand_r", Signature(ArgTypes
{UnsignedIntPtrTy
}, RetType
{IntTy
}),
2946 Summary(NoEvalCall
).ArgConstraint(NotNull(ArgNo(0))));
2948 // void *mmap(void *addr, size_t length, int prot, int flags, int fd,
2950 // FIXME: Improve for errno modeling.
2951 addToFunctionSummaryMap(
2953 Signature(ArgTypes
{VoidPtrTy
, SizeTy
, IntTy
, IntTy
, IntTy
, Off_tTy
},
2954 RetType
{VoidPtrTy
}),
2956 .ArgConstraint(ArgumentCondition(1, WithinRange
, Range(1, SizeMax
)))
2958 ArgumentCondition(4, WithinRange
, Range(-1, IntMax
))));
2960 std::optional
<QualType
> Off64_tTy
= lookupTy("off64_t");
2961 // void *mmap64(void *addr, size_t length, int prot, int flags, int fd,
2963 // FIXME: Improve for errno modeling.
2964 addToFunctionSummaryMap(
2966 Signature(ArgTypes
{VoidPtrTy
, SizeTy
, IntTy
, IntTy
, IntTy
, Off64_tTy
},
2967 RetType
{VoidPtrTy
}),
2969 .ArgConstraint(ArgumentCondition(1, WithinRange
, Range(1, SizeMax
)))
2971 ArgumentCondition(4, WithinRange
, Range(-1, IntMax
))));
2973 // int pipe(int fildes[2]);
2974 addToFunctionSummaryMap(
2975 "pipe", Signature(ArgTypes
{IntPtrTy
}, RetType
{IntTy
}),
2977 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2978 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2979 .ArgConstraint(NotNull(ArgNo(0))));
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
}),
2989 .Case(ReturnsNonnegative
, ErrnoIrrelevant
)
2990 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2992 ArgumentCondition(0, WithinRange
, Range(0, IntMax
))));
2994 // ssize_t readlink(const char *restrict path, char *restrict buf,
2996 addToFunctionSummaryMap(
2998 Signature(ArgTypes
{ConstCharPtrRestrictTy
, CharPtrRestrictTy
, SizeTy
},
2999 RetType
{Ssize_tTy
}),
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)))
3015 ArgumentCondition(2, WithinRange
, Range(0, SizeMax
))));
3017 // ssize_t readlinkat(int fd, const char *restrict path,
3018 // char *restrict buf, size_t bufsize);
3019 addToFunctionSummaryMap(
3022 ArgTypes
{IntTy
, ConstCharPtrRestrictTy
, CharPtrRestrictTy
, SizeTy
},
3023 RetType
{Ssize_tTy
}),
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)))
3040 ArgumentCondition(3, WithinRange
, Range(0, SizeMax
))));
3042 // int renameat(int olddirfd, const char *oldpath, int newdirfd, const char
3044 addToFunctionSummaryMap(
3046 Signature(ArgTypes
{IntTy
, ConstCharPtrTy
, IntTy
, ConstCharPtrTy
},
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))));
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(
3062 Signature(ArgTypes
{ConstCharPtrRestrictTy
, CharPtrRestrictTy
},
3063 RetType
{CharPtrTy
}),
3065 .Case({NotNull(Ret
)}, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
3066 .Case({IsNull(Ret
)}, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
3067 .ArgConstraint(NotNull(ArgNo(0))));
3069 QualType CharPtrConstPtr
= getPointerTy(getConstTy(CharPtrTy
));
3071 // int execv(const char *path, char *const argv[]);
3072 addToFunctionSummaryMap(
3074 Signature(ArgTypes
{ConstCharPtrTy
, CharPtrConstPtr
}, RetType
{IntTy
}),
3076 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
)
3077 .ArgConstraint(NotNull(ArgNo(0))));
3079 // int execvp(const char *file, char *const argv[]);
3080 addToFunctionSummaryMap(
3082 Signature(ArgTypes
{ConstCharPtrTy
, CharPtrConstPtr
}, RetType
{IntTy
}),
3084 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
)
3085 .ArgConstraint(NotNull(ArgNo(0))));
3087 // int getopt(int argc, char * const argv[], const char *optstring);
3088 addToFunctionSummaryMap(
3090 Signature(ArgTypes
{IntTy
, CharPtrConstPtr
, ConstCharPtrTy
},
3093 .Case({ReturnValueCondition(WithinRange
, Range(-1, UCharRangeMax
))},
3095 .ArgConstraint(ArgumentCondition(0, WithinRange
, Range(0, IntMax
)))
3096 .ArgConstraint(NotNull(ArgNo(1)))
3097 .ArgConstraint(NotNull(ArgNo(2))));
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
);
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.
3121 // int socket(int domain, int type, int protocol);
3122 addToFunctionSummaryMap(
3123 "socket", Signature(ArgTypes
{IntTy
, IntTy
, IntTy
}, RetType
{IntTy
}),
3125 .Case(ReturnsValidFileDescriptor
, ErrnoMustNotBeChecked
,
3127 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
));
3131 .Case(ReturnsValidFileDescriptor
, ErrnoMustNotBeChecked
,
3133 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
3134 .ArgConstraint(ArgumentCondition(0, WithinRange
, Range(0, IntMax
)));
3135 if (!addToFunctionSummaryMap(
3137 // int accept(int socket, struct sockaddr *restrict address,
3138 // socklen_t *restrict address_len);
3139 Signature(ArgTypes
{IntTy
, StructSockaddrPtrRestrictTy
,
3140 Socklen_tPtrRestrictTy
},
3143 addToFunctionSummaryMap(
3145 Signature(ArgTypes
{IntTy
, Irrelevant
, Socklen_tPtrRestrictTy
},
3149 // int bind(int socket, const struct sockaddr *address, socklen_t
3151 if (!addToFunctionSummaryMap(
3153 Signature(ArgTypes
{IntTy
, ConstStructSockaddrPtrTy
, Socklen_tTy
},
3156 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
3157 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
3159 ArgumentCondition(0, WithinRange
, Range(0, IntMax
)))
3160 .ArgConstraint(NotNull(ArgNo(1)))
3162 BufferSize(/*Buffer=*/ArgNo(1), /*BufSize=*/ArgNo(2)))
3164 ArgumentCondition(2, WithinRange
, Range(0, Socklen_tMax
)))))
3165 // Do not add constraints on sockaddr.
3166 addToFunctionSummaryMap(
3168 Signature(ArgTypes
{IntTy
, Irrelevant
, Socklen_tTy
}, RetType
{IntTy
}),
3170 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
3171 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
3173 ArgumentCondition(0, WithinRange
, Range(0, IntMax
)))
3175 ArgumentCondition(2, WithinRange
, Range(0, Socklen_tMax
))));
3177 // int getpeername(int socket, struct sockaddr *restrict address,
3178 // socklen_t *restrict address_len);
3179 if (!addToFunctionSummaryMap(
3181 Signature(ArgTypes
{IntTy
, StructSockaddrPtrRestrictTy
,
3182 Socklen_tPtrRestrictTy
},
3185 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
3186 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
3188 ArgumentCondition(0, WithinRange
, Range(0, IntMax
)))
3189 .ArgConstraint(NotNull(ArgNo(1)))
3190 .ArgConstraint(NotNull(ArgNo(2)))))
3191 addToFunctionSummaryMap(
3193 Signature(ArgTypes
{IntTy
, Irrelevant
, Socklen_tPtrRestrictTy
},
3196 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
3197 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
3199 ArgumentCondition(0, WithinRange
, Range(0, IntMax
))));
3201 // int getsockname(int socket, struct sockaddr *restrict address,
3202 // socklen_t *restrict address_len);
3203 if (!addToFunctionSummaryMap(
3205 Signature(ArgTypes
{IntTy
, StructSockaddrPtrRestrictTy
,
3206 Socklen_tPtrRestrictTy
},
3209 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
3210 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
3212 ArgumentCondition(0, WithinRange
, Range(0, IntMax
)))
3213 .ArgConstraint(NotNull(ArgNo(1)))
3214 .ArgConstraint(NotNull(ArgNo(2)))))
3215 addToFunctionSummaryMap(
3217 Signature(ArgTypes
{IntTy
, Irrelevant
, Socklen_tPtrRestrictTy
},
3220 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
3221 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
3223 ArgumentCondition(0, WithinRange
, Range(0, IntMax
))));
3225 // int connect(int socket, const struct sockaddr *address, socklen_t
3227 if (!addToFunctionSummaryMap(
3229 Signature(ArgTypes
{IntTy
, ConstStructSockaddrPtrTy
, Socklen_tTy
},
3232 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
3233 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
3235 ArgumentCondition(0, WithinRange
, Range(0, IntMax
)))
3236 .ArgConstraint(NotNull(ArgNo(1)))))
3237 addToFunctionSummaryMap(
3239 Signature(ArgTypes
{IntTy
, Irrelevant
, Socklen_tTy
}, RetType
{IntTy
}),
3241 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
3242 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
3244 ArgumentCondition(0, WithinRange
, Range(0, IntMax
))));
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(
3260 // ssize_t recvfrom(int socket, void *restrict buffer,
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
}),
3269 addToFunctionSummaryMap(
3271 Signature(ArgTypes
{IntTy
, VoidPtrRestrictTy
, SizeTy
, IntTy
,
3272 Irrelevant
, Socklen_tPtrRestrictTy
},
3273 RetType
{Ssize_tTy
}),
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(
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
}),
3297 addToFunctionSummaryMap(
3299 Signature(ArgTypes
{IntTy
, ConstVoidPtrTy
, SizeTy
, IntTy
, Irrelevant
,
3301 RetType
{Ssize_tTy
}),
3304 // int listen(int sockfd, int backlog);
3305 addToFunctionSummaryMap(
3306 "listen", Signature(ArgTypes
{IntTy
, IntTy
}, RetType
{IntTy
}),
3308 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
3309 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
3311 ArgumentCondition(0, WithinRange
, Range(0, IntMax
))));
3313 // ssize_t recv(int sockfd, void *buf, size_t len, int flags);
3314 addToFunctionSummaryMap(
3316 Signature(ArgTypes
{IntTy
, VoidPtrTy
, SizeTy
, IntTy
},
3317 RetType
{Ssize_tTy
}),
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))));
3330 std::optional
<QualType
> StructMsghdrTy
= lookupTy("msghdr");
3331 std::optional
<QualType
> StructMsghdrPtrTy
= getPointerTy(StructMsghdrTy
);
3332 std::optional
<QualType
> ConstStructMsghdrPtrTy
=
3333 getPointerTy(getConstTy(StructMsghdrTy
));
3335 // ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);
3336 addToFunctionSummaryMap(
3338 Signature(ArgTypes
{IntTy
, StructMsghdrPtrTy
, IntTy
},
3339 RetType
{Ssize_tTy
}),
3341 .Case({ReturnValueCondition(WithinRange
, Range(1, Ssize_tMax
))},
3342 ErrnoMustNotBeChecked
, GenericSuccessMsg
)
3343 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
3345 ArgumentCondition(0, WithinRange
, Range(0, IntMax
))));
3347 // ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
3348 addToFunctionSummaryMap(
3350 Signature(ArgTypes
{IntTy
, ConstStructMsghdrPtrTy
, IntTy
},
3351 RetType
{Ssize_tTy
}),
3353 .Case({ReturnValueCondition(WithinRange
, Range(1, Ssize_tMax
))},
3354 ErrnoMustNotBeChecked
, GenericSuccessMsg
)
3355 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
3357 ArgumentCondition(0, WithinRange
, Range(0, IntMax
))));
3359 // int setsockopt(int socket, int level, int option_name,
3360 // const void *option_value, socklen_t option_len);
3361 addToFunctionSummaryMap(
3363 Signature(ArgTypes
{IntTy
, IntTy
, IntTy
, ConstVoidPtrTy
, Socklen_tTy
},
3366 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
3367 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
3368 .ArgConstraint(NotNull(ArgNo(3)))
3370 BufferSize(/*Buffer=*/ArgNo(3), /*BufSize=*/ArgNo(4)))
3372 ArgumentCondition(4, WithinRange
, Range(0, Socklen_tMax
))));
3374 // int getsockopt(int socket, int level, int option_name,
3375 // void *restrict option_value,
3376 // socklen_t *restrict option_len);
3377 addToFunctionSummaryMap(
3379 Signature(ArgTypes
{IntTy
, IntTy
, IntTy
, VoidPtrRestrictTy
,
3380 Socklen_tPtrRestrictTy
},
3383 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
3384 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
3385 .ArgConstraint(NotNull(ArgNo(3)))
3386 .ArgConstraint(NotNull(ArgNo(4))));
3388 // ssize_t send(int sockfd, const void *buf, size_t len, int flags);
3389 addToFunctionSummaryMap(
3391 Signature(ArgTypes
{IntTy
, ConstVoidPtrTy
, SizeTy
, IntTy
},
3392 RetType
{Ssize_tTy
}),
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))));
3405 // int socketpair(int domain, int type, int protocol, int sv[2]);
3406 addToFunctionSummaryMap(
3408 Signature(ArgTypes
{IntTy
, IntTy
, IntTy
, IntPtrTy
}, RetType
{IntTy
}),
3410 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
3411 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
3412 .ArgConstraint(NotNull(ArgNo(3))));
3414 // int shutdown(int socket, int how);
3415 addToFunctionSummaryMap(
3416 "shutdown", Signature(ArgTypes
{IntTy
, IntTy
}, RetType
{IntTy
}),
3418 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
3419 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
3421 ArgumentCondition(0, WithinRange
, Range(0, IntMax
))));
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);
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(
3432 Signature(ArgTypes
{ConstStructSockaddrPtrRestrictTy
, Socklen_tTy
,
3433 CharPtrRestrictTy
, Socklen_tTy
, CharPtrRestrictTy
,
3434 Socklen_tTy
, IntTy
},
3438 BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1)))
3440 ArgumentCondition(1, WithinRange
, Range(0, Socklen_tMax
)))
3442 BufferSize(/*Buffer=*/ArgNo(2), /*BufSize=*/ArgNo(3)))
3444 ArgumentCondition(3, WithinRange
, Range(0, Socklen_tMax
)))
3446 BufferSize(/*Buffer=*/ArgNo(4), /*BufSize=*/ArgNo(5)))
3448 ArgumentCondition(5, WithinRange
, Range(0, Socklen_tMax
))));
3450 std::optional
<QualType
> StructUtimbufTy
= lookupTy("utimbuf");
3451 std::optional
<QualType
> StructUtimbufPtrTy
= getPointerTy(StructUtimbufTy
);
3453 // int utime(const char *filename, struct utimbuf *buf);
3454 addToFunctionSummaryMap(
3456 Signature(ArgTypes
{ConstCharPtrTy
, StructUtimbufPtrTy
}, RetType
{IntTy
}),
3458 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
3459 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
3460 .ArgConstraint(NotNull(ArgNo(0))));
3462 std::optional
<QualType
> StructTimespecTy
= lookupTy("timespec");
3463 std::optional
<QualType
> StructTimespecPtrTy
=
3464 getPointerTy(StructTimespecTy
);
3465 std::optional
<QualType
> ConstStructTimespecPtrTy
=
3466 getPointerTy(getConstTy(StructTimespecTy
));
3468 // int futimens(int fd, const struct timespec times[2]);
3469 addToFunctionSummaryMap(
3471 Signature(ArgTypes
{IntTy
, ConstStructTimespecPtrTy
}, RetType
{IntTy
}),
3473 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
3474 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
3476 ArgumentCondition(0, WithinRange
, Range(0, IntMax
))));
3478 // int utimensat(int dirfd, const char *pathname,
3479 // const struct timespec times[2], int flags);
3480 addToFunctionSummaryMap(
3483 ArgTypes
{IntTy
, ConstCharPtrTy
, ConstStructTimespecPtrTy
, IntTy
},
3486 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
3487 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
3488 .ArgConstraint(NotNull(ArgNo(1))));
3490 std::optional
<QualType
> StructTimevalTy
= lookupTy("timeval");
3491 std::optional
<QualType
> ConstStructTimevalPtrTy
=
3492 getPointerTy(getConstTy(StructTimevalTy
));
3494 // int utimes(const char *filename, const struct timeval times[2]);
3495 addToFunctionSummaryMap(
3497 Signature(ArgTypes
{ConstCharPtrTy
, ConstStructTimevalPtrTy
},
3500 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
3501 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
3502 .ArgConstraint(NotNull(ArgNo(0))));
3504 // int nanosleep(const struct timespec *rqtp, struct timespec *rmtp);
3505 addToFunctionSummaryMap(
3507 Signature(ArgTypes
{ConstStructTimespecPtrTy
, StructTimespecPtrTy
},
3510 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
3511 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
3512 .ArgConstraint(NotNull(ArgNo(0))));
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
);
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
);
3529 // struct tm * localtime(const time_t *tp);
3530 addToFunctionSummaryMap(
3532 Signature(ArgTypes
{ConstTime_tPtrTy
}, RetType
{StructTmPtrTy
}),
3533 Summary(NoEvalCall
).ArgConstraint(NotNull(ArgNo(0))));
3535 // struct tm *localtime_r(const time_t *restrict timer,
3536 // struct tm *restrict result);
3537 addToFunctionSummaryMap(
3539 Signature(ArgTypes
{ConstTime_tPtrRestrictTy
, StructTmPtrRestrictTy
},
3540 RetType
{StructTmPtrTy
}),
3542 .ArgConstraint(NotNull(ArgNo(0)))
3543 .ArgConstraint(NotNull(ArgNo(1))));
3545 // char *asctime_r(const struct tm *restrict tm, char *restrict buf);
3546 addToFunctionSummaryMap(
3548 Signature(ArgTypes
{ConstStructTmPtrRestrictTy
, CharPtrRestrictTy
},
3549 RetType
{CharPtrTy
}),
3551 .ArgConstraint(NotNull(ArgNo(0)))
3552 .ArgConstraint(NotNull(ArgNo(1)))
3553 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
3554 /*MinBufSize=*/BVF
.getValue(26, IntTy
))));
3556 // char *ctime_r(const time_t *timep, char *buf);
3557 addToFunctionSummaryMap(
3559 Signature(ArgTypes
{ConstTime_tPtrTy
, CharPtrTy
}, RetType
{CharPtrTy
}),
3561 .ArgConstraint(NotNull(ArgNo(0)))
3562 .ArgConstraint(NotNull(ArgNo(1)))
3563 .ArgConstraint(BufferSize(
3564 /*Buffer=*/ArgNo(1),
3565 /*MinBufSize=*/BVF
.getValue(26, IntTy
))));
3567 // struct tm *gmtime_r(const time_t *restrict timer,
3568 // struct tm *restrict result);
3569 addToFunctionSummaryMap(
3571 Signature(ArgTypes
{ConstTime_tPtrRestrictTy
, StructTmPtrRestrictTy
},
3572 RetType
{StructTmPtrTy
}),
3574 .ArgConstraint(NotNull(ArgNo(0)))
3575 .ArgConstraint(NotNull(ArgNo(1))));
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))));
3582 std::optional
<QualType
> Clockid_tTy
= lookupTy("clockid_t");
3584 // int clock_gettime(clockid_t clock_id, struct timespec *tp);
3585 addToFunctionSummaryMap(
3587 Signature(ArgTypes
{Clockid_tTy
, StructTimespecPtrTy
}, RetType
{IntTy
}),
3589 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
3590 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
3591 .ArgConstraint(NotNull(ArgNo(1))));
3593 std::optional
<QualType
> StructItimervalTy
= lookupTy("itimerval");
3594 std::optional
<QualType
> StructItimervalPtrTy
=
3595 getPointerTy(StructItimervalTy
);
3597 // int getitimer(int which, struct itimerval *curr_value);
3598 addToFunctionSummaryMap(
3600 Signature(ArgTypes
{IntTy
, StructItimervalPtrTy
}, RetType
{IntTy
}),
3602 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
3603 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
3604 .ArgConstraint(NotNull(ArgNo(1))));
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
);
3632 QualType PthreadStartRoutineTy
= getPointerTy(
3633 ACtx
.getFunctionType(/*ResultTy=*/VoidPtrTy
, /*Args=*/VoidPtrTy
,
3634 FunctionProtoType::ExtProtoInfo()));
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))));
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(
3648 Signature(ArgTypes
{Pthread_tPtrRestrictTy
,
3649 ConstPthread_attr_tPtrRestrictTy
,
3650 PthreadStartRoutineTy
, VoidPtrRestrictTy
},
3653 .ArgConstraint(NotNull(ArgNo(0)))
3654 .ArgConstraint(NotNull(ArgNo(2))));
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))));
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
},
3672 .ArgConstraint(NotNull(ArgNo(0)))
3673 .ArgConstraint(NotNull(ArgNo(1))));
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
}),
3681 .ArgConstraint(NotNull(ArgNo(0)))
3683 ArgumentCondition(1, WithinRange
, Range(0, SizeMax
))));
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
},
3692 Summary(NoEvalCall
).ArgConstraint(NotNull(ArgNo(0))));
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))));
3705 // Functions for testing.
3706 if (AddTestFunctions
) {
3707 const RangeInt IntMin
= BVF
.getMinValue(IntTy
).getLimitedValue();
3709 addToFunctionSummaryMap(
3710 "__not_null", Signature(ArgTypes
{IntPtrTy
}, RetType
{IntTy
}),
3711 Summary(EvalCallAsPure
).ArgConstraint(NotNull(ArgNo(0))));
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))));
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
}))));
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
)
3849 ArgumentCondition(0U, OutOfRange
, Range({1, 2}, {4, IntMax
}))));
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))));
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(
3874 Signature(ArgTypes
{Irrelevant
, IntTy
}, RetType
{IntTy
}),
3875 Summary(EvalCallAsPure
).ArgConstraint(NotNull(ArgNo(0))));
3876 addToFunctionSummaryMap(
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
)
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
));
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))},
3922 .Case({ArgumentCondition(0U, WithinRange
,
3923 IntRangeVector
{{3, 3}, {7, IntMax
}}),
3924 ReturnValueCondition(WithinRange
, SingleValue(2))},
3926 .Case({ArgumentCondition(0U, WithinRange
,
3927 IntRangeVector
{{IntMin
, 0}, {7, IntMax
}}),
3928 ReturnValueCondition(WithinRange
, SingleValue(3))},
3930 .Case({ArgumentCondition(
3932 IntRangeVector
{{IntMin
, 0}, {3, 3}, {7, IntMax
}}),
3933 ReturnValueCondition(WithinRange
, SingleValue(4))},
3938 void 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
;
3949 bool ento::shouldRegisterStdCLibraryFunctionsChecker(
3950 const CheckerManager
&mgr
) {
3954 void ento::registerStdCLibraryFunctionsTesterChecker(CheckerManager
&mgr
) {
3955 auto *Checker
= mgr
.getChecker
<StdLibraryFunctionsChecker
>();
3956 Checker
->AddTestFunctions
= true;
3959 bool ento::shouldRegisterStdCLibraryFunctionsTesterChecker(
3960 const CheckerManager
&mgr
) {