clang 24.0.0git
BoundsChecking.h
Go to the documentation of this file.
1//===- BoundsChecking.h - Bounds checking related APIs ----------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This header declares 'checkBounds', a function that compares memory offsets
10// (that may be symbolic) and uses heuristical workarounds to provide more
11// accurate results than directly calling evalBinOp or assumeInBound.
12//
13// As of now, this logic only supports the needs of `security.ArrayBound`, but
14// in the future it will be generalized and applied in all checkers that
15// perform bounds checking (to bring them out of `alpha` stage).
16//
17// TODO: This header should be extended by other utilities (e.g. message
18// formatting tools) that are relevant for multiple bounds checking checkers.
19//
20//===----------------------------------------------------------------------===//
21
22#ifndef LLVM_CLANG_STATICANALYZER_CHECKERS_BOUNDSCHECKING_H
23#define LLVM_CLANG_STATICANALYZER_CHECKERS_BOUNDSCHECKING_H
25#include <optional>
26
28
29struct CheckFlags {
30 unsigned CheckUnderflow : 1;
32 unsigned AlsoAcceptEquality : 1;
33};
34
35class CheckResult;
36
37/// Checks the validity of accessing a memory region with extent \p Extent at
38/// offset \p Offset. The \p Flags influence the semantics of the check.
40 std::optional<NonLoc> Extent, CheckFlags Flags);
41
42class CheckResult {
43public:
44 /// When true, the bounds check noticed that the value of an unsigned
45 /// expression is constrained to negative values (because the analyzer
46 /// skipped the modeling of a cast expression). This execution path must be
47 /// discarded because it does not represent a real possibility.
48 /// FIXME: This hack is currently needed to filter out many ugly false
49 /// positives; but it should be removed when we fix cast modeling.
50 bool isCorruptedState() const { return IsCorruptedState; }
51
52 /// When true, the checked offset may be in bounds.
53 bool mayBeInBounds() const { return static_cast<bool>(InBoundsState); }
54
55 /// When true, the checked offset may be negative.
56 bool mayUnderflow() const { return MayUnderflow; }
57 /// When true, the checked offset may be >= the extent of the region.
58 bool mayOverflow() const { return ExtentIfMayOverflow.has_value(); }
59 /// When true, the checked offset may be out of bounds.
60 bool mayBeInvalid() const { return MayUnderflow || ExtentIfMayOverflow; }
61
62 /// Returns the offset of the accessed location from the beginning of the
63 /// accessd region.
64 NonLoc getOffset() const { return Offset; }
65
66 /// Returns the extent of the accessed region if it is relevant (because the
67 /// offset may overflow it), otherwise returns std::nullopt.
68 std::optional<NonLoc> getExtentIfMayOverflow() const {
69 return ExtentIfMayOverflow;
70 }
71
72 /// Returns the program state that should be used for continuing the analysis
73 /// after this bounds check. This returns null if mayBeInBounds() is false, in
74 /// that case the state before the check should be used in the error node.
75 ProgramStateRef getInBoundsState() const { return InBoundsState; }
76
77 friend CheckResult checkBounds(ProgramStateRef State, SValBuilder &SVB,
78 NonLoc Offset, std::optional<NonLoc> Extent,
79 CheckFlags Flags);
80
81private:
82 // Offset of the accessed location, measured from the start of the region.
83 // TODO: As of now, the offset and the extent are always measured in bytes,
84 // but we will probably need to allow other size units in the future.
85 const NonLoc Offset;
86
87 explicit CheckResult(NonLoc Offs) : Offset(Offs) {}
88
89 bool IsCorruptedState = false;
90 bool MayUnderflow = false;
91 std::optional<NonLoc> ExtentIfMayOverflow = std::nullopt;
92 ProgramStateRef InBoundsState = nullptr;
93};
94
95enum class Comparison { LT, LE, EQ };
96
98 switch (C) {
99 case Comparison::LT:
100 return BO_LT;
101 case Comparison::LE:
102 return BO_LE;
103 case Comparison::EQ:
104 return BO_EQ;
105 }
106 llvm_unreachable("unhandled Comparison kind");
107}
108
109// Evaluates the comparison \p Value \p CmpKind \p Threshold; and splits the
110// state, returning a pair {ComparisonTrueState, ComparisonFalseState}.
111// May return {nullptr, nullptr} when `evalBinOp` fails.
112// This uses a custom simplification algorithm that approximates a mathematical
113// comparison between the two numbers; ignoring overflow and heuristically
114// avoiding the automatic conversions done by the underlying `evalBinOp`.
115std::pair<ProgramStateRef, ProgramStateRef>
117 NonLoc Threshold, Comparison CmpKind);
118} // namespace clang::ento::bounds
119
120#endif // LLVM_CLANG_STATICANALYZER_CHECKERS_BOUNDSCHECKING_H
BinaryOperatorKind Opcode
Definition Expr.h:4087
bool mayBeInBounds() const
When true, the checked offset may be in bounds.
bool mayBeInvalid() const
When true, the checked offset may be out of bounds.
bool mayUnderflow() const
When true, the checked offset may be negative.
NonLoc getOffset() const
Returns the offset of the accessed location from the beginning of the accessd region.
friend CheckResult checkBounds(ProgramStateRef State, SValBuilder &SVB, NonLoc Offset, std::optional< NonLoc > Extent, CheckFlags Flags)
Checks the validity of accessing a memory region with extent Extent at offset Offset.
ProgramStateRef getInBoundsState() const
Returns the program state that should be used for continuing the analysis after this bounds check.
bool mayOverflow() const
When true, the checked offset may be >= the extent of the region.
bool isCorruptedState() const
When true, the bounds check noticed that the value of an unsigned expression is constrained to negati...
std::optional< NonLoc > getExtentIfMayOverflow() const
Returns the extent of the accessed region if it is relevant (because the offset may overflow it),...
std::pair< ProgramStateRef, ProgramStateRef > compareValueToThreshold(ProgramStateRef State, SValBuilder &SVB, NonLoc Value, NonLoc Threshold, Comparison CmpKind)
BinaryOperator::Opcode asOpcode(Comparison C)
CheckResult checkBounds(ProgramStateRef State, SValBuilder &SVB, NonLoc Offset, std::optional< NonLoc > Extent, CheckFlags Flags)
Checks the validity of accessing a memory region with extent Extent at offset Offset.
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
@ Comparison
A comparison.
Definition Sema.h:661