1fe6060f1SDimitry Andric //===- DynamicExtent.cpp - Dynamic extent related APIs ----------*- C++ -*-===//
2fe6060f1SDimitry Andric //
3fe6060f1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4fe6060f1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5fe6060f1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6fe6060f1SDimitry Andric //
7fe6060f1SDimitry Andric //===----------------------------------------------------------------------===//
8fe6060f1SDimitry Andric //
9fe6060f1SDimitry Andric // This file defines APIs that track and query dynamic extent information.
10fe6060f1SDimitry Andric //
11fe6060f1SDimitry Andric //===----------------------------------------------------------------------===//
12fe6060f1SDimitry Andric
13fe6060f1SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicExtent.h"
14fe6060f1SDimitry Andric #include "clang/AST/Expr.h"
15fe6060f1SDimitry Andric #include "clang/Basic/LLVM.h"
16fe6060f1SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
17fe6060f1SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
18fe6060f1SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h"
19fe6060f1SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
20fe6060f1SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
21fe6060f1SDimitry Andric
22fe6060f1SDimitry Andric REGISTER_MAP_WITH_PROGRAMSTATE(DynamicExtentMap, const clang::ento::MemRegion *,
23fe6060f1SDimitry Andric clang::ento::DefinedOrUnknownSVal)
24fe6060f1SDimitry Andric
25fe6060f1SDimitry Andric namespace clang {
26fe6060f1SDimitry Andric namespace ento {
27fe6060f1SDimitry Andric
getDynamicExtent(ProgramStateRef State,const MemRegion * MR,SValBuilder & SVB)28fe6060f1SDimitry Andric DefinedOrUnknownSVal getDynamicExtent(ProgramStateRef State,
29fe6060f1SDimitry Andric const MemRegion *MR, SValBuilder &SVB) {
30fe6060f1SDimitry Andric MR = MR->StripCasts();
31fe6060f1SDimitry Andric
32fe6060f1SDimitry Andric if (const DefinedOrUnknownSVal *Size = State->get<DynamicExtentMap>(MR))
33*5f757f3fSDimitry Andric if (auto SSize =
34*5f757f3fSDimitry Andric SVB.convertToArrayIndex(*Size).getAs<DefinedOrUnknownSVal>())
35*5f757f3fSDimitry Andric return *SSize;
36fe6060f1SDimitry Andric
37fe6060f1SDimitry Andric return MR->getMemRegionManager().getStaticSize(MR, SVB);
38fe6060f1SDimitry Andric }
39fe6060f1SDimitry Andric
getElementExtent(QualType Ty,SValBuilder & SVB)40fe6060f1SDimitry Andric DefinedOrUnknownSVal getElementExtent(QualType Ty, SValBuilder &SVB) {
41fe6060f1SDimitry Andric return SVB.makeIntVal(SVB.getContext().getTypeSizeInChars(Ty).getQuantity(),
42fe6060f1SDimitry Andric SVB.getArrayIndexType());
43fe6060f1SDimitry Andric }
44fe6060f1SDimitry Andric
getConstantArrayElementCount(SValBuilder & SVB,const MemRegion * MR)45*5f757f3fSDimitry Andric static DefinedOrUnknownSVal getConstantArrayElementCount(SValBuilder &SVB,
46*5f757f3fSDimitry Andric const MemRegion *MR) {
47*5f757f3fSDimitry Andric MR = MR->StripCasts();
48*5f757f3fSDimitry Andric
49*5f757f3fSDimitry Andric const auto *TVR = MR->getAs<TypedValueRegion>();
50*5f757f3fSDimitry Andric if (!TVR)
51*5f757f3fSDimitry Andric return UnknownVal();
52*5f757f3fSDimitry Andric
53*5f757f3fSDimitry Andric if (const ConstantArrayType *CAT =
54*5f757f3fSDimitry Andric SVB.getContext().getAsConstantArrayType(TVR->getValueType()))
55*5f757f3fSDimitry Andric return SVB.makeIntVal(CAT->getSize(), /* isUnsigned = */ false);
56*5f757f3fSDimitry Andric
57*5f757f3fSDimitry Andric return UnknownVal();
58*5f757f3fSDimitry Andric }
59*5f757f3fSDimitry Andric
60*5f757f3fSDimitry Andric static DefinedOrUnknownSVal
getDynamicElementCount(ProgramStateRef State,SVal Size,DefinedOrUnknownSVal ElementSize)61*5f757f3fSDimitry Andric getDynamicElementCount(ProgramStateRef State, SVal Size,
62*5f757f3fSDimitry Andric DefinedOrUnknownSVal ElementSize) {
63*5f757f3fSDimitry Andric SValBuilder &SVB = State->getStateManager().getSValBuilder();
64*5f757f3fSDimitry Andric
65*5f757f3fSDimitry Andric auto ElementCount =
66*5f757f3fSDimitry Andric SVB.evalBinOp(State, BO_Div, Size, ElementSize, SVB.getArrayIndexType())
67*5f757f3fSDimitry Andric .getAs<DefinedOrUnknownSVal>();
68*5f757f3fSDimitry Andric return ElementCount.value_or(UnknownVal());
69*5f757f3fSDimitry Andric }
70*5f757f3fSDimitry Andric
getDynamicElementCount(ProgramStateRef State,const MemRegion * MR,SValBuilder & SVB,QualType ElementTy)71fe6060f1SDimitry Andric DefinedOrUnknownSVal getDynamicElementCount(ProgramStateRef State,
72fe6060f1SDimitry Andric const MemRegion *MR,
73fe6060f1SDimitry Andric SValBuilder &SVB,
74fe6060f1SDimitry Andric QualType ElementTy) {
75bdd1243dSDimitry Andric assert(MR != nullptr && "Not-null region expected");
76fe6060f1SDimitry Andric MR = MR->StripCasts();
77fe6060f1SDimitry Andric
78*5f757f3fSDimitry Andric DefinedOrUnknownSVal ElementSize = getElementExtent(ElementTy, SVB);
79*5f757f3fSDimitry Andric if (ElementSize.isZeroConstant())
80*5f757f3fSDimitry Andric return getConstantArrayElementCount(SVB, MR);
81fe6060f1SDimitry Andric
82*5f757f3fSDimitry Andric return getDynamicElementCount(State, getDynamicExtent(State, MR, SVB),
83*5f757f3fSDimitry Andric ElementSize);
84fe6060f1SDimitry Andric }
85fe6060f1SDimitry Andric
getDynamicExtentWithOffset(ProgramStateRef State,SVal BufV)86fe6060f1SDimitry Andric SVal getDynamicExtentWithOffset(ProgramStateRef State, SVal BufV) {
87*5f757f3fSDimitry Andric SValBuilder &SVB = State->getStateManager().getSValBuilder();
88fe6060f1SDimitry Andric const MemRegion *MRegion = BufV.getAsRegion();
89fe6060f1SDimitry Andric if (!MRegion)
90fe6060f1SDimitry Andric return UnknownVal();
91fe6060f1SDimitry Andric RegionOffset Offset = MRegion->getAsOffset();
92fe6060f1SDimitry Andric if (Offset.hasSymbolicOffset())
93fe6060f1SDimitry Andric return UnknownVal();
94fe6060f1SDimitry Andric const MemRegion *BaseRegion = MRegion->getBaseRegion();
95fe6060f1SDimitry Andric if (!BaseRegion)
96fe6060f1SDimitry Andric return UnknownVal();
97fe6060f1SDimitry Andric
98*5f757f3fSDimitry Andric NonLoc OffsetInChars =
99*5f757f3fSDimitry Andric SVB.makeArrayIndex(Offset.getOffset() / SVB.getContext().getCharWidth());
100*5f757f3fSDimitry Andric DefinedOrUnknownSVal ExtentInBytes = getDynamicExtent(State, BaseRegion, SVB);
101fe6060f1SDimitry Andric
102*5f757f3fSDimitry Andric return SVB.evalBinOp(State, BinaryOperator::Opcode::BO_Sub, ExtentInBytes,
103*5f757f3fSDimitry Andric OffsetInChars, SVB.getArrayIndexType());
104*5f757f3fSDimitry Andric }
105*5f757f3fSDimitry Andric
getDynamicElementCountWithOffset(ProgramStateRef State,SVal BufV,QualType ElementTy)106*5f757f3fSDimitry Andric DefinedOrUnknownSVal getDynamicElementCountWithOffset(ProgramStateRef State,
107*5f757f3fSDimitry Andric SVal BufV,
108*5f757f3fSDimitry Andric QualType ElementTy) {
109*5f757f3fSDimitry Andric const MemRegion *MR = BufV.getAsRegion();
110*5f757f3fSDimitry Andric if (!MR)
111*5f757f3fSDimitry Andric return UnknownVal();
112*5f757f3fSDimitry Andric
113*5f757f3fSDimitry Andric SValBuilder &SVB = State->getStateManager().getSValBuilder();
114*5f757f3fSDimitry Andric DefinedOrUnknownSVal ElementSize = getElementExtent(ElementTy, SVB);
115*5f757f3fSDimitry Andric if (ElementSize.isZeroConstant())
116*5f757f3fSDimitry Andric return getConstantArrayElementCount(SVB, MR);
117*5f757f3fSDimitry Andric
118*5f757f3fSDimitry Andric return getDynamicElementCount(State, getDynamicExtentWithOffset(State, BufV),
119*5f757f3fSDimitry Andric ElementSize);
120fe6060f1SDimitry Andric }
121fe6060f1SDimitry Andric
setDynamicExtent(ProgramStateRef State,const MemRegion * MR,DefinedOrUnknownSVal Size,SValBuilder & SVB)122fe6060f1SDimitry Andric ProgramStateRef setDynamicExtent(ProgramStateRef State, const MemRegion *MR,
123fe6060f1SDimitry Andric DefinedOrUnknownSVal Size, SValBuilder &SVB) {
124fe6060f1SDimitry Andric MR = MR->StripCasts();
125fe6060f1SDimitry Andric
126fe6060f1SDimitry Andric if (Size.isUnknown())
127fe6060f1SDimitry Andric return State;
128fe6060f1SDimitry Andric
129fe6060f1SDimitry Andric return State->set<DynamicExtentMap>(MR->StripCasts(), Size);
130fe6060f1SDimitry Andric }
131fe6060f1SDimitry Andric
132fe6060f1SDimitry Andric } // namespace ento
133fe6060f1SDimitry Andric } // namespace clang
134