| 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 | |