4 #include "llvm/Support/FormatVariadic.h" 10 class PlacementNewChecker :
public Checker<check::PreStmt<CXXNewExpr>> {
12 void checkPreStmt(
const CXXNewExpr *
NE, CheckerContext &C)
const;
18 CheckerContext &C)
const;
22 CheckerContext &C)
const;
23 BugType BT{
this,
"Insufficient storage for placement new",
28 SVal PlacementNewChecker::getExtentSizeOfPlace(
const Expr *Place,
30 CheckerContext &C)
const {
31 const MemRegion *MRegion = C.getSVal(Place).getAsRegion();
34 RegionOffset
Offset = MRegion->getAsOffset();
35 if (Offset.hasSymbolicOffset())
37 const MemRegion *BaseRegion = MRegion->getBaseRegion();
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);
47 return SvalBuilder.evalBinOp(State, BinaryOperator::Opcode::BO_Sub,
48 ExtentInBytes, OffsetInBytes,
49 SvalBuilder.getArrayIndexType());
52 SVal PlacementNewChecker::getExtentSizeOfNewTarget(
const CXXNewExpr *
NE,
54 CheckerContext &C)
const {
55 SValBuilder &SvalBuilder = C.getSValBuilder();
61 SVal ElementCount = C.getSVal(SizeExpr);
62 if (
auto ElementCountNL = ElementCount.getAs<NonLoc>()) {
64 return SvalBuilder.evalBinOp(
65 State, BO_Mul, *ElementCountNL,
67 SvalBuilder.getArrayIndexType());
74 C.getASTContext().getCharWidth(),
76 return SvalBuilder.makeArrayIndex(I.getZExtValue());
81 void PlacementNewChecker::checkPreStmt(
const CXXNewExpr *NE,
82 CheckerContext &C)
const {
90 SVal SizeOfTarget = getExtentSizeOfNewTarget(NE, State, C);
92 SVal SizeOfPlace = getExtentSizeOfPlace(Place, State, C);
93 const auto SizeOfTargetCI = SizeOfTarget.getAs<nonloc::ConcreteInt>();
96 const auto SizeOfPlaceCI = SizeOfPlace.getAs<nonloc::ConcreteInt>();
100 if (SizeOfPlaceCI->getValue() < SizeOfTargetCI->getValue()) {
101 if (ExplodedNode *N = C.generateErrorNode(State)) {
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());
107 auto R = std::make_unique<PathSensitiveBugReport>(BT, Msg, N);
108 bugreporter::trackExpressionValue(N, Place, *R);
109 C.emitReport(std::move(R));
115 void ento::registerPlacementNewChecker(CheckerManager &mgr) {
116 mgr.registerChecker<PlacementNewChecker>();
119 bool ento::shouldRegisterPlacementNewChecker(
const LangOptions &LO) {
bool isReservedGlobalPlacementOperator() const
Determines whether this operator new or delete is one of the reserved global placement operators: voi...
A (possibly-)qualified type.
const char *const MemoryError
FunctionDecl * getOperatorNew() const
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
unsigned getNumPlacementArgs() const
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
Optional< Expr * > getArraySize()
CharUnits - This is an opaque type for sizes expressed in character units.
QuantityType getQuantity() const
getQuantity - Get the raw integer representation of this quantity.
This represents one expression.
Represents a new-expression for memory allocation and constructor calls, e.g: "new CXXNewExpr(foo)"...
QualType getAllocatedType() const
Dataflow Directional Tag Classes.
bool NE(InterpState &S, CodePtr OpPC)
Expr * getPlacementArg(unsigned I)
CharUnits getTypeSizeInChars(QualType T) const
Return the size of the specified (complete) type T, in characters.