mirror of https://github.com/microsoft/clang.git
[ExprConstant] Fix PR28314 - crash while evluating objectsize.
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
This commit is contained in:
parent
7b4330af6b
commit
8313f1a0e7
|
@ -6540,25 +6540,32 @@ static const Expr *ignorePointerCastsAndParens(const Expr *E) {
|
||||||
///
|
///
|
||||||
/// Please note: this function is specialized for how __builtin_object_size
|
/// Please note: this function is specialized for how __builtin_object_size
|
||||||
/// views "objects".
|
/// views "objects".
|
||||||
|
///
|
||||||
|
/// If this encounters an invalid RecordDecl, it will always return true.
|
||||||
static bool isDesignatorAtObjectEnd(const ASTContext &Ctx, const LValue &LVal) {
|
static bool isDesignatorAtObjectEnd(const ASTContext &Ctx, const LValue &LVal) {
|
||||||
assert(!LVal.Designator.Invalid);
|
assert(!LVal.Designator.Invalid);
|
||||||
|
|
||||||
auto IsLastFieldDecl = [&Ctx](const FieldDecl *FD) {
|
auto IsLastOrInvalidFieldDecl = [&Ctx](const FieldDecl *FD, bool &Invalid) {
|
||||||
if (FD->getParent()->isUnion())
|
const RecordDecl *Parent = FD->getParent();
|
||||||
|
Invalid = Parent->isInvalidDecl();
|
||||||
|
if (Invalid || Parent->isUnion())
|
||||||
return true;
|
return true;
|
||||||
const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(FD->getParent());
|
const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(Parent);
|
||||||
return FD->getFieldIndex() + 1 == Layout.getFieldCount();
|
return FD->getFieldIndex() + 1 == Layout.getFieldCount();
|
||||||
};
|
};
|
||||||
|
|
||||||
auto &Base = LVal.getLValueBase();
|
auto &Base = LVal.getLValueBase();
|
||||||
if (auto *ME = dyn_cast_or_null<MemberExpr>(Base.dyn_cast<const Expr *>())) {
|
if (auto *ME = dyn_cast_or_null<MemberExpr>(Base.dyn_cast<const Expr *>())) {
|
||||||
if (auto *FD = dyn_cast<FieldDecl>(ME->getMemberDecl())) {
|
if (auto *FD = dyn_cast<FieldDecl>(ME->getMemberDecl())) {
|
||||||
if (!IsLastFieldDecl(FD))
|
bool Invalid;
|
||||||
return false;
|
if (!IsLastOrInvalidFieldDecl(FD, Invalid))
|
||||||
|
return Invalid;
|
||||||
} else if (auto *IFD = dyn_cast<IndirectFieldDecl>(ME->getMemberDecl())) {
|
} else if (auto *IFD = dyn_cast<IndirectFieldDecl>(ME->getMemberDecl())) {
|
||||||
for (auto *FD : IFD->chain())
|
for (auto *FD : IFD->chain()) {
|
||||||
if (!IsLastFieldDecl(cast<FieldDecl>(FD)))
|
bool Invalid;
|
||||||
return false;
|
if (!IsLastOrInvalidFieldDecl(cast<FieldDecl>(FD), Invalid))
|
||||||
|
return Invalid;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6581,8 +6588,9 @@ static bool isDesignatorAtObjectEnd(const ASTContext &Ctx, const LValue &LVal) {
|
||||||
return false;
|
return false;
|
||||||
BaseType = CT->getElementType();
|
BaseType = CT->getElementType();
|
||||||
} else if (auto *FD = getAsField(LVal.Designator.Entries[I])) {
|
} else if (auto *FD = getAsField(LVal.Designator.Entries[I])) {
|
||||||
if (!IsLastFieldDecl(FD))
|
bool Invalid;
|
||||||
return false;
|
if (!IsLastOrInvalidFieldDecl(FD, Invalid))
|
||||||
|
return Invalid;
|
||||||
BaseType = FD->getType();
|
BaseType = FD->getType();
|
||||||
} else {
|
} else {
|
||||||
assert(getAsBaseClass(LVal.Designator.Entries[I]) != nullptr &&
|
assert(getAsBaseClass(LVal.Designator.Entries[I]) != nullptr &&
|
||||||
|
|
|
@ -52,3 +52,27 @@ void f6(void)
|
||||||
__builtin___memccpy_chk (buf, b, '\0', sizeof(b), __builtin_object_size (buf, 0));
|
__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}}
|
__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;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue