This is an archive of the discontinued LLVM Phabricator instance.

[ExprConstant] Fix crash when initialize an indirect field with another field.
ClosedPublic

Authored by vsapsai on Jan 24 2018, 12:13 PM.

Details

Summary

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

Diff Detail

Repository
rL LLVM

Event Timeline

vsapsai created this revision.Jan 24 2018, 12:13 PM

Please handle this by temporarily updating the This pointer appropriately when evaluating the CXXDefaultInitExpr rather than trying to work around the This value being wrong later (your approach will still go wrong if the This pointer is used in other ways, such as an explicit mention of this or a member function call). You can refer to how we do this in CodeGen: look for CodeGenFunction::CXXDefaultInitExprScope and CodeGenFunction::FieldConstructionScope.

Thanks for response, Richard. I'll look into using CXXDefaultInitExpr.

As for

[…] your approach will still go wrong if the This pointer is used in other ways, such as an explicit mention of this or a member function call.

I wasn't able to find a failing test case. Maybe I misunderstood you but in my testing functions declared in named structs had correct This pointer and in anonymous structs functions cannot be declared.

vsapsai updated this revision to Diff 135708.Feb 23 2018, 2:56 PM
  • Override This for indirect field initializer more like it is done for InitListExpr.

I rebased my changes, so the diff between different versions can be noisy.

rsmith accepted this revision.Feb 23 2018, 3:10 PM

Looks good, thanks!

[…] your approach will still go wrong if the This pointer is used in other ways, such as an explicit mention of this or a member function call.

I wasn't able to find a failing test case. Maybe I misunderstood you but in my testing functions declared in named structs had correct This pointer and in anonymous structs functions cannot be declared.

Here's a testcase that fails today:

struct A { int n = 0; struct { void *p = this; }; void *q = this; };
constexpr A a = A();
static_assert(a.p != a.q, ""); // fails today, should pass

constexpr A b = A{0};
static_assert(b.p != b.q, ""); // passes today

With the previous approach of fixing up the This value only in class member access, the above testcase would presumably still fail. I expect it to pass with your new approach.

This revision is now accepted and ready to land.Feb 23 2018, 3:10 PM
This revision was automatically updated to reflect the committed changes.
This revision was automatically updated to reflect the committed changes.

Thanks for the review. Explicit this usage is a good test, added it.

Checked that it happened to work with my previous approach because initializer was CXXDefaultInitExpr with expression

ImplicitCastExpr 0x7fe966808c40 'void *' <BitCast>
`-CXXThisExpr 0x7fe966808c28 'struct A::(anonymous at file.cc:3:5) *' this