aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/CodeGen/CGExprAgg.cpp
diff options
context:
space:
mode:
authoryabinc <yabinc@google.com>2024-09-24 19:06:20 -0700
committerGitHub <noreply@github.com>2024-09-24 19:06:20 -0700
commit7a086e1b2dc05f54afae3591614feede727601fa (patch)
treee15bd1089946e0352c8a2d9034c7c17ee3632002 /clang/lib/CodeGen/CGExprAgg.cpp
parent0a42c7c6679bcc6f7be4b3d103670197acac96a9 (diff)
downloadllvm-7a086e1b2dc05f54afae3591614feede727601fa.zip
llvm-7a086e1b2dc05f54afae3591614feede727601fa.tar.gz
llvm-7a086e1b2dc05f54afae3591614feede727601fa.tar.bz2
[clang][CodeGen] Zero init unspecified fields in initializers in C (#97121)
When an initializer is provided to a variable, the Linux kernel relied on the compiler to zero-initialize unspecified fields, as clarified in https://www.spinics.net/lists/netdev/msg1007244.html. But clang doesn't guarantee this: 1. For a union type, if an empty initializer is given, clang only initializes bytes for the first field, left bytes for other (larger) fields are marked as undef. Accessing those undef bytes can lead to undefined behaviors. 2. For a union type, if an initializer explicitly sets a field, left bytes for other (larger) fields are marked as undef. 3. When an initializer is given, clang doesn't zero initialize padding. So this patch makes the following change: 1. In C, when an initializer is provided for a variable, zero-initialize undef and padding fields in the initializer. 2. Document the change in LanguageExtensions.rst. As suggested in https://github.com/llvm/llvm-project/issues/78034#issuecomment-2183437928, the change isn't required by C23, but it's standards conforming to do so. Fixes: https://github.com/llvm/llvm-project/issues/97459
Diffstat (limited to 'clang/lib/CodeGen/CGExprAgg.cpp')
-rw-r--r--clang/lib/CodeGen/CGExprAgg.cpp40
1 files changed, 38 insertions, 2 deletions
diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp
index bbfc667..43f3bcc 100644
--- a/clang/lib/CodeGen/CGExprAgg.cpp
+++ b/clang/lib/CodeGen/CGExprAgg.cpp
@@ -1698,6 +1698,17 @@ void AggExprEmitter::VisitCXXParenListOrInitListExpr(
// Prepare a 'this' for CXXDefaultInitExprs.
CodeGenFunction::FieldConstructionScope FCS(CGF, Dest.getAddress());
+ const bool ZeroInitPadding =
+ CGF.CGM.shouldZeroInitPadding() && !Dest.isZeroed();
+ const Address BaseLoc = Dest.getAddress().withElementType(CGF.Int8Ty);
+ auto DoZeroInitPadding = [&](CharUnits Offset, CharUnits Size) {
+ if (Size.isPositive()) {
+ Address Loc = CGF.Builder.CreateConstGEP(BaseLoc, Offset.getQuantity());
+ llvm::Constant *SizeVal = CGF.Builder.getInt64(Size.getQuantity());
+ CGF.Builder.CreateMemSet(Loc, CGF.Builder.getInt8(0), SizeVal, false);
+ }
+ };
+
if (record->isUnion()) {
// Only initialize one field of a union. The field itself is
// specified by the initializer list.
@@ -1722,17 +1733,37 @@ void AggExprEmitter::VisitCXXParenListOrInitListExpr(
if (NumInitElements) {
// Store the initializer into the field
EmitInitializationToLValue(InitExprs[0], FieldLoc);
+ if (ZeroInitPadding) {
+ CharUnits TotalSize =
+ Dest.getPreferredSize(CGF.getContext(), DestLV.getType());
+ CharUnits FieldSize =
+ CGF.getContext().getTypeSizeInChars(FieldLoc.getType());
+ DoZeroInitPadding(FieldSize, TotalSize - FieldSize);
+ }
} else {
// Default-initialize to null.
- EmitNullInitializationToLValue(FieldLoc);
+ if (ZeroInitPadding)
+ EmitNullInitializationToLValue(DestLV);
+ else
+ EmitNullInitializationToLValue(FieldLoc);
}
-
return;
}
// Here we iterate over the fields; this makes it simpler to both
// default-initialize fields and skip over unnamed fields.
+ const ASTRecordLayout &Layout = CGF.getContext().getASTRecordLayout(record);
+ CharUnits SizeSoFar = CharUnits::Zero();
for (const auto *field : record->fields()) {
+ if (ZeroInitPadding) {
+ unsigned FieldNo = field->getFieldIndex();
+ CharUnits Offset =
+ CGF.getContext().toCharUnitsFromBits(Layout.getFieldOffset(FieldNo));
+ DoZeroInitPadding(SizeSoFar, Offset - SizeSoFar);
+ CharUnits FieldSize =
+ CGF.getContext().getTypeSizeInChars(field->getType());
+ SizeSoFar = Offset + FieldSize;
+ }
// We're done once we hit the flexible array member.
if (field->getType()->isIncompleteArrayType())
break;
@@ -1774,6 +1805,11 @@ void AggExprEmitter::VisitCXXParenListOrInitListExpr(
}
}
}
+ if (ZeroInitPadding) {
+ CharUnits TotalSize =
+ Dest.getPreferredSize(CGF.getContext(), DestLV.getType());
+ DoZeroInitPadding(SizeSoFar, TotalSize - SizeSoFar);
+ }
}
void AggExprEmitter::VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E,