This is an archive of the discontinued LLVM Phabricator instance.

[libc++][AIX] Make basic_string layout compatible with earlier version
ClosedPublic

Authored by xingxue on Jun 21 2022, 9:00 AM.

Details

Summary

Patch D123580 changed to use bit fields for strings in long and short mode. As a result, this changes the layout of these strings on AIX because bit fields on AIX are 4 bytes, which breaks the ABI compatibility with earlier strings before the change on AIX. This patch applies the fix proposed by @hubert.reinterpretcast in https://reviews.llvm.org/D127672#3590741 to make string layout compatible. This patch will also make test cases alignof.compile.pass.cpp and sizeof.compile.pass.cpp introduced in D127672 (later reverted) pass on AIX.

Diff Detail

Event Timeline

xingxue created this revision.Jun 21 2022, 9:00 AM
Herald added a project: Restricted Project. · View Herald TranscriptJun 21 2022, 9:00 AM
xingxue requested review of this revision.Jun 21 2022, 9:00 AM
Herald added a project: Restricted Project. · View Herald TranscriptJun 21 2022, 9:00 AM
Herald added a reviewer: Restricted Project. · View Herald Transcript
philnik added inline comments.Jun 21 2022, 10:06 AM
libcxx/include/string
728

How exactly is this different from using __atrribute__((__packed__))? If it's not I would suggest to put __is_long_ and __cap_ into it's own struct and mark only that as __attribute__((__packed__))to avoid the explicit padding and alignas() specifiers.

libcxx/include/string
728

That should work. Any preference between base class, anonymous struct, or named member?

The named member version is the most pragmatic (does not change whether the type is standard layout, does not use language extension).

philnik added inline comments.Jun 22 2022, 12:56 AM
libcxx/include/string
728

I think an anonymous struct would be the best option. That makes it almost identical to the current version, so there wouldn't have to be any code changes elsewhere.

xingxue updated this revision to Diff 439014.Jun 22 2022, 7:28 AM

Changed to use anonymous struct and __attribute__((__packed__)) as suggested.

xingxue updated this revision to Diff 439016.Jun 22 2022, 7:31 AM

Include context.

xingxue marked 3 inline comments as done.Jun 22 2022, 7:33 AM
xingxue added inline comments.
libcxx/include/string
728

Changed to use anonymous struct and attribute((packed)) as suggested, thanks!

Thanks for working on this!

The build failure is unrelated, can you rebase before reuploading this patch?

libcxx/include/string
730–733

Please add a comment explaining why we packed is needed.
(I understand it, but over a year I will scratch my head.)

753

Does __long have a fixed size too? If so can add a static_assert for it too?

xingxue updated this revision to Diff 439100.Jun 22 2022, 11:12 AM
xingxue marked an inline comment as done.

Addressed comments.

  • add comments explaining why attribute __packed__ is used;
  • add static_assert for struct __long.
xingxue marked an inline comment as done.Jun 22 2022, 11:17 AM

The build failure is unrelated, can you rebase before reuploading this patch?

Definitely, rebased before uploading the latest diff.

libcxx/include/string
730–733

Done, thanks!

753

static_assert for __long added, thanks!

libcxx/include/string
753

This assumes that pointer is not a type (maybe some sort of fancy smart pointer) that has a higher alignment requirement than sizeof(size_type) * 2.

SGTM, but for now I prefer to leave the approval to people more familiar with the details of this patch and AIX.

xingxue updated this revision to Diff 439823.Jun 24 2022, 11:09 AM
xingxue marked an inline comment as done.

Addressed the comment to consider potential padding in the assert added for struct __long.

xingxue marked an inline comment as done.Jun 24 2022, 11:11 AM
xingxue added inline comments.
libcxx/include/string
753

Good point, thanks! Modified the assert to take padding into account.

libcxx/include/string
752

This reduces to:

((2 * sizeof(size_type) - 1) / sizeof(pointer) + 2) * sizeof(pointer)

but I think now that there are many other ways for this to go wrong (pointer requires less alignment than its size, alignment of size_type causes trailing padding, etc.).

Maybe:

struct __long_size_ref {
  size_type __x, __y;
  pointer __z;
};
static_assert(sizeof(__long) == sizeof(__long_size_ref));
philnik added inline comments.Jun 24 2022, 12:35 PM
libcxx/include/string
752

How about we just drop the static_assert? I've got a patch that adds tests which static_asserts the size and alignment of specific instantiations of basic_string. That's a lot more reliable than hoping to get the size and alignment right for user-defined types.

xingxue marked an inline comment as done.Jun 24 2022, 12:39 PM
xingxue added inline comments.
libcxx/include/string
752

Sounds good.

xingxue updated this revision to Diff 439870.Jun 24 2022, 1:02 PM

Dropped the static_assert on the size of struct __long.

philnik accepted this revision.Jun 24 2022, 1:56 PM

LGTM with my comment addressed.

libcxx/include/string
730–734

Could you have this comment just once above the __long and __short structs? Having it cloned makes it a lot easier for them to get out of sync.

This revision is now accepted and ready to land.Jun 24 2022, 1:56 PM
xingxue added inline comments.Jun 24 2022, 2:02 PM
libcxx/include/string
730–734

For sure. Thanks very much for your review and good suggestions!

This revision was landed with ongoing or failed builds.Jun 24 2022, 2:26 PM
This revision was automatically updated to reflect the committed changes.