Skip to content

Commit

Permalink
PoC
Browse files Browse the repository at this point in the history
  • Loading branch information
steakhal committed Aug 20, 2023
1 parent c058eb9 commit 986059a
Show file tree
Hide file tree
Showing 4 changed files with 208 additions and 133 deletions.
52 changes: 51 additions & 1 deletion clang/lib/StaticAnalyzer/Core/DynamicExtent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,69 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
#include <optional>

REGISTER_MAP_WITH_PROGRAMSTATE(DynamicExtentMap, const clang::ento::MemRegion *,
clang::ento::DefinedOrUnknownSVal)

namespace clang {
namespace ento {

static bool isLastField(const FieldDecl *FD) {
RecordDecl::field_iterator FI(
DeclContext::decl_iterator(const_cast<FieldDecl *>(FD)));
return ++FI == FD->getParent()->field_end();
}

/// Check if the region refers to a field that is the last one
/// transitively across parent records.
static bool isLastField(const FieldRegion *FR) {
for (; FR; FR = dyn_cast<FieldRegion>(FR->getSuperRegion())) {
if (!isLastField(FR->getDecl()))
return false;
}
return true;
}

/// Calculate the extent of the FAM based on the extent of the parent region.
static std::optional<DefinedOrUnknownSVal>
getDynamicExtentOfFlexibleArrayMembers(ProgramStateRef State,
const MemRegion *MR, SValBuilder &SVB) {
const auto *FR = dyn_cast<FieldRegion>(MR);

if (!FR || !isa<ArrayType>(FR->getValueType()) || !isLastField(FR))
return std::nullopt;

RegionOffset RelPos = FR->getAsOffset();
if (!RelPos.isValid() || RelPos.hasSymbolicOffset())
return std::nullopt;

// Check if we have an associated extent with this base region.
const auto *BaseExtent = State->get<DynamicExtentMap>(RelPos.getRegion());
if (!BaseExtent)
return std::nullopt;

QualType IndexTy = SVB.getArrayIndexType();
int64_t OffsetInBits = RelPos.getOffset();
uint64_t CharBits = SVB.getContext().getCharWidth();
assert(OffsetInBits % CharBits == 0);
DefinedSVal OffsetInBytes = SVB.makeIntVal(OffsetInBits / CharBits, IndexTy);
SVal FAMExtent =
SVB.evalBinOp(State, BO_Sub, *BaseExtent, OffsetInBytes, IndexTy);
return FAMExtent.castAs<DefinedOrUnknownSVal>();
}

DefinedOrUnknownSVal getDynamicExtent(ProgramStateRef State,
const MemRegion *MR, SValBuilder &SVB) {
MR = MR->StripCasts();

if (const DefinedOrUnknownSVal *Size = State->get<DynamicExtentMap>(MR))
if (const DefinedOrUnknownSVal *Size = State->get<DynamicExtentMap>(MR)) {
return *Size;
}

if (auto FAMSize = getDynamicExtentOfFlexibleArrayMembers(State, MR, SVB)) {
return *FAMSize;
}

return MR->getMemRegionManager().getStaticSize(MR, SVB);
}
Expand Down
49 changes: 1 addition & 48 deletions clang/lib/StaticAnalyzer/Core/MemRegion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -800,54 +800,7 @@ DefinedOrUnknownSVal MemRegionManager::getStaticSize(const MemRegion *MR,
return UnknownVal();

QualType Ty = cast<TypedValueRegion>(SR)->getDesugaredValueType(Ctx);
const DefinedOrUnknownSVal Size = getElementExtent(Ty, SVB);

// We currently don't model flexible array members (FAMs), which are:
// - int array[]; of IncompleteArrayType
// - int array[0]; of ConstantArrayType with size 0
// - int array[1]; of ConstantArrayType with size 1
// https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html
const auto isFlexibleArrayMemberCandidate =
[this](const ArrayType *AT) -> bool {
if (!AT)
return false;

auto IsIncompleteArray = [](const ArrayType *AT) {
return isa<IncompleteArrayType>(AT);
};
auto IsArrayOfZero = [](const ArrayType *AT) {
const auto *CAT = dyn_cast<ConstantArrayType>(AT);
return CAT && CAT->getSize() == 0;
};
auto IsArrayOfOne = [](const ArrayType *AT) {
const auto *CAT = dyn_cast<ConstantArrayType>(AT);
return CAT && CAT->getSize() == 1;
};

using FAMKind = LangOptions::StrictFlexArraysLevelKind;
const FAMKind StrictFlexArraysLevel =
Ctx.getLangOpts().getStrictFlexArraysLevel();

// "Default": Any trailing array member is a FAM.
// Since we cannot tell at this point if this array is a trailing member
// or not, let's just do the same as for "OneZeroOrIncomplete".
if (StrictFlexArraysLevel == FAMKind::Default)
return IsArrayOfOne(AT) || IsArrayOfZero(AT) || IsIncompleteArray(AT);

if (StrictFlexArraysLevel == FAMKind::OneZeroOrIncomplete)
return IsArrayOfOne(AT) || IsArrayOfZero(AT) || IsIncompleteArray(AT);

if (StrictFlexArraysLevel == FAMKind::ZeroOrIncomplete)
return IsArrayOfZero(AT) || IsIncompleteArray(AT);

assert(StrictFlexArraysLevel == FAMKind::IncompleteOnly);
return IsIncompleteArray(AT);
};

if (isFlexibleArrayMemberCandidate(Ctx.getAsArrayType(Ty)))
return UnknownVal();

return Size;
return getElementExtent(Ty, SVB);
}
// FIXME: The following are being used in 'SimpleSValBuilder' and in
// 'ArrayBoundChecker::checkLocation' because there is no symbol to
Expand Down

0 comments on commit 986059a

Please sign in to comment.