diff --git a/clang/lib/StaticAnalyzer/Checkers/PointerAlignmentChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/PointerAlignmentChecker.cpp index 496d24c5747f3..d74ee26ad85d0 100644 --- a/clang/lib/StaticAnalyzer/Checkers/PointerAlignmentChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/PointerAlignmentChecker.cpp @@ -190,25 +190,36 @@ int getTrailingZerosCount(const MemRegion *R, ProgramStateRef State, return -1; unsigned NaturalAlign = ASTCtx.getTypeAlignInChars(PT).getQuantity(); - if (const FieldRegion *FR = R->getAs()) { + unsigned FullOffsetInChars = 0; + for (auto *SubR = R->getAs(); SubR; + SubR = SubR->getSuperRegion()->getAs()) { // If this is the a field of a larger struct, we can use the alignment // of the containing struct combined with the offset to try to increase // the assumed alignment. - const RegionOffset &Offset = FR->getAsOffset(); - if (!Offset.hasSymbolicOffset()) { - if (const auto *Base = - FR->getSuperRegion()->getAs()) { - auto BaseTy = Base->getValueType(); - unsigned BaseAlign = ASTCtx.getTypeAlignInChars(BaseTy).getQuantity(); - uint64_t FieldOffsetBits = Offset.getOffset(); - unsigned Offset = - ASTCtx.toCharUnitsFromBits(FieldOffsetBits).getQuantity(); - unsigned OffsetAlign = - (Offset == 0) ? BaseAlign : (1ULL << llvm::countr_zero(Offset)); - unsigned InferredAlign = std::min(BaseAlign, OffsetAlign); - NaturalAlign = std::max(NaturalAlign, InferredAlign); - } - } + const auto *FR = SubR->getAs(); + if (!FR) + break; + + const RegionOffset &LocalOffset = FR->getAsOffset(); + if (LocalOffset.hasSymbolicOffset()) + break; + + const auto *Base = FR->getSuperRegion()->getAs(); + if (!Base) + break; + + auto BaseTy = Base->getValueType(); + unsigned BaseAlign = ASTCtx.getTypeAlignInChars(BaseTy).getQuantity(); + uint64_t LocalOffsetBits = LocalOffset.getOffset(); + FullOffsetInChars += + ASTCtx.toCharUnitsFromBits(LocalOffsetBits).getQuantity(); + unsigned FullOffsetAlign = + (FullOffsetInChars == 0) + ? BaseAlign + : (1ULL << llvm::countr_zero(FullOffsetInChars)); + + unsigned InferredAlign = std::min(BaseAlign, FullOffsetAlign); + NaturalAlign = std::max(NaturalAlign, InferredAlign); } if (const ElementRegion *ER = R->getAs()) { diff --git a/clang/test/Analysis/pointer-alignment.c b/clang/test/Analysis/pointer-alignment.c index ea748505e951f..f6faa063a7470 100644 --- a/clang/test/Analysis/pointer-alignment.c +++ b/clang/test/Analysis/pointer-alignment.c @@ -227,3 +227,23 @@ long long * __sealed_capability sealed_cast(int * __sealed_capability in) { // verified when unsealed. return (long long * __sealed_capability)in; } + +// --- +struct __attribute__((aligned(8))) AlignedOuterStruct { + struct UnalignedInnerStruct { + int a; + int b; + int c; + int d; + } inner; +}; + +void write_to_first_member2(struct AlignedOuterStruct *chunk) { + // No warning because alignment of is inferred from the parent struct. + *(long long*)(&chunk->inner.a) = 0; +} + +void write_to_second_member2(struct AlignedOuterStruct *chunk) { + // No warning because alignment of is inferred from the parent struct. + *(long long*)(&chunk->inner.c) = 0; +}