From e8f1ffb50a203c3b2e1f5bb94f493ecb381a43fa Mon Sep 17 00:00:00 2001 From: Volodymyr Sapsai Date: Fri, 23 Feb 2018 23:59:20 +0000 Subject: [PATCH] [ExprConstant] Fix crash when initialize an indirect field with another field. When indirect field is initialized with another field, you have MemberExpr with CXXThisExpr that corresponds to the field's immediate anonymous parent. But 'this' was referring to the non-anonymous parent. So when we were building LValue Designator, it was incorrect as it had wrong starting point. Usage of such designator would cause unexpected APValue changes and crashes. The fix is in adjusting 'this' for indirect fields from non-anonymous parent to the field's immediate parent. Discovered by OSS-Fuzz: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=4985 rdar://problem/36359187 Reviewers: rsmith, efriedma Reviewed By: rsmith Subscribers: cfe-commits, jkorous-apple Differential Revision: https://reviews.llvm.org/D42498 llvm-svn: 325997 --- clang/lib/AST/ExprConstant.cpp | 20 +++++-- .../SemaCXX/constant-expression-cxx1y.cpp | 54 +++++++++++++++++++ 2 files changed, 70 insertions(+), 4 deletions(-) diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 6ef6d566665a..3d44d3369d0c 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -4383,6 +4383,7 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This, #endif for (const auto *I : Definition->inits()) { LValue Subobject = This; + LValue SubobjectParent = This; APValue *Value = &Result; // Determine the subobject to initialize. @@ -4413,7 +4414,8 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This, } else if (IndirectFieldDecl *IFD = I->getIndirectMember()) { // Walk the indirect field decl's chain to find the object to initialize, // and make sure we've initialized every step along it. - for (auto *C : IFD->chain()) { + auto IndirectFieldChain = IFD->chain(); + for (auto *C : IndirectFieldChain) { FD = cast(C); CXXRecordDecl *CD = cast(FD->getParent()); // Switch the union field if it differs. This happens if we had @@ -4429,6 +4431,10 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This, *Value = APValue(APValue::UninitStruct(), CD->getNumBases(), std::distance(CD->field_begin(), CD->field_end())); } + // Store Subobject as its parent before updating it for the last element + // in the chain. + if (C == IndirectFieldChain.back()) + SubobjectParent = Subobject; if (!HandleLValueMember(Info, I->getInit(), Subobject, FD)) return false; if (CD->isUnion()) @@ -4440,10 +4446,16 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This, llvm_unreachable("unknown base initializer kind"); } + // Need to override This for implicit field initializers as in this case + // This refers to innermost anonymous struct/union containing initializer, + // not to currently constructed class. + const Expr *Init = I->getInit(); + ThisOverrideRAII ThisOverride(*Info.CurrentCall, &SubobjectParent, + isa(Init)); FullExpressionRAII InitScope(Info); - if (!EvaluateInPlace(*Value, Info, Subobject, I->getInit()) || - (FD && FD->isBitField() && !truncateBitfieldValue(Info, I->getInit(), - *Value, FD))) { + if (!EvaluateInPlace(*Value, Info, Subobject, Init) || + (FD && FD->isBitField() && + !truncateBitfieldValue(Info, Init, *Value, FD))) { // If we're checking for a potential constant expression, evaluate all // initializers even if some of them fail. if (!Info.noteFailure()) diff --git a/clang/test/SemaCXX/constant-expression-cxx1y.cpp b/clang/test/SemaCXX/constant-expression-cxx1y.cpp index d22cba430adc..c5c868bd1b24 100644 --- a/clang/test/SemaCXX/constant-expression-cxx1y.cpp +++ b/clang/test/SemaCXX/constant-expression-cxx1y.cpp @@ -1045,3 +1045,57 @@ namespace Mutable { constexpr B b; constexpr int p = b.n; // expected-error {{constant expression}} expected-note {{mutable}} } + +namespace IndirectFields { + +// Reference indirect field. +struct A { + struct { + union { + int x = x = 3; // expected-note {{outside its lifetime}} + }; + }; + constexpr A() {} +}; +static_assert(A().x == 3, ""); // expected-error{{not an integral constant expression}} expected-note{{in call to 'A()'}} + +// Reference another indirect field, with different 'this'. +struct B { + struct { + union { + int x = 3; + }; + int y = x; + }; + constexpr B() {} +}; +static_assert(B().y == 3, ""); + +// Nested evaluation of indirect field initializers. +struct C { + union { + int x = 1; + }; +}; +struct D { + struct { + C c; + int y = c.x + 1; + }; +}; +static_assert(D().y == 2, ""); + +// Explicit 'this'. +struct E { + int n = 0; + struct { + void *x = this; + }; + void *y = this; +}; +constexpr E e1 = E(); +static_assert(e1.x != e1.y, ""); +constexpr E e2 = E{0}; +static_assert(e2.x != e2.y, ""); + +} // namespace IndirectFields