/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/StaticAnalyzer/Core/DynamicExtent.cpp
Line | Count | Source (jump to first uncovered line) |
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 | 75.5k | const MemRegion *MR, SValBuilder &SVB) { |
30 | 75.5k | MR = MR->StripCasts(); |
31 | | |
32 | 75.5k | if (const DefinedOrUnknownSVal *Size = State->get<DynamicExtentMap>(MR)) |
33 | 820 | if (auto SSize = |
34 | 820 | SVB.convertToArrayIndex(*Size).getAs<DefinedOrUnknownSVal>()) |
35 | 820 | return *SSize; |
36 | | |
37 | 74.7k | return MR->getMemRegionManager().getStaticSize(MR, SVB); |
38 | 75.5k | } |
39 | | |
40 | 93.5k | DefinedOrUnknownSVal getElementExtent(QualType Ty, SValBuilder &SVB) { |
41 | 93.5k | return SVB.makeIntVal(SVB.getContext().getTypeSizeInChars(Ty).getQuantity(), |
42 | 93.5k | SVB.getArrayIndexType()); |
43 | 93.5k | } |
44 | | |
45 | | static DefinedOrUnknownSVal getConstantArrayElementCount(SValBuilder &SVB, |
46 | 2 | const MemRegion *MR) { |
47 | 2 | MR = MR->StripCasts(); |
48 | | |
49 | 2 | const auto *TVR = MR->getAs<TypedValueRegion>(); |
50 | 2 | if (!TVR) |
51 | 0 | return UnknownVal(); |
52 | | |
53 | 2 | if (const ConstantArrayType *CAT = |
54 | 2 | SVB.getContext().getAsConstantArrayType(TVR->getValueType())) |
55 | 2 | return SVB.makeIntVal(CAT->getSize(), /* isUnsigned = */ false); |
56 | | |
57 | 0 | return UnknownVal(); |
58 | 2 | } |
59 | | |
60 | | static DefinedOrUnknownSVal |
61 | | getDynamicElementCount(ProgramStateRef State, SVal Size, |
62 | 843 | DefinedOrUnknownSVal ElementSize) { |
63 | 843 | SValBuilder &SVB = State->getStateManager().getSValBuilder(); |
64 | | |
65 | 843 | auto ElementCount = |
66 | 843 | SVB.evalBinOp(State, BO_Div, Size, ElementSize, SVB.getArrayIndexType()) |
67 | 843 | .getAs<DefinedOrUnknownSVal>(); |
68 | 843 | return ElementCount.value_or(UnknownVal()); |
69 | 843 | } |
70 | | |
71 | | DefinedOrUnknownSVal getDynamicElementCount(ProgramStateRef State, |
72 | | const MemRegion *MR, |
73 | | SValBuilder &SVB, |
74 | 822 | QualType ElementTy) { |
75 | 822 | assert(MR != nullptr && "Not-null region expected"); |
76 | 822 | MR = MR->StripCasts(); |
77 | | |
78 | 822 | DefinedOrUnknownSVal ElementSize = getElementExtent(ElementTy, SVB); |
79 | 822 | if (ElementSize.isZeroConstant()) |
80 | 0 | return getConstantArrayElementCount(SVB, MR); |
81 | | |
82 | 822 | return getDynamicElementCount(State, getDynamicExtent(State, MR, SVB), |
83 | 822 | ElementSize); |
84 | 822 | } |
85 | | |
86 | 595 | SVal getDynamicExtentWithOffset(ProgramStateRef State, SVal BufV) { |
87 | 595 | SValBuilder &SVB = State->getStateManager().getSValBuilder(); |
88 | 595 | const MemRegion *MRegion = BufV.getAsRegion(); |
89 | 595 | if (!MRegion) |
90 | 0 | return UnknownVal(); |
91 | 595 | RegionOffset Offset = MRegion->getAsOffset(); |
92 | 595 | if (Offset.hasSymbolicOffset()) |
93 | 0 | return UnknownVal(); |
94 | 595 | const MemRegion *BaseRegion = MRegion->getBaseRegion(); |
95 | 595 | if (!BaseRegion) |
96 | 0 | return UnknownVal(); |
97 | | |
98 | 595 | NonLoc OffsetInChars = |
99 | 595 | SVB.makeArrayIndex(Offset.getOffset() / SVB.getContext().getCharWidth()); |
100 | 595 | DefinedOrUnknownSVal ExtentInBytes = getDynamicExtent(State, BaseRegion, SVB); |
101 | | |
102 | 595 | return SVB.evalBinOp(State, BinaryOperator::Opcode::BO_Sub, ExtentInBytes, |
103 | 595 | OffsetInChars, SVB.getArrayIndexType()); |
104 | 595 | } |
105 | | |
106 | | DefinedOrUnknownSVal getDynamicElementCountWithOffset(ProgramStateRef State, |
107 | | SVal BufV, |
108 | 23 | QualType ElementTy) { |
109 | 23 | const MemRegion *MR = BufV.getAsRegion(); |
110 | 23 | if (!MR) |
111 | 0 | return UnknownVal(); |
112 | | |
113 | 23 | SValBuilder &SVB = State->getStateManager().getSValBuilder(); |
114 | 23 | DefinedOrUnknownSVal ElementSize = getElementExtent(ElementTy, SVB); |
115 | 23 | if (ElementSize.isZeroConstant()) |
116 | 2 | return getConstantArrayElementCount(SVB, MR); |
117 | | |
118 | 21 | return getDynamicElementCount(State, getDynamicExtentWithOffset(State, BufV), |
119 | 21 | ElementSize); |
120 | 23 | } |
121 | | |
122 | | ProgramStateRef setDynamicExtent(ProgramStateRef State, const MemRegion *MR, |
123 | 1.84k | DefinedOrUnknownSVal Size, SValBuilder &SVB) { |
124 | 1.84k | MR = MR->StripCasts(); |
125 | | |
126 | 1.84k | if (Size.isUnknown()) |
127 | 34 | return State; |
128 | | |
129 | 1.81k | return State->set<DynamicExtentMap>(MR->StripCasts(), Size); |
130 | 1.84k | } |
131 | | |
132 | | } // namespace ento |
133 | | } // namespace clang |