This is an archive of the discontinued LLVM Phabricator instance.

[CodeGen] -fsanitize={function,kcfi}: ensure align 4 if +strict-align
AbandonedPublic

Authored by MaskRay on Jun 28 2023, 11:18 PM.

Details

Summary

Fix https://github.com/llvm/llvm-project/issues/63579

% cat a.c
void foo() {}
% clang --target=arm-none-eabi -mthumb -mno-unaligned-access -fsanitize=kcfi a.c -S -o - | grep p2align
        .p2align        1
% clang --target=armv6m-none-eabi -fsanitize=function a.c -S -o - | grep p2align
        .p2align        1

With -mno-unaligned-access (possibly implicit), we should ensure that
-fsanitize={function,kcfi} instrumented functions are aligned by at least 4, so
that loading the type hash before the function label will not cause a misaligned
access, even if the backend doesn't set setMinFunctionAlignment to 4 or greater.

With this patch, the generated assembly for the examples above will contain .p2align 2.

If -falign-functions= is specified, take the maxiumum.

If __attribute__((aligned(2))) is specified, arbitrarily let the function
attribute win.

Since SanOpts is per-function, move the alignment setting code from
CodeGenModule::SetLLVMFunctionAttributesForDefinition to CodeGenFunction.
This move requires some attention.

Note: CodeGenModule::SetLLVMFunctionAttributesForDefinition is called by many
thunk codegen code with a dummy GlobalDecl/FunctionDecl.
However, in one call site, MicrosoftCXXABI::EmitVirtualMemPtrThunk has a
SetLLVMFunctionAttributesForDefinition use case that requires the
"Some C++ ABIs require 2-byte alignment for member functions" code. So
keep this part in CodeGenModule.

Diff Detail

Event Timeline

MaskRay created this revision.Jun 28 2023, 11:18 PM
Herald added a project: Restricted Project. · View Herald TranscriptJun 28 2023, 11:18 PM
MaskRay requested review of this revision.Jun 28 2023, 11:18 PM
Herald added a project: Restricted Project. · View Herald TranscriptJun 28 2023, 11:18 PM
Herald added a subscriber: cfe-commits. · View Herald Transcript

The details of this approach look good to me, but is this the best place to solve it? Doing it in clang means that every language front end that wants to use either of these sanitizers is responsible for doing this same work: tagging every IR function with align 4 if it also has !kcfi_type or !func_sanitize, and perhaps also checking the target-features to decide whether to do that.

I'd imagined the problem being solved at a lower level, when converting the IR into actual function prologues, so that all front ends generating IR would benefit from the fix.

I also think it makes sense to fix the alignment when we lower the metadata, not in the frontend, unless I'm missing something.

It's not clear to me how "strict-align" is relevant; if sanitizer lowering is generating "align 4" loads, the relevant pointers need to be appropriately aligned regardless of the cost of unaligned loads. Misaligned loads are undefined behavior in LLVM IR on all targets. (32-bit ARM in particular has cases where 32-bit unaligned loads are supported, but certain load instruction variations enforce alignment.)

The details of this approach look good to me, but is this the best place to solve it? Doing it in clang means that every language front end that wants to use either of these sanitizers is responsible for doing this same work: tagging every IR function with align 4 if it also has !kcfi_type or !func_sanitize, and perhaps also checking the target-features to decide whether to do that.

I'd imagined the problem being solved at a lower level, when converting the IR into actual function prologues, so that all front ends generating IR would benefit from the fix.

I also think it makes sense to fix the alignment when we lower the metadata, not in the frontend, unless I'm missing something.

It's not clear to me how "strict-align" is relevant; if sanitizer lowering is generating "align 4" loads, the relevant pointers need to be appropriately aligned regardless of the cost of unaligned loads. Misaligned loads are undefined behavior in LLVM IR on all targets. (32-bit ARM in particular has cases where 32-bit unaligned loads are supported, but certain load instruction variations enforce alignment.)

OK. See D154125 for the MachineFunction.cpp approach. If we go that direction, I'll abandon this patch.

MaskRay abandoned this revision.Jun 30 2023, 9:13 AM

Obsoleted by D154125