Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Force tag to the same position in KStringInner #77

Merged
merged 1 commit into from
Jul 22, 2024

Conversation

ssbr
Copy link
Contributor

@ssbr ssbr commented Jul 22, 2024

tag() relies on KStringInner having a tag field at the same offset in every union variant, and every union variant is repr(C) so that this holds (provided that B has the same size, anyway -- since it's a sealed trait, that is guaranteed for any constructed instance, though it's a bit subtle).

However, the union itself does not have a guaranteed layout unless one uses repr(C). It's a bit silly, but technically every single variant could be in a different location, causing the tags not to line up within the union even though they do within the structs individually. See e.g. https://rust-lang.github.io/unsafe-code-guidelines/layout/unions.html

The fixes would be:

  1. use a struct with a tag field first, and then a union field second. (Or even an enum, as is done with the non-unsafe implementation).
  2. use a repr(C) union instead of a repr(Rust) union.
  3. Maybe add some assertions so that even with repr(Rust), the layout is as expected?

I opted to do (2) as a quick fix to send out.

(Did not add tests, because I believe this has no change in behavior -- the layout is presumably the same now as it was before, only now it is guaranteed.)

tag() relies on KStringInner having a tag field at the same offset in every union variant, and every union variant is repr(C) so that this holds (provided that `B` has the same size, anyway -- since it's a sealed trait, that is guaranteed for any constructed instance, though it's a bit subtle).

However, the union _itself_ does not have a guaranteed layout unless one uses repr(C). It's a bit silly, but technically every single variant could be in a different location, causing the tags not to line up within the union even though they do within the structs individually. See e.g. https://rust-lang.github.io/unsafe-code-guidelines/layout/unions.html

The fixes would be:

1. use a struct with a tag field first, and then a union field second. (Or even an enum, as is done with the non-`unsafe` implementation).
2. use a repr(C) union instead of a repr(Rust) union.
3. Maybe add some assertions so that even with repr(Rust), the layout is as expected?

I opted to do (2) as a quick fix to send out.
@epage epage merged commit fd7b3bc into cobalt-org:master Jul 22, 2024
14 of 16 checks passed
@ssbr ssbr deleted the patch-1 branch July 22, 2024 20:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants