[PATCH] Insert poisoned paddings between fields in C++ classes.
Richard Smith
richard at metafoo.co.uk
Wed Oct 8 18:09:14 PDT 2014
================
Comment at: lib/AST/RecordLayoutBuilder.cpp:1346-1347
@@ +1345,4 @@
+// These padding are added to help AddressSanitizer detect intra-object-overflow
+// bugs. Later in CogeGen an extra code will be emitted to poison these
+// extra paddings.
+bool RecordLayoutBuilder::MayInsertExtraPaddingAfterField(const RecordDecl *RD,
----------------
Typo. "Later in CodeGen, extra code will [...]"
================
Comment at: lib/AST/RecordLayoutBuilder.cpp:1348
@@ +1347,3 @@
+// extra paddings.
+bool RecordLayoutBuilder::MayInsertExtraPaddingAfterField(const RecordDecl *RD,
+ const FieldDecl *FD) {
----------------
This does not depend on the value of `FD`; perhaps remove `FD` and just call it once per class?
================
Comment at: lib/AST/RecordLayoutBuilder.cpp:1362-1367
@@ +1361,8 @@
+ ReasonToReject = "union";
+ else if (CXXRD->isTriviallyCopyable())
+ ReasonToReject = "trivially copyable";
+ else if (CXXRD->hasSimpleDestructor())
+ ReasonToReject = "has simple DTOR";
+ else if (CXXRD->isStandardLayout())
+ ReasonToReject = "standard layout";
+
----------------
What's the reason behind picking these rules? It seems like we could be more aggressive here and still follow the C++ standard. Is this for C compatibility, or people who roll their own memcpy, or something else? I guess the ASan-instrumented memcpy can be taught that it's OK to copy intra-object redzone?
================
Comment at: lib/AST/RecordLayoutBuilder.cpp:1364-1365
@@ +1363,4 @@
+ ReasonToReject = "trivially copyable";
+ else if (CXXRD->hasSimpleDestructor())
+ ReasonToReject = "has simple DTOR";
+ else if (CXXRD->isStandardLayout())
----------------
This 'simple destructor' check doesn't seem right. What properties do you intend to check for here?
================
Comment at: lib/AST/RecordLayoutBuilder.cpp:1369-1379
@@ +1368,13 @@
+
+ // FIXME (before commit): where should this SpecialCaseList reside?
+ // In RecordLayoutBuilder? In global scope?
+ // Also, can we reuse the existing -fsanitize-blacklist flag to pass
+ // the file path (i.e. the same blacklist file will be used in AST and
+ // CogeGen), or we should have another flag?
+ auto SCL = llvm::SpecialCaseList::createOrDie(
+ "/tmp/blacklist.txt");
+ StringRef Filename =
+ Context.getSourceManager().getFilename(RD->getLocation());
+ if (SCL->inSection("src", Filename))
+ ReasonToReject = "blacklisted by src";
+
----------------
Please fix =)
I think reusing the same `-fsanitize-blacklist` flag makes sense.
================
Comment at: lib/AST/RecordLayoutBuilder.cpp:1381-1387
@@ +1380,9 @@
+
+ // FIXME (before commit): what flag to use for debug output?
+ if (0) {
+ const char *ToPrint = ReasonToReject ? ReasonToReject : "ACCEPTED";
+ llvm::errs() << "ASAN_FIELD_PADDING: " << Filename << " " << *RD
+ << "::" << *FD << " : " << ToPrint << "\n";
+ }
+ return ReasonToReject == 0;
+}
----------------
If you're going to keep this, it should be put behind a remark flag, and should use the normal diagnostics machinery.
================
Comment at: lib/AST/RecordLayoutBuilder.cpp:1394-1395
@@ +1393,4 @@
+ SmallVector<FieldDecl *, 16> Fields(D->field_begin(), D->field_end());
+ // FIXME (before commit): is there a way to know that the field is last
+ // w/o this temporary vector?
+ for (size_t i = 0, e = Fields.size(); i < e; i++)
----------------
This might be easier if you insert padding before fields rather than after them.
================
Comment at: lib/AST/RecordLayoutBuilder.cpp:1397-1398
@@ -1346,1 +1396,4 @@
+ for (size_t i = 0, e = Fields.size(); i < e; i++)
+ LayoutField(Fields[i],
+ i + 1 != e && MayInsertExtraPaddingAfterField(D, Fields[i]));
}
----------------
Maybe factor out adding the padding from adding the field? I don't think they need to be done together, do they?
Also, you shouldn't add padding at the end of the class if it ends in a flexible array member.
================
Comment at: lib/CodeGen/CGClass.cpp:695
@@ -694,1 +694,3 @@
+// Emit code in CTOR (Prologue==true) or DTOR(Prologue==false)
+// to poison the extra field paddings inserted under
----------------
"ctor" and "dtor" in lowercase please.
Stripping the poison in the dtor doesn't match C++ semantics: you aren't required to run the dtor to reuse the storage as something else, but conversely you can't reuse the storage as something else unless you use placement-new to construct a new object.
As a compromise to be nicer to existing code, maybe we should strip poison both in the dtor and in a new-expression?
================
Comment at: lib/CodeGen/CGClass.cpp:703-704
@@ +702,4 @@
+ : cast<CXXDestructorDecl>(CurGD.getDecl())->getParent();
+ if (ClassDecl->hasAttr<PackedAttr>() || ClassDecl->isStandardLayout() ||
+ ClassDecl->isTriviallyCopyable())
+ return;
----------------
This doesn't match the set of checks you did in `MayInsertExtraPaddingAfterField`; in particular, do you need to consider unions here?
================
Comment at: lib/CodeGen/CGClass.cpp:708-709
@@ +707,4 @@
+ struct SizeAndOffset {
+ uint64_t size;
+ uint64_t offset;
+ };
----------------
Field names should be capitalized.
================
Comment at: lib/CodeGen/CGClass.cpp:719
@@ +718,3 @@
+ for (unsigned i = 0, e = Info.getFieldCount(); i != e; ++i)
+ SSV[i].offset = Info.getFieldOffset(i) / 8;
+
----------------
Please don't hard-code `8` here; use `ASTContext::toCharUnitsFromBits` instead.
================
Comment at: lib/CodeGen/CGClass.cpp:737
@@ +736,3 @@
+ // LLVM AddressSanitizer pass may decide to inline them later.
+ llvm::Type *PtrIntTy = Builder.getIntNTy(PtrSize);
+ llvm::Type *Args[2] = {PtrIntTy, PtrIntTy};
----------------
This is `IntPtrTy` (a member of `CodeGenFunction`).
http://reviews.llvm.org/D5687
More information about the cfe-commits
mailing list