]> granicus.if.org Git - clang/commitdiff
[ExprConstant] Fix PR28314 - crash while evluating objectsize.
authorGeorge Burgess IV <george.burgess.iv@gmail.com>
Mon, 27 Jun 2016 19:40:41 +0000 (19:40 +0000)
committerGeorge Burgess IV <george.burgess.iv@gmail.com>
Mon, 27 Jun 2016 19:40:41 +0000 (19:40 +0000)
This fixes a crash in code like:
```
struct A {
  struct B b;
  char c[1];
}

int foo(struct A* a) { return __builtin_object_size(a->c, 0); }
```

We wouldn't check whether the structs we were examining were invalid,
and getting the layout of an invalid struct is (unsurprisingly) A Bad
Thing. With this patch, we'll always return conservatively if we see an
invalid struct, since I'm assuming the presence of an invalid struct
means that our compilation failed (so having a conservative result isn't
such a big deal).

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@273911 91177308-0d34-0410-b5e6-96231b3b80d8

lib/AST/ExprConstant.cpp
test/Sema/builtin-object-size.c

index e14330cf60e78774abd7c421b3b917216483260a..6771175ba6d4d862fa83d54d92f1e4a9c66e2ba7 100644 (file)
@@ -6540,25 +6540,32 @@ static const Expr *ignorePointerCastsAndParens(const Expr *E) {
 ///
 /// Please note: this function is specialized for how __builtin_object_size
 /// views "objects".
+///
+/// If this encounters an invalid RecordDecl, it will always return true.
 static bool isDesignatorAtObjectEnd(const ASTContext &Ctx, const LValue &LVal) {
   assert(!LVal.Designator.Invalid);
 
-  auto IsLastFieldDecl = [&Ctx](const FieldDecl *FD) {
-    if (FD->getParent()->isUnion())
+  auto IsLastOrInvalidFieldDecl = [&Ctx](const FieldDecl *FD, bool &Invalid) {
+    const RecordDecl *Parent = FD->getParent();
+    Invalid = Parent->isInvalidDecl();
+    if (Invalid || Parent->isUnion())
       return true;
-    const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(FD->getParent());
+    const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(Parent);
     return FD->getFieldIndex() + 1 == Layout.getFieldCount();
   };
 
   auto &Base = LVal.getLValueBase();
   if (auto *ME = dyn_cast_or_null<MemberExpr>(Base.dyn_cast<const Expr *>())) {
     if (auto *FD = dyn_cast<FieldDecl>(ME->getMemberDecl())) {
-      if (!IsLastFieldDecl(FD))
-        return false;
+      bool Invalid;
+      if (!IsLastOrInvalidFieldDecl(FD, Invalid))
+        return Invalid;
     } else if (auto *IFD = dyn_cast<IndirectFieldDecl>(ME->getMemberDecl())) {
-      for (auto *FD : IFD->chain())
-        if (!IsLastFieldDecl(cast<FieldDecl>(FD)))
-          return false;
+      for (auto *FD : IFD->chain()) {
+        bool Invalid;
+        if (!IsLastOrInvalidFieldDecl(cast<FieldDecl>(FD), Invalid))
+          return Invalid;
+      }
     }
   }
 
@@ -6581,8 +6588,9 @@ static bool isDesignatorAtObjectEnd(const ASTContext &Ctx, const LValue &LVal) {
         return false;
       BaseType = CT->getElementType();
     } else if (auto *FD = getAsField(LVal.Designator.Entries[I])) {
-      if (!IsLastFieldDecl(FD))
-        return false;
+      bool Invalid;
+      if (!IsLastOrInvalidFieldDecl(FD, Invalid))
+        return Invalid;
       BaseType = FD->getType();
     } else {
       assert(getAsBaseClass(LVal.Designator.Entries[I]) != nullptr &&
index b1bda0652c146efd3a663f81343ef8d11bb94fe2..14674c66f3a66ed2519722dbd3dab1067c3e6bf5 100644 (file)
@@ -52,3 +52,27 @@ void f6(void)
   __builtin___memccpy_chk (buf, b, '\0', sizeof(b), __builtin_object_size (buf, 0));
   __builtin___memccpy_chk (b, buf, '\0', sizeof(buf), __builtin_object_size (b, 0));  // expected-warning {{'__builtin___memccpy_chk' will always overflow destination buffer}}
 }
+
+int pr28314(void) {
+  struct {
+    struct InvalidField a; // expected-error{{has incomplete type}} expected-note 3{{forward declaration of 'struct InvalidField'}}
+    char b[0];
+  } *p;
+
+  struct {
+    struct InvalidField a; // expected-error{{has incomplete type}}
+    char b[1];
+  } *p2;
+
+  struct {
+    struct InvalidField a; // expected-error{{has incomplete type}}
+    char b[2];
+  } *p3;
+
+  int a = 0;
+  a += __builtin_object_size(&p->a, 0);
+  a += __builtin_object_size(p->b, 0);
+  a += __builtin_object_size(p2->b, 0);
+  a += __builtin_object_size(p3->b, 0);
+  return a;
+}