This is an archive of the discontinued LLVM Phabricator instance.

[scudo] Refactor of CRC32 and ARM runtime CRC32 detection
ClosedPublic

Authored by cryptoad on Jan 11 2017, 12:06 PM.

Details

Summary

ARM & AArch64 runtime detection for hardware support of CRC32 has been added
via check of the AT_HWVAL auxiliary vector.

Following Michal's suggestions in D28417, the CRC32 code has been further
changed and looks better now. When compiled with full relro (which is strongly
suggested to benefit from additional hardening), the weak symbol for
computeHardwareCRC32 is read-only and the assembly generated is fairly clean
and straight forward. As suggested, an additional optimization is to skip
the runtime check if SSE 4.2 has been enabled globally, as opposed to only
for scudo_crc32.cpp.

scudo_crc32.h has no purpose anymore and was removed.

Event Timeline

cryptoad updated this revision to Diff 84008.Jan 11 2017, 12:06 PM
cryptoad retitled this revision from to [scudo] Refactor of CRC32 and ARM runtime CRC32 detection.
cryptoad updated this object.
cryptoad added reviewers: mgorny, alekseyshl, kcc.
cryptoad added a subscriber: llvm-commits.
rengolin added inline comments.Jan 13 2017, 10:42 AM
lib/scudo/scudo_allocator.cpp
87

nit pick, an extra else adds clarity and helps future changes.

lib/scudo/scudo_utils.cpp
105

This only works on Linux, right?

cryptoad marked an inline comment as done.Jan 13 2017, 10:49 AM
cryptoad added inline comments.
lib/scudo/scudo_utils.cpp
105

Correct. This is ensured in config-ix.cmake:

if (COMPILER_RT_HAS_SANITIZER_COMMON AND SCUDO_SUPPORTED_ARCH AND
    OS_NAME MATCHES "Linux")
  set(COMPILER_RT_HAS_SCUDO TRUE)
else()
  set(COMPILER_RT_HAS_SCUDO FALSE)
endif()

I can add a check for SANITIZER_LINUX being defined in the top header if you feel it makes things clearer.

Did you test this on AArch32 and AArch64?

lib/scudo/scudo_utils.cpp
105

Probably a good idea, if anyone ever updates the CMake file. :)

cryptoad marked 3 inline comments as done.Jan 13 2017, 11:06 AM

Tested locally on AArch64 and armhf to be exact.
AArch64 is not yet supported in the the cmake config, the patch is next.

Did you test this on AArch32 and AArch64?

cryptoad updated this revision to Diff 84335.Jan 13 2017, 11:06 AM

Addressing review comments.

rengolin accepted this revision.Jan 13 2017, 11:18 AM
rengolin added a reviewer: rengolin.

LGTM. Thanks!

This revision is now accepted and ready to land.Jan 13 2017, 11:18 AM

Thank you Renato! I will wait for @mgorny's comments to make sure it fits his idea as well.

mgorny accepted this revision.Jan 13 2017, 12:40 PM
mgorny edited edge metadata.

LGTM modulo the first comment. I won't be able to test it today, though, but I doubt it could break something for me ;-).

lib/scudo/scudo_allocator.cpp
82

If I'm not mistaken, you could add || defined(__ARM_FEATURE_CRC32) to cover the same idea for ARM.

85

I'm sorry if I'm a bit ignorant here but why are you checking the function address? Is there a potential case for it being null?

cryptoad marked an inline comment as done.Jan 13 2017, 1:46 PM
cryptoad added inline comments.
lib/scudo/scudo_allocator.cpp
82

I think for ARM, since the feature could be enabled via -mcrc (specifically for CRC32, unlike the whole instruction set for SSE 4.2), the runtime check is still required, as no other potentially illegal instructions would be emitted anywhere else.

85

Given that it's a weak symbol, if not implemented anywhere the pointer will be null indeed (some details can be found at https://en.wikipedia.org/wiki/Weak_symbol) after linking. That way, if -msse42 is not available for scudo_crc32.cpp, computeHardwareCRC32 remains unimplemented, and we fallback to the software implementation.

rengolin added inline comments.Jan 13 2017, 1:52 PM
lib/scudo/scudo_allocator.cpp
82

