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

Fix invalid pointer casts in arm64 implementation #65

Merged
merged 2 commits into from
Sep 6, 2024

Conversation

davidben
Copy link
Contributor

@davidben davidben commented Sep 6, 2024

It is UB in C and C++ to type-pun pointers in this way, for two reasons. First, casting to a pointer is forbidden if the pointer is not aligned. Second, this kind of type-punning is a strict aliasing violation.

Instead, the way to read 8 bytes as a time as a uint64_t is to call memcpy. Compilers recognize this pattern and optimize it, lowering it to the same code, but without breaking the language's abstract state machine.

This is needed to fix some UBSan warnings in Chromium.

It is UB in C and C++ to type-pun pointers in this way, for two reasons.
First, casting to a pointer is forbidden if the pointer is not aligned.
Second, this kind of type-punning is a strict aliasing violation.

Instead, the way to read 8 bytes as a time as a uint64_t is to call
memcpy. Compilers recognize this pattern and optimize it, lowering it to
the same code, but without breaking the language's abstract state
machine.

This is needed to fix some UBSan warnings in Chromium.
Copy link
Member

@pwnall pwnall left a comment

Choose a reason for hiding this comment

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

Thank you for for flagging this problem!

Would you be willing to address these comments, or would you prefer that I do it in a follow-up?

@@ -24,17 +25,31 @@
#define KBYTES 1032
#define SEGMENTBYTES 256

static uint64_t LoadU64(const uint8_t in[sizeof(uint64_t)]) {
Copy link
Member

Choose a reason for hiding this comment

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

Can you use and extend crc32c_read_le.h?

I think that ReadUint32LE() and ReadUint64LE() there work as you need them to, and we checked that they're compiled as efficiently as memcpy on little-endian architectures.

You can add a ReadUint16LE() with tests, and then use it here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah nice! Done. See commit message of 1b4eb1a for some notes on what I changed there.

In doing so, I fixed up crc32c_read_le.h a bit:

1. The documentation and tests say the buffers need to be aligned, but
   they don't.

2. Add a 16-bit version.

3. Remove an unnecessary static_cast<uint8_t>. The pointer is already
   uint8_t.

4. Replace the necessary static_casts with uintN_t{x} per the Google
   style guide. https://google.github.io/styleguide/cppguide.html#Casting
Copy link
Member

@pwnall pwnall left a comment

Choose a reason for hiding this comment

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

Thank you very much for the revisions!

@pwnall pwnall merged commit d3d60ac into google:main Sep 6, 2024
21 checks passed
@davidben davidben deleted the fix-alignment-ub branch September 6, 2024 22:51
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