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