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>(MR)) 33 if (auto SSize = 34 SVB.convertToArrayIndex(*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(SVB.getContext().getTypeSizeInChars(Ty).getQuantity(), 42 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(TVR->getValueType())) 55 return SVB.makeIntVal(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, BO_Div, Size, ElementSize, SVB.getArrayIndexType()) 67 .getAs<DefinedOrUnknownSVal>(); 68 return ElementCount.value_or(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(ElementTy, SVB); 79 if (ElementSize.isZeroConstant()) 80 return getConstantArrayElementCount(SVB, MR); 81 82 return getDynamicElementCount(State, 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(Offset.getOffset() / SVB.getContext().getCharWidth()); 100 DefinedOrUnknownSVal ExtentInBytes = getDynamicExtent(State, BaseRegion, SVB); 101 102 return SVB.evalBinOp(State, BinaryOperator::Opcode::BO_Sub, ExtentInBytes, 103 OffsetInChars, 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(ElementTy, SVB); 115 if (ElementSize.isZeroConstant()) 116 return getConstantArrayElementCount(SVB, MR); 117 118 return getDynamicElementCount(State, 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>(MR->StripCasts(), Size); 130 } 131 132 } // namespace ento 133 } // namespace clang 134