This is an archive of the discontinued LLVM Phabricator instance.

[Asan] Add "funclet" OpBundle to Asan calls that are generated inside a funclet
Needs ReviewPublic

Authored by saudi on Feb 1 2023, 1:33 PM.

Details

Summary

This patch implements a fix for issue https://github.com/llvm/llvm-project/issues/64990, implementing the solution suggested in the comments of issue https://github.com/llvm/llvm-project/issues/39667

It ensures that when asan creates calls (__asan_*) inside of a funclet, those calls are tagged with the required "funclet" OpBundle.
It only applies to EH personality that use funclets, especially Windows EH.

Also, changed localescape test, switching its EH personality to match the code which doesn't match the funclet scoping.

Diff Detail

Event Timeline

saudi created this revision.Feb 1 2023, 1:33 PM
saudi requested review of this revision.Feb 1 2023, 1:33 PM
rnk added a reviewer: akhuang.May 9 2023, 2:56 PM
rnk added a reviewer: hans.

Seeking a code reviewer, +@aeubanks, @vitalybuka

This came up in https://github.com/google/sanitizers/issues/749

The general approach makes sense to me.

can you update the description to say https://github.com/llvm/llvm-project/issues/39667 (or #39667) instead of PR39667? llvm.org/PR39667 redirects to a different issue

saudi edited the summary of this revision. (Show Details)Aug 18 2023, 6:04 AM
saudi updated this revision to Diff 551595.Aug 18 2023, 12:08 PM

Rebased on main.

Also added a check to allow colorless BasicBlocks from colorEHFunclets(), for the case of unreachable BB, which may happen during the asan pass.

rnk explained the background for this to me but I'm still somewhat unfamiliar with the details so you may need to explain some things to me

it'd be nice to add an end-to-end test in compiler-rt for whatever case you were seeing

the test coverage doesn't seem sufficient, can you add some more tests?

llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp
649

I'd separate out a bool instead of using std::optional, that's a bit clearer

702

should run clang-format before uploading

706

I'm unfamiliar with this code, why is this true?

2710–2713

is EH relevant to the ctor/dtor functions?

llvm/test/Instrumentation/AddressSanitizer/asan-funclet.ll
4

please use llvm/utils/update_test_checks.py instead of manual CHECK lines

7

test needs REQUIRES: x86-registered-target

22

please remove irrelevant things in the IR like dso_local/noundef/etc and also make the function names a little nicer

saudi updated this revision to Diff 553523.Aug 25 2023, 10:30 AM
saudi marked 2 inline comments as done.

Updated to address comments.

    • Changed std::optional to use a bool instead
    • Removed changes for __asan_* calls that don't apply to Windows EH handling scenarios (module ctor/dtor, globals array)
  • Added compiler-rt test
  • Improved the test for more coverage

I didn't update the test with llvm/utils/update_test_checks.py, I have more questions about it, which I will post soon.

saudi marked 3 inline comments as done.Aug 25 2023, 10:33 AM
saudi added inline comments.
llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp
706

This is a constraint on the funclets in the Windows EH model.

An illustration in code is in WinEHPrepare pass verifyPreparedFunclets method here : https://github.com/llvm/llvm-project/blob/llvmorg-18-init/llvm/lib/CodeGen/WinEHPrepare.cpp#L1167
(from which I copied the assert)

In the documentation I found this: https://llvm.org/docs/ExceptionHandling.html#funclet-parent-tokens
It explains that the funclet structure must represent a tree.

I'm not an expert in this, but my understanding is that in WinEH model, the funclets need to be structured as a tree; the coloring allows to identify which "node" each EH-related BasicBlock belongs to, having the constraint that the BB must belong to one and only one node.

@rnk can you confirm?

2710–2713

My approach was to play it safe by using the RuntimeCallInserter for any runtime calls to __asan_*() introduced by the AddressSanitizer pass; the RuntimeCallInserter being responsible for adding funclet bundles as a postprocess.

I agree it's confusing. I updated the code where I removed the modifications for unneeded cases, where the __asan_xxx calls can't be in a EH pad, like this example of the module ctor/dtor

llvm/test/Instrumentation/AddressSanitizer/asan-funclet.ll
4

The pass introduces a lot of instructions and a few basic blocks. The output of update_test_checks.py gets large and too specific for testing this particular feature. It would easily break when asan gets modified in the future.

This is my first time using that script. Is the usual approach to apply update_test_checks.py and only keep the CHECK lines necessary with potential minor modifications?

saudi edited the summary of this revision. (Show Details)Aug 25 2023, 10:41 AM

mostly lgtm, but one major suggestion

llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp
663

these initialize/reset aren't great in terms of keeping C++ lifetimes straight, I think we should go with a more RAII approach where we construct a RuntimeCallInserter per function we instrument and pass that around. this will make sure we automatically handle all the corner cases like the LooksLikeCodeInBug11395 codepath, and also make sure we never reuse RuntimeCallInserter for multiple functions. then we can get rid of all the manual calls to initialize/finalize.

llvm/test/Instrumentation/AddressSanitizer/asan-funclet.ll
4

typically yeah we still recommend people to use update_test_checks.py since updating them is easy if other patches change the tests, and manual checks are error-prone and can often become obsolete. but most asan tests aren't using it so this is fine

saudi updated this revision to Diff 554060.Aug 28 2023, 2:56 PM
saudi marked an inline comment as done.

Applied suggestion in comment (making RuntimeCallInserter use an RAII approach)

vitalybuka added inline comments.Aug 28 2023, 2:59 PM
llvm/test/Instrumentation/AddressSanitizer/asan-funclet.ll
4

Can you please precommit the test generated with update_test_checks without your patch
so in this patch we can see a difference in generated code.
Assuming compiler does not crash without the patch.

rnk added inline comments.Aug 28 2023, 3:54 PM
llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp
706

I think it is possible to construct cases where valid transforms will lead to multi-color blocks. Consider patches like https://reviews.llvm.org/D29428

I would actually strengthen the assert here to report an error via the LLVMContext. That seems to be the behavior that folks want.

saudi added inline comments.Aug 28 2023, 5:32 PM
llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp
706

If I understand correctly:

  • WinEHPrepare pass is run later, and ensures the blocks are monochromatic
  • In AddressSanitizer pass, this constraint is not guaranteed, we could be trying to introduce a runtime call inside a multi-color block

And you are suggesting detecting and reporting that case as a remark.

Could another approach be to tag the new calls somehow, in a way that would let WinHEPrepare know that instead of discarding it, it should just add the missing OpBundle?

And if so, could you point me in the right direction? (I was thinking of adding a new opbundle "autofunclet", but there might be much better ways?)

llvm/test/Instrumentation/AddressSanitizer/asan-funclet.ll
4

Just to be sure, are you suggesting that I do the following?

  1. prepare the file asan-funclet.ll before the fix is applied, apply update_test_checks.py and do a NFC commit with this single file asan-funclet.ll
  2. apply my code change, and update asan-funclet.ll using update_test_checks.py -> update this patch, so that we can see more easily what happens?

Note that the test file will become much larger: applying update_test_checks.py generates 500+ lines of checks. It's why I went with the more manual checks, but I can surely do that.