aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/Sema/SemaChecking.cpp
diff options
context:
space:
mode:
authorRoger Ferrer Ibanez <roger.ferreribanez@arm.com>2016-08-12 08:04:13 +0000
committerRoger Ferrer Ibanez <roger.ferreribanez@arm.com>2016-08-12 08:04:13 +0000
commit722a4db1985ca9a8b982074d658dfee9c4624d53 (patch)
tree6e1feae76b0cb2244b98abbc4f2e33457fe32a74 /clang/lib/Sema/SemaChecking.cpp
parent85c6b44817227d838a3f3385f707ecf42dc79713 (diff)
downloadllvm-722a4db1985ca9a8b982074d658dfee9c4624d53.zip
llvm-722a4db1985ca9a8b982074d658dfee9c4624d53.tar.gz
llvm-722a4db1985ca9a8b982074d658dfee9c4624d53.tar.bz2
This patch implements PR#22821.
Taking the address of a packed member is dangerous since the reduced alignment of the pointee is lost. This can lead to memory alignment faults in some architectures if the pointer value is dereferenced. This change adds a new warning to clang emitted when taking the address of a packed member. A packed member is either a field/data member declared as attribute((packed)) or belonging to a struct/class declared as such. The associated flag is -Waddress-of-packed-member. Conversions (either implicit or via a valid casting) to pointer types with lower or equal alignment requirements (e.g. void* or char*) will silence the warning. Differential Revision: https://reviews.llvm.org/D20561 llvm-svn: 278483
Diffstat (limited to 'clang/lib/Sema/SemaChecking.cpp')
-rw-r--r--clang/lib/Sema/SemaChecking.cpp67
1 files changed, 67 insertions, 0 deletions
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index c1781c2..6edb251 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -8383,6 +8383,8 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
DiagnoseNullConversion(S, E, T, CC);
+ S.DiscardMisalignedMemberAddress(Target, E);
+
if (!Source->isIntegerType() || !Target->isIntegerType())
return;
@@ -9453,6 +9455,7 @@ void Sema::CheckCompletedExpr(Expr *E, SourceLocation CheckLoc,
CheckUnsequencedOperations(E);
if (!IsConstexpr && !E->isValueDependent())
CheckForIntOverflow(E);
+ DiagnoseMisalignedMembers();
}
void Sema::CheckBitFieldInitialization(SourceLocation InitLoc,
@@ -10998,3 +11001,67 @@ void Sema::CheckArgumentWithTypeTag(const ArgumentWithTypeTagAttr *Attr,
<< ArgumentExpr->getSourceRange()
<< TypeTagExpr->getSourceRange();
}
+
+void Sema::AddPotentialMisalignedMembers(Expr *E, RecordDecl *RD, ValueDecl *MD,
+ CharUnits Alignment) {
+ MisalignedMembers.emplace_back(E, RD, MD, Alignment);
+}
+
+void Sema::DiagnoseMisalignedMembers() {
+ for (MisalignedMember &m : MisalignedMembers) {
+ Diag(m.E->getLocStart(), diag::warn_taking_address_of_packed_member)
+ << m.MD << m.RD << m.E->getSourceRange();
+ }
+ MisalignedMembers.clear();
+}
+
+void Sema::DiscardMisalignedMemberAddress(const Type *T, Expr *E) {
+ if (!T->isPointerType())
+ return;
+ if (isa<UnaryOperator>(E) &&
+ cast<UnaryOperator>(E)->getOpcode() == UO_AddrOf) {
+ auto *Op = cast<UnaryOperator>(E)->getSubExpr()->IgnoreParens();
+ if (isa<MemberExpr>(Op)) {
+ auto MA = std::find(MisalignedMembers.begin(), MisalignedMembers.end(),
+ MisalignedMember(Op));
+ if (MA != MisalignedMembers.end() &&
+ Context.getTypeAlignInChars(T->getPointeeType()) <= MA->Alignment)
+ MisalignedMembers.erase(MA);
+ }
+ }
+}
+
+void Sema::RefersToMemberWithReducedAlignment(
+ Expr *E,
+ std::function<void(Expr *, RecordDecl *, ValueDecl *, CharUnits)> Action) {
+ const auto *ME = dyn_cast<MemberExpr>(E);
+ while (ME && isa<FieldDecl>(ME->getMemberDecl())) {
+ QualType BaseType = ME->getBase()->getType();
+ if (ME->isArrow())
+ BaseType = BaseType->getPointeeType();
+ RecordDecl *RD = BaseType->getAs<RecordType>()->getDecl();
+
+ ValueDecl *MD = ME->getMemberDecl();
+ bool ByteAligned = Context.getTypeAlignInChars(MD->getType()).isOne();
+ if (ByteAligned) // Attribute packed does not have any effect.
+ break;
+
+ if (!ByteAligned &&
+ (RD->hasAttr<PackedAttr>() || (MD->hasAttr<PackedAttr>()))) {
+ CharUnits Alignment = std::min(Context.getTypeAlignInChars(MD->getType()),
+ Context.getTypeAlignInChars(BaseType));
+ // Notify that this expression designates a member with reduced alignment
+ Action(E, RD, MD, Alignment);
+ break;
+ }
+ ME = dyn_cast<MemberExpr>(ME->getBase());
+ }
+}
+
+void Sema::CheckAddressOfPackedMember(Expr *rhs) {
+ using namespace std::placeholders;
+ RefersToMemberWithReducedAlignment(
+ rhs, std::bind(&Sema::AddPotentialMisalignedMembers, std::ref(*this), _1,
+ _2, _3, _4));
+}
+