From: Nick Lewycky Date: Wed, 11 Sep 2013 02:03:20 +0000 (+0000) Subject: Disable the bool and enum sanitizers when emitting the implicitly-defined copy X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=62a3bbaac79f6e1b242ae3914e3ed4615f09302d;p=clang Disable the bool and enum sanitizers when emitting the implicitly-defined copy constructor, copy assignment operator and move assignment operator. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@190481 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp index 4eb27c3d54..392fe85f64 100644 --- a/lib/CodeGen/CGClass.cpp +++ b/lib/CodeGen/CGClass.cpp @@ -740,6 +740,29 @@ void CodeGenFunction::EmitConstructorBody(FunctionArgList &Args) { ExitCXXTryStmt(*cast(Body), true); } +namespace { + /// RAII object to indicate that codegen is copying the value representation + /// instead of the object representation. Useful when copying a struct or + /// class which has uninitialized members and we're only performing + /// lvalue-to-rvalue conversion on the object but not its members. + class CopyingValueRepresentation { + public: + explicit CopyingValueRepresentation(CodeGenFunction &CGF) + : CGF(CGF), SO(*CGF.SanOpts), OldSanOpts(CGF.SanOpts) { + SO.Bool = false; + SO.Enum = false; + CGF.SanOpts = &SO; + } + ~CopyingValueRepresentation() { + CGF.SanOpts = OldSanOpts; + } + private: + CodeGenFunction &CGF; + SanitizerOptions SO; + const SanitizerOptions *OldSanOpts; + }; +} + namespace { class FieldMemcpyizer { public: @@ -939,9 +962,10 @@ namespace { if (AggregatedInits.size() <= 1) { // This memcpy is too small to be worthwhile. Fall back on default // codegen. - for (unsigned i = 0; i < AggregatedInits.size(); ++i) { + if (!AggregatedInits.empty()) { + CopyingValueRepresentation CVR(CGF); EmitMemberInitializer(CGF, ConstructorDecl->getParent(), - AggregatedInits[i], ConstructorDecl, Args); + AggregatedInits[0], ConstructorDecl, Args); } reset(); return; @@ -980,8 +1004,8 @@ namespace { private: // Returns the memcpyable field copied by the given statement, if one - // exists. Otherwise r - FieldDecl* getMemcpyableField(Stmt *S) { + // exists. Otherwise returns null. + FieldDecl *getMemcpyableField(Stmt *S) { if (!AssignmentsMemcpyable) return 0; if (BinaryOperator *BO = dyn_cast(S)) { @@ -1075,8 +1099,10 @@ namespace { void emitAggregatedStmts() { if (AggregatedStmts.size() <= 1) { - for (unsigned i = 0; i < AggregatedStmts.size(); ++i) - CGF.EmitStmt(AggregatedStmts[i]); + if (!AggregatedStmts.empty()) { + CopyingValueRepresentation CVR(CGF); + CGF.EmitStmt(AggregatedStmts[0]); + } reset(); } @@ -1672,8 +1698,7 @@ CodeGenFunction::EmitSynthesizedCXXCopyCtorCall(const CXXConstructorDecl *D, EmitAggregateCopy(This, Src, (*ArgBeg)->getType()); return; } - llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(D, - clang::Ctor_Complete); + llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(D, clang::Ctor_Complete); assert(D->isInstance() && "Trying to emit a member call expr on a static method!"); diff --git a/test/CodeGenCXX/catch-undef-behavior.cpp b/test/CodeGenCXX/catch-undef-behavior.cpp index 217c3fdb0f..c949506d4e 100644 --- a/test/CodeGenCXX/catch-undef-behavior.cpp +++ b/test/CodeGenCXX/catch-undef-behavior.cpp @@ -340,7 +340,7 @@ class C : public A, public B // align=16 // offset. The pointer before subtraction doesn't need to be aligned for // the destination type. -// CHECK-LABEL-LABEL: define void @_Z16downcast_pointerP1B(%class.B* %b) +// CHECK-LABEL: define void @_Z16downcast_pointerP1B(%class.B* %b) void downcast_pointer(B *b) { (void) static_cast(b); // Alignment check from EmitTypeCheck(TCK_DowncastPointer, ...) @@ -357,7 +357,7 @@ void downcast_pointer(B *b) { // CHECK-NEXT: br i1 [[AND]] } -// CHECK-LABEL-LABEL: define void @_Z18downcast_referenceR1B(%class.B* %b) +// CHECK-LABEL: define void @_Z18downcast_referenceR1B(%class.B* %b) void downcast_reference(B &b) { (void) static_cast(b); // Alignment check from EmitTypeCheck(TCK_DowncastReference, ...) @@ -372,4 +372,87 @@ void downcast_reference(B &b) { // CHECK-NEXT: br i1 [[AND]] } +namespace CopyValueRepresentation { + // CHECK-LABEL: define {{.*}} @_ZN23CopyValueRepresentation2S3aSERKS0_ + // CHECK-NOT: call {{.*}} @__ubsan_handle_load_invalid_value + // CHECK-LABEL: define {{.*}} @_ZN23CopyValueRepresentation2S4aSEOS0_ + // CHECK-NOT: call {{.*}} @__ubsan_handle_load_invalid_value + // CHECK-LABEL: define {{.*}} @_ZN23CopyValueRepresentation2S5C2ERKS0_ + // CHECK-NOT: call {{.*}} __ubsan_handle_load_invalid_value + // CHECK-LABEL: define {{.*}} @_ZN23CopyValueRepresentation2S2C2ERKS0_ + // CHECK: __ubsan_handle_load_invalid_value + // CHECK-LABEL: define {{.*}} @_ZN23CopyValueRepresentation2S1C2ERKS0_ + // CHECK-NOT: call {{.*}} __ubsan_handle_load_invalid_value + + struct CustomCopy { CustomCopy(); CustomCopy(const CustomCopy&); }; + struct S1 { + CustomCopy CC; + bool b; + }; + void callee1(S1); + void test1() { + S1 s11; + callee1(s11); + S1 s12; + s12 = s11; + } + + static bool some_global_bool; + struct ExprCopy { + ExprCopy(); + ExprCopy(const ExprCopy&, bool b = some_global_bool); + }; + struct S2 { + ExprCopy EC; + bool b; + }; + void callee2(S2); + void test2(void) { + S2 s21; + callee2(s21); + S2 s22; + s22 = s21; + } + + struct CustomAssign { CustomAssign &operator=(const CustomAssign&); }; + struct S3 { + CustomAssign CA; + bool b; + }; + void test3() { + S3 x, y; + x = y; + } + + struct CustomMove { + CustomMove(); + CustomMove(const CustomMove&&); + CustomMove &operator=(const CustomMove&&); + }; + struct S4 { + CustomMove CM; + bool b; + }; + void test4() { + S4 x, y; + x = static_cast(y); + } + + struct EnumCustomCopy { + EnumCustomCopy(); + EnumCustomCopy(const EnumCustomCopy&); + }; + struct S5 { + EnumCustomCopy ECC; + bool b; + }; + void callee5(S5); + void test5() { + S5 s51; + callee5(s51); + S5 s52; + s52 = s51; + } +} + // CHECK: attributes [[NR_NUW]] = { noreturn nounwind }