Skip to content

Commit e652e2a

Browse files
committed
[CHERI CSA] Iteratively walk up the chain of record nesting to maximize the inferred alignment.
1 parent bfd7544 commit e652e2a

File tree

2 files changed

+47
-16
lines changed

2 files changed

+47
-16
lines changed

clang/lib/StaticAnalyzer/Checkers/PointerAlignmentChecker.cpp

Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -190,25 +190,36 @@ int getTrailingZerosCount(const MemRegion *R, ProgramStateRef State,
190190
return -1;
191191
unsigned NaturalAlign = ASTCtx.getTypeAlignInChars(PT).getQuantity();
192192

193-
if (const FieldRegion *FR = R->getAs<FieldRegion>()) {
193+
unsigned FullOffsetInChars = 0;
194+
for (auto *SubR = R->getAs<SubRegion>(); SubR;
195+
SubR = SubR->getSuperRegion()->getAs<SubRegion>()) {
194196
// If this is the a field of a larger struct, we can use the alignment
195197
// of the containing struct combined with the offset to try to increase
196198
// the assumed alignment.
197-
const RegionOffset &Offset = FR->getAsOffset();
198-
if (!Offset.hasSymbolicOffset()) {
199-
if (const auto *Base =
200-
FR->getSuperRegion()->getAs<TypedValueRegion>()) {
201-
auto BaseTy = Base->getValueType();
202-
unsigned BaseAlign = ASTCtx.getTypeAlignInChars(BaseTy).getQuantity();
203-
uint64_t FieldOffsetBits = Offset.getOffset();
204-
unsigned Offset =
205-
ASTCtx.toCharUnitsFromBits(FieldOffsetBits).getQuantity();
206-
unsigned OffsetAlign =
207-
(Offset == 0) ? BaseAlign : (1ULL << llvm::countr_zero(Offset));
208-
unsigned InferredAlign = std::min(BaseAlign, OffsetAlign);
209-
NaturalAlign = std::max(NaturalAlign, InferredAlign);
210-
}
211-
}
199+
const auto *FR = SubR->getAs<FieldRegion>();
200+
if (!FR)
201+
break;
202+
203+
const RegionOffset &LocalOffset = FR->getAsOffset();
204+
if (LocalOffset.hasSymbolicOffset())
205+
break;
206+
207+
const auto *Base = FR->getSuperRegion()->getAs<TypedValueRegion>();
208+
if (!Base)
209+
break;
210+
211+
auto BaseTy = Base->getValueType();
212+
unsigned BaseAlign = ASTCtx.getTypeAlignInChars(BaseTy).getQuantity();
213+
uint64_t LocalOffsetBits = LocalOffset.getOffset();
214+
FullOffsetInChars +=
215+
ASTCtx.toCharUnitsFromBits(LocalOffsetBits).getQuantity();
216+
unsigned FullOffsetAlign =
217+
(FullOffsetInChars == 0)
218+
? BaseAlign
219+
: (1ULL << llvm::countr_zero(FullOffsetInChars));
220+
221+
unsigned InferredAlign = std::min(BaseAlign, FullOffsetAlign);
222+
NaturalAlign = std::max(NaturalAlign, InferredAlign);
212223
}
213224

214225
if (const ElementRegion *ER = R->getAs<ElementRegion>()) {

clang/test/Analysis/pointer-alignment.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,3 +227,23 @@ long long * __sealed_capability sealed_cast(int * __sealed_capability in) {
227227
// verified when unsealed.
228228
return (long long * __sealed_capability)in;
229229
}
230+
231+
// ---
232+
struct __attribute__((aligned(8))) AlignedOuterStruct {
233+
struct UnalignedInnerStruct {
234+
int a;
235+
int b;
236+
int c;
237+
int d;
238+
} inner;
239+
};
240+
241+
void write_to_first_member2(struct AlignedOuterStruct *chunk) {
242+
// No warning because alignment of is inferred from the parent struct.
243+
*(long long*)(&chunk->inner.a) = 0;
244+
}
245+
246+
void write_to_second_member2(struct AlignedOuterStruct *chunk) {
247+
// No warning because alignment of is inferred from the parent struct.
248+
*(long long*)(&chunk->inner.c) = 0;
249+
}

0 commit comments

Comments
 (0)