clang 10.0.0git

CheckPlacementNew.cpp
Go to the documentation of this file.
1 #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
2 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
3 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
4 #include "llvm/Support/FormatVariadic.h"
5
6 using namespace clang;
7 using namespace ento;
8
9 namespace {
10 class PlacementNewChecker : public Checker<check::PreStmt<CXXNewExpr>> {
11 public:
12 void checkPreStmt(const CXXNewExpr *NE, CheckerContext &C) const;
13
14 private:
15 // Returns the size of the target in a placement new expression.
16 // E.g. in "new (&s) long" it returns the size of `long`.
17 SVal getExtentSizeOfNewTarget(const CXXNewExpr *NE, ProgramStateRef State,
18 CheckerContext &C) const;
19 // Returns the size of the place in a placement new expression.
20 // E.g. in "new (&s) long" it returns the size of `s`.
21 SVal getExtentSizeOfPlace(const Expr *NE, ProgramStateRef State,
22 CheckerContext &C) const;
23 BugType BT{this, "Insufficient storage for placement new",
24 categories::MemoryError};
25 };
26 } // namespace
27
28 SVal PlacementNewChecker::getExtentSizeOfPlace(const Expr *Place,
29 ProgramStateRef State,
30 CheckerContext &C) const {
31 const MemRegion *MRegion = C.getSVal(Place).getAsRegion();
32 if (!MRegion)
33 return UnknownVal();
34 RegionOffset Offset = MRegion->getAsOffset();
35 if (Offset.hasSymbolicOffset())
36 return UnknownVal();
37 const MemRegion *BaseRegion = MRegion->getBaseRegion();
38 if (!BaseRegion)
39 return UnknownVal();
40
41 SValBuilder &SvalBuilder = C.getSValBuilder();
42 NonLoc OffsetInBytes = SvalBuilder.makeArrayIndex(
43 Offset.getOffset() / C.getASTContext().getCharWidth());
44 DefinedOrUnknownSVal ExtentInBytes =
45 BaseRegion->castAs<SubRegion>()->getExtent(SvalBuilder);
46
47 return SvalBuilder.evalBinOp(State, BinaryOperator::Opcode::BO_Sub,
48 ExtentInBytes, OffsetInBytes,
49 SvalBuilder.getArrayIndexType());
50 }
51
52 SVal PlacementNewChecker::getExtentSizeOfNewTarget(const CXXNewExpr *NE,
53 ProgramStateRef State,
54 CheckerContext &C) const {
55 SValBuilder &SvalBuilder = C.getSValBuilder();
56 QualType ElementType = NE->getAllocatedType();
57 ASTContext &AstContext = C.getASTContext();
58 CharUnits TypeSize = AstContext.getTypeSizeInChars(ElementType);
59 if (NE->isArray()) {
60 const Expr *SizeExpr = *NE->getArraySize();
61 SVal ElementCount = C.getSVal(SizeExpr);
62 if (auto ElementCountNL = ElementCount.getAs<NonLoc>()) {
63 // size in Bytes = ElementCountNL * TypeSize
64 return SvalBuilder.evalBinOp(
65 State, BO_Mul, *ElementCountNL,
66 SvalBuilder.makeArrayIndex(TypeSize.getQuantity()),
67 SvalBuilder.getArrayIndexType());
68 }
69 } else {
70 // Create a concrete int whose size in bits and signedness is equal to
71 // ArrayIndexType.
72 llvm::APInt I(AstContext.getTypeSizeInChars(SvalBuilder.getArrayIndexType())
73 .getQuantity() *
74 C.getASTContext().getCharWidth(),
75 TypeSize.getQuantity());
76 return SvalBuilder.makeArrayIndex(I.getZExtValue());
77 }
78 return UnknownVal();
79 }
80
81 void PlacementNewChecker::checkPreStmt(const CXXNewExpr *NE,
82 CheckerContext &C) const {
83 // Check only the default placement new.
84 if (!NE->getOperatorNew()->isReservedGlobalPlacementOperator())
85 return;
86 if (NE->getNumPlacementArgs() == 0)
87 return;
88
89 ProgramStateRef State = C.getState();
90 SVal SizeOfTarget = getExtentSizeOfNewTarget(NE, State, C);
91 const Expr *Place = NE->getPlacementArg(0);
92 SVal SizeOfPlace = getExtentSizeOfPlace(Place, State, C);
93 const auto SizeOfTargetCI = SizeOfTarget.getAs<nonloc::ConcreteInt>();
94 if (!SizeOfTargetCI)
95 return;
96 const auto SizeOfPlaceCI = SizeOfPlace.getAs<nonloc::ConcreteInt>();
97 if (!SizeOfPlaceCI)
98 return;
99
100 if (SizeOfPlaceCI->getValue() < SizeOfTargetCI->getValue()) {
101 if (ExplodedNode *N = C.generateErrorNode(State)) {
102 std::string Msg =
103 llvm::formatv("Storage provided to placement new is only {0} bytes, "
104 "whereas the allocated type requires {1} bytes",
105 SizeOfPlaceCI->getValue(), SizeOfTargetCI->getValue());
106
107 auto R = std::make_unique<PathSensitiveBugReport>(BT, Msg, N);
108 bugreporter::trackExpressionValue(N, Place, *R);
109 C.emitReport(std::move(R));
110 return;
111 }
112 }
113 }
114
115 void ento::registerPlacementNewChecker(CheckerManager &mgr) {
116 mgr.registerChecker<PlacementNewChecker>();
117 }
118
119 bool ento::shouldRegisterPlacementNewChecker(const LangOptions &LO) {
120 return true;
121 }
ento
clang::FunctionDecl::isReservedGlobalPlacementOperator
bool isReservedGlobalPlacementOperator() const
Determines whether this operator new or delete is one of the reserved global placement operators: voi...
Definition: Decl.cpp:2961
clang::QualType
A (possibly-)qualified type.
Definition: Type.h:654
clang::ento::categories::MemoryError
const char *const MemoryError
Definition: CommonBugCategories.cpp:18
clang::CXXNewExpr::getOperatorNew
FunctionDecl * getOperatorNew() const
Definition: ExprCXX.h:2218
clang::ento::ProgramStateRef
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
Definition: ProgramState_Fwd.h:37
BugType.h
clang::CXXNewExpr::getNumPlacementArgs
unsigned getNumPlacementArgs() const
Definition: ExprCXX.h:2236
clang::ASTContext
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:168
State
LineState State
Definition: UnwrappedLineFormatter.cpp:932
clang::LangOptions
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
Definition: LangOptions.h:53
clang::CXXNewExpr::getArraySize
Optional< Expr * > getArraySize()
Definition: ExprCXX.h:2225
clang::CharUnits
CharUnits - This is an opaque type for sizes expressed in character units.
Definition: CharUnits.h:38
clang::CharUnits::getQuantity
QuantityType getQuantity() const
getQuantity - Get the raw integer representation of this quantity.
Definition: CharUnits.h:179
Offset
unsigned Offset
Definition: Format.cpp:1827
clang::Expr
This represents one expression.
Definition: Expr.h:108
BuiltinCheckerRegistration.h
clang::CXXNewExpr
Represents a new-expression for memory allocation and constructor calls, e.g: "new CXXNewExpr(foo)"...
Definition: ExprCXX.h:2100
clang::CXXNewExpr::getAllocatedType
QualType getAllocatedType() const
Definition: ExprCXX.h:2193
clang::CXXNewExpr::isArray
bool isArray() const
Definition: ExprCXX.h:2223
clang::interp::APInt
llvm::APInt APInt
Definition: Integral.h:27
clang
Dataflow Directional Tag Classes.
Definition: CFGReachabilityAnalysis.h:21
clang::interp::NE
bool NE(InterpState &S, CodePtr OpPC)
Definition: Interp.h:223
clang::CXXNewExpr::getPlacementArg
Expr * getPlacementArg(unsigned I)
Definition: ExprCXX.h:2245
clang::ASTContext::getTypeSizeInChars
CharUnits getTypeSizeInChars(QualType T) const
Return the size of the specified (complete) type T, in characters.
Definition: ASTContext.cpp:2383
CheckerContext.h