vsapsai created this revision.
vsapsai added reviewers: rsmith, efriedma.

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


https://reviews.llvm.org/D42498

Files:
  clang/lib/AST/ExprConstant.cpp
  clang/test/SemaCXX/constant-expression-cxx1y.cpp

Index: clang/test/SemaCXX/constant-expression-cxx1y.cpp
===================================================================
--- clang/test/SemaCXX/constant-expression-cxx1y.cpp
+++ clang/test/SemaCXX/constant-expression-cxx1y.cpp
@@ -1021,3 +1021,44 @@
 }
 static_assert(evalNested(), "");
 } // namespace PR19741
+
+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, "");
+
+} // namespace IndirectFields
Index: clang/lib/AST/ExprConstant.cpp
===================================================================
--- clang/lib/AST/ExprConstant.cpp
+++ clang/lib/AST/ExprConstant.cpp
@@ -449,6 +449,9 @@
     /// Index - The call index of this call.
     unsigned Index;
 
+    /// IndirectField - The indirect field being evaluated.
+    const IndirectFieldDecl *IndirectField = nullptr;
+
     // FIXME: Adding this to every 'CallStackFrame' may have a nontrivial impact
     // on the overall stack usage of deeply-recursing constexpr evaluataions.
     // (We should cache this map rather than recomputing it repeatedly.)
@@ -4370,6 +4373,7 @@
   for (const auto *I : Definition->inits()) {
     LValue Subobject = This;
     APValue *Value = &Result;
+    Frame.IndirectField = nullptr;
 
     // Determine the subobject to initialize.
     FieldDecl *FD = nullptr;
@@ -4399,6 +4403,7 @@
     } 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.
+      Frame.IndirectField = IFD;
       for (auto *C : IFD->chain()) {
         FD = cast<FieldDecl>(C);
         CXXRecordDecl *CD = cast<CXXRecordDecl>(FD->getParent());
@@ -4437,6 +4442,7 @@
       Success = false;
     }
   }
+  Frame.IndirectField = nullptr;
 
   return Success &&
          EvaluateStmt(Ret, Info, Definition->getBody()) != ESR_Failed;
@@ -5612,6 +5618,20 @@
 
         Result.setFrom(Info.Ctx, RVal);
       }
+    } else if (Info.CurrentCall->IndirectField) {
+      // Fields of anonymous structs/unions can refer to other fields. In this
+      // case the 'this' expression corresponds to anonymous struct/union but
+      // Info.CurrentCall->This corresponds to the field's non-anonymous parent.
+      for (auto *C : Info.CurrentCall->IndirectField->chain()) {
+        const FieldDecl *FD = cast<FieldDecl>(C);
+        if (!FD->isImplicit()) {
+          assert(E->getType()->getPointeeCXXRecordDecl() == FD->getParent() &&
+                 "Should adjust LValue to refer to the same 'this'");
+          break;
+        }
+        if (!HandleLValueMember(Info, E, Result, FD))
+          return false;
+      }
     }
     return true;
   }
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D42498: [... Volodymyr Sapsai via Phabricator via cfe-commits

Reply via email to