Skip to content

Conversation

@Xazax-hun
Copy link
Contributor

@Xazax-hun Xazax-hun commented Jun 20, 2024

The code path responsible for calculating field offsets creates opaque fields for all the base classes. This code path simply summed up the sizes of the base classes to get the offset. Unfortunately, this does not work for base classes with vptrs. C++ does not embedd the vptrs from the base classes into the derived class. The derived class has a single vptr. This PR removes this assumption that we can just add the base class sizes up and relies purely on base and field offsets to calculate the sizes for the opaque fields representing the base classes.

Fixes #73136.
rdar://126754931

@Xazax-hun Xazax-hun changed the title [cxx-interop] Fix wrong field offsets with value types using inheritance [draft][cxx-interop] Fix wrong field offsets with value types using inheritance Jun 20, 2024
@Xazax-hun
Copy link
Contributor Author

Looks like there are still some test failures that I need to investigate.

@Xazax-hun Xazax-hun marked this pull request as draft June 20, 2024 12:44
@Xazax-hun Xazax-hun force-pushed the gaborh/inheritance branch 2 times, most recently from 8794431 to 3c086ab Compare June 21, 2024 17:39
@Xazax-hun
Copy link
Contributor Author

@swift-ci please smoke test

@Xazax-hun Xazax-hun added the c++ interop Feature: Interoperability with C++ label Jun 24, 2024
The code path responsible for calculating field offsets creates opaque fields for all the base classes. This code path simply summed up the sizes of the base classes to get the offset. Unfortunately, this does not work for base classes with vptrs. C++ does not embedd the vptrs from the base classes into the derived class. The derived class has a single vptr. This PR removes this assumption that we can just add the base class sizes up and relies purely on base and field offsets to calculate the sizes for the opaque fields representing the base classes.
@Xazax-hun Xazax-hun force-pushed the gaborh/inheritance branch from 3c086ab to 2161a1d Compare June 24, 2024 14:28
@Xazax-hun
Copy link
Contributor Author

@swift-ci please smoke test

@Xazax-hun Xazax-hun changed the title [draft][cxx-interop] Fix wrong field offsets with value types using inheritance [cxx-interop] Fix wrong field offsets with value types using inheritance Jun 24, 2024
@Xazax-hun Xazax-hun marked this pull request as ready for review June 24, 2024 18:13
@Xazax-hun
Copy link
Contributor Author

A high-level comment. I could have tried to correctly calculate the ABI by introducing adjustments, like subtracting the size of the vptr from the base's size. But there are complex ABI rules in some cases where fields can be packed into the base's trailing padding. I decided that only relying on the offsets is more reliable and less likely to break when something changes in Clang.

Copy link
Contributor

@rjmccall rjmccall left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the basic approach here is just wrong. If we want to add opaque storage for a (non-empty) base, we should add storage covering its nv-size rather than trying to compute it by the range to the next base in the layout. But really, I think we should be recursing into the base rather than treating it as totally opaque.


auto baseType = base.getType().getCanonicalType();
// The empty bases are all at offset 0, so we need to remove them to
// reliably calculate base subobject sizes using the next base's offset.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is not generally true that empty bases are all at offset zero.

@Xazax-hun
Copy link
Contributor Author

I think the basic approach here is just wrong. If we want to add opaque storage for a (non-empty) base, we should add storage covering its nv-size rather than trying to compute it by the range to the next base in the layout. But really, I think we should be recursing into the base rather than treating it as totally opaque.

I will give the non-virtual size a try and see if this works out. By recursing into the base you mean collecting all the fields from the base classes as well, right?

@rjmccall
Copy link
Contributor

I think the basic approach here is just wrong. If we want to add opaque storage for a (non-empty) base, we should add storage covering its nv-size rather than trying to compute it by the range to the next base in the layout. But really, I think we should be recursing into the base rather than treating it as totally opaque.

I will give the non-virtual size a try and see if this works out. By recursing into the base you mean collecting all the fields from the base classes as well, right?

Yes, I mean collecting fields from base classes (offset as necessary) as an alternative to just adding the entire base subobject as opaque storage.

While you're at it, please fix this to not just ignore virtual bases. Maybe we don't import these types yet, but (1) there's no reason for this code to handle them incorrectly and (2) I suspect we can visit them indirectly, e.g. if you have a class with a field that has a virtual base. The correct way to handle virtual bases is to handle them exactly like normal bases, but only when you're visiting the object as a complete object type (i.e. not when you're recursively visiting base subobjects in the walk I'm asking you to add).

@Xazax-hun
Copy link
Contributor Author

Xazax-hun commented Jul 11, 2024

Thanks! I could not get back to this for a while, but now I opened a new PR that does the recursive walk: #75176

This one does not deal with virtual inheritance yet, because that is not required to fix the crash and we have some higher priority items to address first (and the patch is already getting larger enough, so splitting up might also make reviewing easier).

@Xazax-hun Xazax-hun closed this Jul 11, 2024
@Xazax-hun Xazax-hun deleted the gaborh/inheritance branch July 17, 2024 14:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

c++ interop Feature: Interoperability with C++

3 participants