Skip to content

Commit afc240c

Browse files
committed
[CHERI CSA] Extend inference of increase alignment to fields other than the first field of a struct.
1 parent 37ff680 commit afc240c

File tree

2 files changed

+21
-7
lines changed

2 files changed

+21
-7
lines changed

clang/lib/StaticAnalyzer/Checkers/PointerAlignmentChecker.cpp

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -191,15 +191,22 @@ int getTrailingZerosCount(const MemRegion *R, ProgramStateRef State,
191191
unsigned NaturalAlign = ASTCtx.getTypeAlignInChars(PT).getQuantity();
192192

193193
if (const FieldRegion *FR = R->getAs<FieldRegion>()) {
194-
// If this is the first field of a larger struct, we can use the alignment
195-
// of the containing struct try to increase the assumed alignment.
194+
// If this is the a field of a larger struct, we can use the alignment
195+
// of the containing struct combined with the offset to try to increase
196+
// the assumed alignment.
196197
const RegionOffset &Offset = FR->getAsOffset();
197-
if (!Offset.hasSymbolicOffset() && Offset.getOffset() == 0) {
198+
if (!Offset.hasSymbolicOffset()) {
198199
if (const auto *Base =
199200
FR->getSuperRegion()->getAs<TypedValueRegion>()) {
200201
auto BaseTy = Base->getValueType();
201202
unsigned BaseAlign = ASTCtx.getTypeAlignInChars(BaseTy).getQuantity();
202-
NaturalAlign = std::max(NaturalAlign, BaseAlign);
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);
203210
}
204211
}
205212
}

clang/test/Analysis/pointer-alignment.c

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,12 @@ uintptr_t* bar(uintptr_t *p) {
4444

4545
struct S {
4646
intptr_t u[40];
47-
int i[40]; // expected-note{{Original allocation}}
47+
int i[40];
4848
int i_aligned[40] __attribute__((aligned(16))); // expected-note{{Original allocation}}
4949
};
5050
int struct_field(struct S *s) {
5151
uintptr_t* p1 = (uintptr_t*)&s->u[3]; // no warning
52-
uintptr_t* p2 = (uintptr_t*)&s->i[8]; // expected-warning{{Pointer value aligned to a 4 byte boundary cast to type 'uintptr_t * __capability' with 16-byte capability alignment}}
52+
uintptr_t* p2 = (uintptr_t*)&s->i[8]; // no warning
5353
uintptr_t* p3 = (uintptr_t*)&s->i_aligned[6]; // expected-warning{{Pointer value aligned to a 8 byte boundary cast to type 'uintptr_t * __capability' with 16-byte capability alignment}}
5454
uintptr_t* p4 = (uintptr_t*)&s->i_aligned[4]; // no warning
5555
return (p4 - p3) + (p2 - p1);
@@ -207,16 +207,23 @@ void cast_and_assign(void) {
207207
struct __attribute__((aligned(8))) AlignedParentStruct {
208208
int a;
209209
int b;
210+
int c;
211+
int d;
210212
};
211213

212214
void write_to_first_member(struct AlignedParentStruct *chunk) {
213215
// No warning because alignment of is inferred from the parent struct.
214216
*(long long*)(&chunk->a) = 0;
215217
}
216218

219+
void write_to_second_member(struct AlignedParentStruct *chunk) {
220+
// No warning because alignment of is inferred from the parent struct.
221+
*(long long*)(&chunk->c) = 0;
222+
}
223+
217224
// ----
218225
long long * __sealed_capability sealed_cast(int * __sealed_capability in) {
219226
// No warnings for sealed capabilities, since they will be effectively dynamically
220227
// verified when unsealed.
221228
return (long long * __sealed_capability)in;
222-
}
229+
}

0 commit comments

Comments
 (0)