const ASTRecordLayout &Layout =
CGF.getContext().getASTRecordLayout(Dtor->getParent());
+ // Nothing to poison
+ if(Layout.getFieldCount() == 0)
+ return;
+
+ // Construct pointer to region to begin poisoning, and calculate poison
+ // size, so that only members declared in this class are poisoned.
+ llvm::Value *OffsetPtr;
+ CharUnits::QuantityType PoisonSize;
+ ASTContext &Context = CGF.getContext();
+
+ llvm::ConstantInt *OffsetSizePtr = llvm::ConstantInt::get(
+ CGF.SizeTy, Context.toCharUnitsFromBits(Layout.getFieldOffset(0)).
+ getQuantity());
+
+ OffsetPtr = CGF.Builder.CreateGEP(CGF.Builder.CreateBitCast(
+ CGF.LoadCXXThis(), CGF.Int8PtrTy), OffsetSizePtr);
+
+ PoisonSize = Layout.getSize().getQuantity() -
+ Context.toCharUnitsFromBits(Layout.getFieldOffset(0)).getQuantity();
+
llvm::Value *Args[] = {
- CGF.Builder.CreateBitCast(CGF.LoadCXXThis(), CGF.VoidPtrTy),
- llvm::ConstantInt::get(CGF.SizeTy, Layout.getSize().getQuantity())};
+ CGF.Builder.CreateBitCast(OffsetPtr, CGF.VoidPtrTy),
+ llvm::ConstantInt::get(CGF.SizeTy, PoisonSize)};
+
llvm::Type *ArgTypes[] = {CGF.VoidPtrTy, CGF.SizeTy};
llvm::FunctionType *FnType =
llvm::Value *Fn =
CGF.CGM.CreateRuntimeFunction(FnType, "__sanitizer_dtor_callback");
+ // Disables tail call elimination, to prevent the current stack frame from
+ // disappearing from the stack trace.
CGF.CurFn->addFnAttr("disable-tail-calls", "true");
CGF.EmitNounwindRuntimeCall(Fn, Args);
}
// the caller's body.
if (getLangOpts().AppleKext)
CurFn->addFnAttr(llvm::Attribute::AlwaysInline);
+
+ // Insert memory-poisoning instrumentation, before final clean ups,
+ // to ensure this class's members are protected from invalid access.
+ if (CGM.getCodeGenOpts().SanitizeMemoryUseAfterDtor
+ && SanOpts.has(SanitizerKind::Memory))
+ EmitDtorSanitizerCallback(*this, Dtor);
+
break;
}
// Exit the try if applicable.
if (isTryBody)
ExitCXXTryStmt(*cast<CXXTryStmt>(Body), true);
-
- // Insert memory-poisoning instrumentation.
- if (CGM.getCodeGenOpts().SanitizeMemoryUseAfterDtor
- && SanOpts.has(SanitizerKind::Memory))
- EmitDtorSanitizerCallback(*this, Dtor);
}
void CodeGenFunction::emitImplicitAssignmentOperatorBody(FunctionArgList &Args) {
Simple s;
// Simple internal member is poisoned by compiler-generated dtor
// CHECK-LABEL: define {{.*}}SimpleD1Ev
-// CHECK: call void @__sanitizer_dtor_callback
+// CHECK-NOT: call void @__sanitizer_dtor_callback
+// CHECK: call void {{.*}}SimpleD2Ev
// CHECK-NOT: call void @__sanitizer_dtor_callback
// CHECK: ret void
Inlined i;
// Simple internal member is poisoned by compiler-generated dtor
// CHECK-LABEL: define {{.*}}InlinedD1Ev
-// CHECK: call void @__sanitizer_dtor_callback
+// CHECK-NOT: call void @__sanitizer_dtor_callback
+// CHECK: call void {{.*}}InlinedD2Ev
// CHECK-NOT: call void @__sanitizer_dtor_callback
// CHECK: ret void
// By including a Simple member in the struct, the compiler is
// forced to generate a non-trivial destructor.
// CHECK-LABEL: define {{.*}}Defaulted_Non_TrivialD1Ev
-// CHECK: call void @__sanitizer_dtor_callback
+// CHECK-NOT: call void @__sanitizer_dtor_callback
+// CHECK: call void {{.*}}Defaulted_Non_TrivialD2
// CHECK-NOT: call void @__sanitizer_dtor_callback
// CHECK: ret void
--- /dev/null
+// RUN: %clang_cc1 -fsanitize=memory -fsanitize-memory-use-after-dtor -disable-llvm-optzns -std=c++11 -triple=x86_64-pc-linux -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -O1 -fsanitize=memory -fsanitize-memory-use-after-dtor -disable-llvm-optzns -std=c++11 -triple=x86_64-pc-linux -emit-llvm -o - %s | FileCheck %s
+
+class Base {
+ public:
+ int x;
+ Base() {
+ x = 5;
+ }
+ virtual ~Base() {
+ x += 1;
+ }
+};
+
+class Derived : public Base {
+ public:
+ int y;
+ Derived() {
+ y = 10;
+ }
+ ~Derived() {
+ y += 1;
+ }
+};
+
+Derived d;
+
+// CHECK-LABEL: define {{.*}}DerivedD1Ev
+// CHECK-NOT: call void @__sanitizer_dtor_callback
+// CHECK: call void {{.*}}DerivedD2Ev
+// CHECK-NOT: call void @__sanitizer_dtor_callback
+// CHECK: ret void
+
+// CHECK-LABEL: define {{.*}}DerivedD0Ev
+// CHECK-NOT: call void @__sanitizer_dtor_callback
+// CHECK: call void {{.*}}DerivedD1Ev
+// CHECK-NOT: call void @__sanitizer_dtor_callback
+// CHECK: ret void
+
+// CHECK-LABEL: define {{.*}}BaseD1Ev
+// CHECK-NOT: call void @__sanitizer_dtor_callback
+// CHECK: call void {{.*}}BaseD2Ev
+// CHECK-NOT: call void @__sanitizer_dtor_callback
+// CHECK: ret void
+
+// CHECK-LABEL: define {{.*}}BaseD0Ev
+// CHECK-NOT: call void @__sanitizer_dtor_callback
+// CHECK: call void {{.*}}BaseD1Ev
+// CHECK-NOT: call void @__sanitizer_dtor_callback
+// CHECK: ret void
+
+// CHECK-LABEL: define {{.*}}BaseD2Ev
+// CHECK: call void @__sanitizer_dtor_callback
+// CHECK-NOT: call void @__sanitizer_dtor_callback
+// CHECK: ret void
+
+// CHECK-LABEL: define {{.*}}DerivedD2Ev
+// CHECK: call void @__sanitizer_dtor_callback
+// CHECK-NOT: call void @__sanitizer_dtor_callback
+// CHECK: call void {{.*}}BaseD2Ev
+// CHECK-NOT: call void @__sanitizer_dtor_callback
+// CHECK: ret void
// Repressing the sanitization attribute results in no msan
// instrumentation of the destructor
// CHECK: define {{.*}}No_SanD1Ev{{.*}} [[ATTRIBUTE:#[0-9]+]]
+// CHECK-NOT: call void @__sanitizer_dtor_callback
// CHECK: call void {{.*}}No_SanD2Ev
-// CHECK: call void @__sanitizer_dtor_callback
+// CHECK-NOT: call void @__sanitizer_dtor_callback
// CHECK: ret void
// CHECK-ATTR: define {{.*}}No_SanD1Ev{{.*}} [[ATTRIBUTE:#[0-9]+]]
+// CHECK-ATTR-NOT: call void @__sanitizer_dtor_callback
// CHECK-ATTR: call void {{.*}}No_SanD2Ev
// CHECK-ATTR-NOT: call void @__sanitizer_dtor_callback
// CHECK-ATTR: ret void
// CHECK: define {{.*}}No_SanD2Ev{{.*}} [[ATTRIBUTE:#[0-9]+]]
-// CHECK: call void {{.*}}Vector
// CHECK: call void @__sanitizer_dtor_callback
+// CHECK-NOT: call void @__sanitizer_dtor_callback
+// CHECK: call void {{.*}}Vector
+// CHECK-NOT: call void @__sanitizer_dtor_callback
// CHECK: ret void
// CHECK-ATTR: define {{.*}}No_SanD2Ev{{.*}} [[ATTRIBUTE:#[0-9]+]]
+// CHECK-ATTR-NOT: call void @__sanitizer_dtor_callback
// CHECK-ATTR: call void {{.*}}Vector
// CHECK-ATTR-NOT: call void @__sanitizer_dtor_callback
// CHECK-ATTR: ret void