1 | //===- DynamicExtent.cpp - Dynamic extent 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 file defines APIs that track and query dynamic extent information. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicExtent.h" |
14 | #include "clang/AST/Expr.h" |
15 | #include "clang/Basic/LLVM.h" |
16 | #include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h" |
17 | #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" |
18 | #include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h" |
19 | #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" |
20 | #include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h" |
21 | |
22 | REGISTER_MAP_WITH_PROGRAMSTATE(DynamicExtentMap, const clang::ento::MemRegion *, |
23 | clang::ento::DefinedOrUnknownSVal) |
24 | |
25 | namespace clang { |
26 | namespace ento { |
27 | |
28 | DefinedOrUnknownSVal getDynamicExtent(ProgramStateRef State, |
29 | const MemRegion *MR, SValBuilder &SVB) { |
30 | MR = MR->StripCasts(); |
31 | |
32 | if (const DefinedOrUnknownSVal *Size = State->get<DynamicExtentMap>(key: MR)) |
33 | if (auto SSize = |
34 | SVB.convertToArrayIndex(val: *Size).getAs<DefinedOrUnknownSVal>()) |
35 | return *SSize; |
36 | |
37 | return MR->getMemRegionManager().getStaticSize(MR, SVB); |
38 | } |
39 | |
40 | DefinedOrUnknownSVal getElementExtent(QualType Ty, SValBuilder &SVB) { |
41 | return SVB.makeIntVal(integer: SVB.getContext().getTypeSizeInChars(T: Ty).getQuantity(), |
42 | type: SVB.getArrayIndexType()); |
43 | } |
44 | |
45 | static DefinedOrUnknownSVal getConstantArrayElementCount(SValBuilder &SVB, |
46 | const MemRegion *MR) { |
47 | MR = MR->StripCasts(); |
48 | |
49 | const auto *TVR = MR->getAs<TypedValueRegion>(); |
50 | if (!TVR) |
51 | return UnknownVal(); |
52 | |
53 | if (const ConstantArrayType *CAT = |
54 | SVB.getContext().getAsConstantArrayType(T: TVR->getValueType())) |
55 | return SVB.makeIntVal(integer: CAT->getSize(), /* isUnsigned = */ false); |
56 | |
57 | return UnknownVal(); |
58 | } |
59 | |
60 | static DefinedOrUnknownSVal |
61 | getDynamicElementCount(ProgramStateRef State, SVal Size, |
62 | DefinedOrUnknownSVal ElementSize) { |
63 | SValBuilder &SVB = State->getStateManager().getSValBuilder(); |
64 | |
65 | auto ElementCount = |
66 | SVB.evalBinOp(state: State, op: BO_Div, lhs: Size, rhs: ElementSize, type: SVB.getArrayIndexType()) |
67 | .getAs<DefinedOrUnknownSVal>(); |
68 | return ElementCount.value_or(u: UnknownVal()); |
69 | } |
70 | |
71 | DefinedOrUnknownSVal getDynamicElementCount(ProgramStateRef State, |
72 | const MemRegion *MR, |
73 | SValBuilder &SVB, |
74 | QualType ElementTy) { |
75 | assert(MR != nullptr && "Not-null region expected" ); |
76 | MR = MR->StripCasts(); |
77 | |
78 | DefinedOrUnknownSVal ElementSize = getElementExtent(Ty: ElementTy, SVB); |
79 | if (ElementSize.isZeroConstant()) |
80 | return getConstantArrayElementCount(SVB, MR); |
81 | |
82 | return getDynamicElementCount(State, Size: getDynamicExtent(State, MR, SVB), |
83 | ElementSize); |
84 | } |
85 | |
86 | SVal getDynamicExtentWithOffset(ProgramStateRef State, SVal BufV) { |
87 | SValBuilder &SVB = State->getStateManager().getSValBuilder(); |
88 | const MemRegion *MRegion = BufV.getAsRegion(); |
89 | if (!MRegion) |
90 | return UnknownVal(); |
91 | RegionOffset Offset = MRegion->getAsOffset(); |
92 | if (Offset.hasSymbolicOffset()) |
93 | return UnknownVal(); |
94 | const MemRegion *BaseRegion = MRegion->getBaseRegion(); |
95 | if (!BaseRegion) |
96 | return UnknownVal(); |
97 | |
98 | NonLoc OffsetInChars = |
99 | SVB.makeArrayIndex(idx: Offset.getOffset() / SVB.getContext().getCharWidth()); |
100 | DefinedOrUnknownSVal ExtentInBytes = getDynamicExtent(State, MR: BaseRegion, SVB); |
101 | |
102 | return SVB.evalBinOp(state: State, op: BinaryOperator::Opcode::BO_Sub, lhs: ExtentInBytes, |
103 | rhs: OffsetInChars, type: SVB.getArrayIndexType()); |
104 | } |
105 | |
106 | DefinedOrUnknownSVal getDynamicElementCountWithOffset(ProgramStateRef State, |
107 | SVal BufV, |
108 | QualType ElementTy) { |
109 | const MemRegion *MR = BufV.getAsRegion(); |
110 | if (!MR) |
111 | return UnknownVal(); |
112 | |
113 | SValBuilder &SVB = State->getStateManager().getSValBuilder(); |
114 | DefinedOrUnknownSVal ElementSize = getElementExtent(Ty: ElementTy, SVB); |
115 | if (ElementSize.isZeroConstant()) |
116 | return getConstantArrayElementCount(SVB, MR); |
117 | |
118 | return getDynamicElementCount(State, Size: getDynamicExtentWithOffset(State, BufV), |
119 | ElementSize); |
120 | } |
121 | |
122 | ProgramStateRef setDynamicExtent(ProgramStateRef State, const MemRegion *MR, |
123 | DefinedOrUnknownSVal Size, SValBuilder &SVB) { |
124 | MR = MR->StripCasts(); |
125 | |
126 | if (Size.isUnknown()) |
127 | return State; |
128 | |
129 | return State->set<DynamicExtentMap>(K: MR->StripCasts(), E: Size); |
130 | } |
131 | |
132 | } // namespace ento |
133 | } // namespace clang |
134 | |