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