Right, this is actually a good point. There are basically two ideas here:

  1. You compile to force one implementation or the other, via flags. In this case, if you compile to have CRC, it will fail with sigill on cores that don't have it. The most likely scenario is that all builds will end up not having it, for safety, so you'll never use it.
  1. You have a run time check, as it is now, so that it's not a compilation option and you'll always use whenever you can. The problem now is that you end up paying the comparison price on every call.

The third, and best (but more complicated) way is to use IFUNC, but that's certainly for another patch.

FWIW, right now, the AARch64 sanitizers are getting the VMA configuration via run time calls, just like this patch, because of the problems outlines above, so this is not without prior art. :)

mgorny added inline comments.Jan 13 2017, 1:56 PM
lib/scudo/scudo_allocator.cpp
82

However, the instruction can be enabled implicitly via -march. If you build purely for ARM target that supports CRC32, I don't see a point not to use it.

85

Oh, that was the case I was missing. I don't mind using this then. However, personally I would do it the more obvious way and just #ifdef for the case when hardware CRC32 would not be implemented instead of checking at runtime ;-).

rengolin added inline comments.Jan 13 2017, 2:07 PM
lib/scudo/scudo_allocator.cpp
82

With ARM, the probability that you build in one machine (type) and run in another is higher than in x86. The number of variations and hardware support is also much much higher.

All x86_64 chips of family X have feature Y. A mix bag of ARM chips on family X, which support feature Y, has it in a way that is actually usable (ie. some cores report the feature but you really rather not use it).

All I'm saying is that, using -march=aarch64+crc will not work on any core that doesn't have it, so everyone will *not* use it in case the binary has to run on hardware that doesn't have it. Any Linux distribution (including Android) will not enable it for that reason.

If you're advocating for hard-coding if the feature IS there in mattr (either +crc or +nocrc), but leaving run-time if it's not, than I think that'll be ok, as it's a platform choice.

cryptoad marked an inline comment as done.Jan 13 2017, 2:12 PM
cryptoad added inline comments.
lib/scudo/scudo_allocator.cpp
82

IIUC, the option suggested by Michal is the counterpart to SSE 4.2: test for -mcrc support in the compiler, add it to scudo_crc32.cpp only if detected and keep the runtime check in that case. In the event of -march with CRC support, scudo_allocator.cpp can bypass the runtime check and just do hardware.

85

I had issues with #ifdef as only the .cpp is compiled with CRC32, leaving me without any symbol I could check for existence.
If you have a suggestion around that, I'll take it :)

rengolin added inline comments.Jan 13 2017, 2:18 PM
lib/scudo/scudo_allocator.cpp
82

Sounds good.

mgorny added inline comments.Jan 13 2017, 4:09 PM
lib/scudo/scudo_allocator.cpp
85

I meant making CMake explicitly define some value after determining that SSE4.2/CRC32 support is available. But that's a task for a separate patch, I guess.

lib/scudo/scudo_crc32.cpp
28

One more thing: don't you want to enable -mcrc via CMake for this file?

cryptoad added inline comments.Jan 13 2017, 6:13 PM
lib/scudo/scudo_allocator.cpp
85

Understood!

lib/scudo/scudo_crc32.cpp
28

I wasn't planning to with this, but I will update the patch to take this into account.

cryptoad updated this revision to Diff 84677.Jan 17 2017, 8:23 AM

Adding the cmake changes to allow -mcrc detection and use.

During additional testing, it was discovered that HWCAP_CRC32 was not defined
on some platforms.

phosek added inline comments.Jan 17 2017, 8:44 AM
lib/scudo/scudo_utils.cpp
110

This is likely going to create a dependency on libc++ similarly to D28757.

cryptoad marked an inline comment as done.Jan 17 2017, 8:51 AM
cryptoad added inline comments.
lib/scudo/scudo_utils.cpp
110

Changing that. Is calling getauxval OK?

cryptoad updated this revision to Diff 84684.Jan 17 2017, 9:04 AM
cryptoad marked an inline comment as done.

Removing the static qualifier for the HWCap variable to prevent libc++
dependencies.

phosek added inline comments.Jan 17 2017, 9:08 AM
lib/scudo/scudo_utils.cpp
110

Yes that's fine, it's the static initialization that's the problem.

@mgorny @rengolin I would appreciate if I could get a final nod regarding the latest changes to this patch. Thanks!

Still LGTM. I presume you have tested the final version ;-).

cryptoad closed this revision.Jan 18 2017, 9:22 AM
lib/scudo/scudo_allocator.cpp