Skip to content

Commit

Permalink
[analyzer] Process non-POD array element destructors
Browse files Browse the repository at this point in the history
The constructors of non-POD array elements are evaluated under
certain conditions. This patch makes sure that in such cases
we also evaluate the destructors.

Differential Revision: https://reviews.llvm.org/D130737
  • Loading branch information
isuckatcs committed Aug 23, 2022
1 parent af7edf1 commit aac73a3
Show file tree
Hide file tree
Showing 8 changed files with 682 additions and 46 deletions.
Expand Up @@ -617,11 +617,16 @@ class ExprEngine {
return svalBuilder.evalBinOp(ST, Op, LHS, RHS, T);
}

/// Retreives which element is being constructed in a non POD type array.
/// Retreives which element is being constructed in a non-POD type array.
static Optional<unsigned>
getIndexOfElementToConstruct(ProgramStateRef State, const CXXConstructExpr *E,
const LocationContext *LCtx);

/// Retreives which element is being destructed in a non-POD type array.
static Optional<unsigned>
getPendingArrayDestruction(ProgramStateRef State,
const LocationContext *LCtx);

/// Retreives the size of the array in the pending ArrayInitLoopExpr.
static Optional<unsigned> getPendingInitLoop(ProgramStateRef State,
const CXXConstructExpr *E,
Expand Down Expand Up @@ -825,6 +830,27 @@ class ExprEngine {
const CXXConstructExpr *CE,
const LocationContext *LCtx);

/// Checks whether our policies allow us to inline a non-POD type array
/// destruction.
/// \param Size The size of the array.
bool shouldInlineArrayDestruction(uint64_t Size);

/// Prepares the program state for array destruction. If no error happens
/// the function binds a 'PendingArrayDestruction' entry to the state, which
/// it returns along with the index. If any error happens (we fail to read
/// the size, the index would be -1, etc.) the function will return the
/// original state along with an index of 0. The actual element count of the
/// array can be accessed by the optional 'ElementCountVal' parameter. \param
/// State The program state. \param Region The memory region where the array
/// is stored. \param ElementTy The type an element in the array. \param LCty
/// The location context. \param ElementCountVal A pointer to an optional
/// SVal. If specified, the size of the array will be returned in it. It can
/// be Unknown.
std::pair<ProgramStateRef, uint64_t> prepareStateForArrayDestruction(
const ProgramStateRef State, const MemRegion *Region,
const QualType &ElementTy, const LocationContext *LCtx,
SVal *ElementCountVal = nullptr);

/// Checks whether we construct an array of non-POD type, and decides if the
/// constructor should be inkoved once again.
bool shouldRepeatCtorCall(ProgramStateRef State, const CXXConstructExpr *E,
Expand Down Expand Up @@ -924,6 +950,16 @@ class ExprEngine {
const CXXConstructExpr *E,
const LocationContext *LCtx);

/// Assuming we destruct an array of non-POD types, this method allows us
/// to store which element is to be destructed next.
static ProgramStateRef setPendingArrayDestruction(ProgramStateRef State,
const LocationContext *LCtx,
unsigned Idx);

static ProgramStateRef
removePendingArrayDestruction(ProgramStateRef State,
const LocationContext *LCtx);

/// Sets the size of the array in a pending ArrayInitLoopExpr.
static ProgramStateRef setPendingInitLoop(ProgramStateRef State,
const CXXConstructExpr *E,
Expand Down
18 changes: 15 additions & 3 deletions clang/lib/Analysis/CFG.cpp
Expand Up @@ -1970,9 +1970,10 @@ void CFGBuilder::addImplicitDtorsForDestructor(const CXXDestructorDecl *DD) {
for (auto *FI : RD->fields()) {
// Check for constant size array. Set type to array element type.
QualType QT = FI->getType();
if (const ConstantArrayType *AT = Context->getAsConstantArrayType(QT)) {
// It may be a multidimensional array.
while (const ConstantArrayType *AT = Context->getAsConstantArrayType(QT)) {
if (AT->getSize() == 0)
continue;
break;
QT = AT->getElementType();
}

Expand Down Expand Up @@ -5333,8 +5334,19 @@ CFGImplicitDtor::getDestructorDecl(ASTContext &astContext) const {
const CXXTemporary *temp = bindExpr->getTemporary();
return temp->getDestructor();
}
case CFGElement::MemberDtor: {
const FieldDecl *field = castAs<CFGMemberDtor>().getFieldDecl();
QualType ty = field->getType();

while (const ArrayType *arrayType = astContext.getAsArrayType(ty)) {
ty = arrayType->getElementType();
}

const CXXRecordDecl *classDecl = ty->getAsCXXRecordDecl();
assert(classDecl);
return classDecl->getDestructor();
}
case CFGElement::BaseDtor:
case CFGElement::MemberDtor:
// Not yet supported.
return nullptr;
}
Expand Down

0 comments on commit aac73a3

Please sign in to comment.