17#include "llvm/Support/FormatVariadic.h"
23class PlacementNewChecker :
public Checker<check::PreStmt<CXXNewExpr>> {
28 bool checkPlaceCapacityIsSufficient(
const CXXNewExpr *NE,
31 bool checkPlaceIsAlignedProperly(
const CXXNewExpr *NE,
43 unsigned AllocatedTAlign,
44 unsigned StorageTAlign)
const;
48 const Expr *
P,
unsigned AllocatedTAlign)
const;
51 const Expr *
P,
unsigned AllocatedTAlign)
const;
55 unsigned AllocatedTAlign)
const;
57 BugType SBT{
this,
"Insufficient storage for placement new",
59 BugType ABT{
this,
"Bad align storage for placement new",
64SVal PlacementNewChecker::getExtentSizeOfPlace(
const CXXNewExpr *NE,
66 const Expr *Place =
NE->getPlacementArg(0);
70SVal PlacementNewChecker::getExtentSizeOfNewTarget(
const CXXNewExpr *NE,
72 bool &IsArray)
const {
81 const Expr *SizeExpr = *
NE->getArraySize();
82 SVal ElementCount =
C.getSVal(SizeExpr);
83 if (
auto ElementCountNL = ElementCount.
getAs<
NonLoc>()) {
86 State, BO_Mul, *ElementCountNL,
95 C.getASTContext().getCharWidth(),
102bool PlacementNewChecker::checkPlaceCapacityIsSufficient(
104 bool IsArrayTypeAllocated;
105 SVal SizeOfTarget = getExtentSizeOfNewTarget(NE,
C, IsArrayTypeAllocated);
106 SVal SizeOfPlace = getExtentSizeOfPlace(NE,
C);
114 if ((SizeOfPlaceCI->getValue() < SizeOfTargetCI->getValue()) ||
115 (IsArrayTypeAllocated &&
116 SizeOfPlaceCI->getValue() >= SizeOfTargetCI->getValue())) {
120 if (IsArrayTypeAllocated &&
121 SizeOfPlaceCI->getValue() > SizeOfTargetCI->getValue())
122 Msg = std::string(llvm::formatv(
123 "{0} bytes is possibly not enough for array allocation which "
124 "requires {1} bytes. Current overhead requires the size of {2} "
126 SizeOfPlaceCI->getValue(), SizeOfTargetCI->getValue(),
127 SizeOfPlaceCI->getValue() - SizeOfTargetCI->getValue()));
128 else if (IsArrayTypeAllocated &&
129 SizeOfPlaceCI->getValue() == SizeOfTargetCI->getValue())
130 Msg = std::string(llvm::formatv(
131 "Storage provided to placement new is only {0} bytes, "
132 "whereas the allocated array type requires more space for "
134 SizeOfPlaceCI->getValue(), SizeOfTargetCI->getValue()));
136 Msg = std::string(llvm::formatv(
137 "Storage provided to placement new is only {0} bytes, "
138 "whereas the allocated type requires {1} bytes",
139 SizeOfPlaceCI->getValue(), SizeOfTargetCI->getValue()));
141 auto R = std::make_unique<PathSensitiveBugReport>(SBT, Msg, N);
143 C.emitReport(std::move(R));
153 unsigned AllocatedTAlign,
154 unsigned StorageTAlign)
const {
157 std::string Msg(llvm::formatv(
"Storage type is aligned to {0} bytes but "
158 "allocated type is aligned to {1} bytes",
159 StorageTAlign, AllocatedTAlign));
161 auto R = std::make_unique<PathSensitiveBugReport>(ABT, Msg, N);
163 C.emitReport(std::move(R));
169 unsigned StorageTAlign =
C.getASTContext().getTypeAlign(VD->
getType());
171 StorageTAlign = SpecifiedAlignment;
173 return StorageTAlign /
C.getASTContext().getCharWidth();
176void PlacementNewChecker::checkElementRegionAlign(
178 unsigned AllocatedTAlign)
const {
179 auto IsBaseRegionAlignedProperly = [
this, R, &
C,
P,
180 AllocatedTAlign]() ->
bool {
184 if (SuperRegion->
getKind() == MemRegion::ElementRegionKind) {
185 SuperRegion = cast<SubRegion>(SuperRegion)->getSuperRegion();
193 if (!TheElementDeclRegion)
200 unsigned BaseRegionAlign = 0;
204 BaseRegionAlign = getStorageAlign(
C, TheElementDeclRegion->
getDecl());
206 BaseRegionAlign = getStorageAlign(
C, BaseDeclRegion->
getDecl());
208 if (AllocatedTAlign > BaseRegionAlign) {
209 emitBadAlignReport(
P,
C, AllocatedTAlign, BaseRegionAlign);
216 auto CheckElementRegionOffset = [
this, R, &
C,
P, AllocatedTAlign]() ->
void {
222 TheOffsetRegion.
getOffset() /
C.getASTContext().getCharWidth();
223 unsigned AddressAlign = Offset % AllocatedTAlign;
224 if (AddressAlign != 0) {
225 emitBadAlignReport(
P,
C, AllocatedTAlign, AddressAlign);
230 if (IsBaseRegionAlignedProperly()) {
231 CheckElementRegionOffset();
235void PlacementNewChecker::checkFieldRegionAlign(
237 unsigned AllocatedTAlign)
const {
243 if (isVarRegionAlignedProperly(TheVarRegion,
C,
P, AllocatedTAlign)) {
248 if (Offset.hasSymbolicOffset())
252 Offset.getOffset() /
C.getASTContext().getCharWidth();
253 unsigned AddressAlign = OffsetValue % AllocatedTAlign;
254 if (AddressAlign != 0)
255 emitBadAlignReport(
P,
C, AllocatedTAlign, AddressAlign);
260bool PlacementNewChecker::isVarRegionAlignedProperly(
262 unsigned AllocatedTAlign)
const {
264 unsigned StorageTAlign = getStorageAlign(
C, TheVarDecl);
265 if (AllocatedTAlign > StorageTAlign) {
266 emitBadAlignReport(
P,
C, AllocatedTAlign, StorageTAlign);
274bool PlacementNewChecker::checkPlaceIsAlignedProperly(
const CXXNewExpr *NE,
276 const Expr *Place =
NE->getPlacementArg(0);
279 unsigned AllocatedTAlign =
C.getASTContext().getTypeAlign(AllocatedT) /
280 C.getASTContext().getCharWidth();
282 SVal PlaceVal =
C.getSVal(Place);
285 checkElementRegionAlign(TheElementRegion,
C, Place, AllocatedTAlign);
287 checkFieldRegionAlign(TheFieldRegion,
C, Place, AllocatedTAlign);
289 isVarRegionAlignedProperly(TheVarRegion,
C, Place, AllocatedTAlign);
295void PlacementNewChecker::checkPreStmt(
const CXXNewExpr *NE,
298 if (!
NE->getOperatorNew()->isReservedGlobalPlacementOperator())
301 if (
NE->getNumPlacementArgs() == 0)
304 if (!checkPlaceCapacityIsSufficient(NE,
C))
307 checkPlaceIsAlignedProperly(NE,
C);
314bool ento::shouldRegisterPlacementNewChecker(
const CheckerManager &mgr) {
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
CharUnits getTypeSizeInChars(QualType T) const
Return the size of the specified (complete) type T, in characters.
Represents a new-expression for memory allocation and constructor calls, e.g: "new CXXNewExpr(foo)".
CharUnits - This is an opaque type for sizes expressed in character units.
QuantityType getQuantity() const
getQuantity - Get the raw integer representation of this quantity.
unsigned getMaxAlignment() const
getMaxAlignment - return the maximum alignment specified by attributes on this decl,...
This represents one expression.
A (possibly-)qualified type.
Represent the declaration of a variable (in which case it is an lvalue) a function (in which case it ...
Represents a variable declaration or definition.
CHECKER * registerChecker(AT &&... Args)
Used to register checkers.
virtual const ValueDecl * getDecl() const =0
ElementRegion is used to represent both array elements and casts.
MemRegion - The root abstract class for all memory regions.
RegionOffset getAsOffset() const
Compute the offset within the top level memory object.
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * getBaseRegion() const
const RegionTy * getAs() const
Represent a region's offset within the top level base region.
bool hasSymbolicOffset() const
int64_t getOffset() const
NonLoc makeArrayIndex(uint64_t idx)
QualType getArrayIndexType() const
SVal evalBinOp(ProgramStateRef state, BinaryOperator::Opcode op, SVal lhs, SVal rhs, QualType type)
SVal - This represents a symbolic expression, which can be either an L-value or an R-value.
std::optional< T > getAs() const
Convert to the specified SVal type, returning std::nullopt if this SVal is not of the desired type.
const MemRegion * getAsRegion() const
const VarDecl * getDecl() const override=0
Value representing integer constant.
bool trackExpressionValue(const ExplodedNode *N, const Expr *E, PathSensitiveBugReport &R, TrackingOptions Opts={})
Attempts to add visitors to track expression value back to its point of origin.
const char *const MemoryError
SVal getDynamicExtentWithOffset(ProgramStateRef State, SVal BufV)
Get the dynamic extent for a symbolic value that represents a buffer.
bool NE(InterpState &S, CodePtr OpPC)
The JSON file list parser is used to communicate input to InstallAPI.