xref: /freebsd/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/DynamicExtent.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
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 
getDynamicExtent(ProgramStateRef State,const MemRegion * MR,SValBuilder & SVB)27 DefinedOrUnknownSVal getDynamicExtent(ProgramStateRef State,
28                                       const MemRegion *MR, SValBuilder &SVB) {
29   MR = MR->StripCasts();
30 
31   if (const DefinedOrUnknownSVal *Size = State->get<DynamicExtentMap>(MR))
32     if (auto SSize =
33             SVB.convertToArrayIndex(*Size).getAs<DefinedOrUnknownSVal>())
34       return *SSize;
35 
36   return MR->getMemRegionManager().getStaticSize(MR, SVB);
37 }
38 
getElementExtent(QualType Ty,SValBuilder & SVB)39 DefinedOrUnknownSVal getElementExtent(QualType Ty, SValBuilder &SVB) {
40   return SVB.makeIntVal(SVB.getContext().getTypeSizeInChars(Ty).getQuantity(),
41                         SVB.getArrayIndexType());
42 }
43 
getConstantArrayElementCount(SValBuilder & SVB,const MemRegion * MR)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(TVR->getValueType()))
54     return SVB.makeIntVal(CAT->getSize(), /* isUnsigned = */ false);
55 
56   return UnknownVal();
57 }
58 
59 static DefinedOrUnknownSVal
getDynamicElementCount(ProgramStateRef State,SVal Size,DefinedOrUnknownSVal ElementSize)60 getDynamicElementCount(ProgramStateRef State, SVal Size,
61                        DefinedOrUnknownSVal ElementSize) {
62   SValBuilder &SVB = State->getStateManager().getSValBuilder();
63 
64   auto ElementCount =
65       SVB.evalBinOp(State, BO_Div, Size, ElementSize, SVB.getArrayIndexType())
66           .getAs<DefinedOrUnknownSVal>();
67   return ElementCount.value_or(UnknownVal());
68 }
69 
getDynamicElementCount(ProgramStateRef State,const MemRegion * MR,SValBuilder & SVB,QualType ElementTy)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(ElementTy, SVB);
78   if (ElementSize.isZeroConstant())
79     return getConstantArrayElementCount(SVB, MR);
80 
81   return getDynamicElementCount(State, getDynamicExtent(State, MR, SVB),
82                                 ElementSize);
83 }
84 
getDynamicExtentWithOffset(ProgramStateRef State,SVal BufV)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(Offset.getOffset() / SVB.getContext().getCharWidth());
99   DefinedOrUnknownSVal ExtentInBytes = getDynamicExtent(State, BaseRegion, SVB);
100 
101   return SVB.evalBinOp(State, BinaryOperator::Opcode::BO_Sub, ExtentInBytes,
102                        OffsetInChars, SVB.getArrayIndexType());
103 }
104 
getDynamicElementCountWithOffset(ProgramStateRef State,SVal BufV,QualType ElementTy)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(ElementTy, SVB);
114   if (ElementSize.isZeroConstant())
115     return getConstantArrayElementCount(SVB, MR);
116 
117   return getDynamicElementCount(State, getDynamicExtentWithOffset(State, BufV),
118                                 ElementSize);
119 }
120 
setDynamicExtent(ProgramStateRef State,const MemRegion * MR,DefinedOrUnknownSVal Size)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>(MR->StripCasts(), Size);
129 }
130 
131 } // namespace ento
132 } // namespace clang
133