This is an archive of the discontinued LLVM Phabricator instance.

Update and improve compiler-rt tests for -mllvm -asan_use_after_return=(never|[runtime]|always).
ClosedPublic

Authored by kda on May 28 2021, 1:56 AM.

Diff Detail

Event Timeline

kda created this revision.May 28 2021, 1:56 AM
kda requested review of this revision.May 28 2021, 1:56 AM
Herald added projects: Restricted Project, Restricted Project. · View Herald TranscriptMay 28 2021, 1:56 AM
Herald added subscribers: llvm-commits, Restricted Project. · View Herald Transcript
vitalybuka added inline comments.May 29 2021, 2:37 PM
compiler-rt/lib/asan/asan_fake_stack.cpp
196–197

Flawless change should be in a separate patch.

Also this is slow pass, one per thread. I don't think we care about performance of this branch, so I would prefer we avoid extending API where unnecessary.

compiler-rt/lib/asan/asan_rtl.cpp
26 ↗(On Diff #348465)

why it's moved?

46 ↗(On Diff #348465)

we use __asan_... for interface functions names

I assume none will call it outside of this file
so should be CamelCase and static

Maybe rename it InitAsanDetectUAROption() and move

entire switch here?

compiler-rt/test/asan/TestCases/heavy_uar_test.cpp
4

-O2?

kda updated this revision to Diff 348871.May 31 2021, 8:04 PM
kda marked 3 inline comments as done.

Improvements based on feedback.

kda updated this revision to Diff 348872.May 31 2021, 8:05 PM

remove commmented out lines.

compiler-rt/lib/asan/asan_rtl.cpp
26 ↗(On Diff #348465)

I'm guessing the linter ordered it... as it is now alphabetical.

kda edited the summary of this revision. (Show Details)May 31 2021, 8:47 PM
vitalybuka accepted this revision.Jun 1 2021, 10:23 AM

LGTM

compiler-rt/lib/asan/asan_rtl.cpp
26 ↗(On Diff #348465)

:) somehow I didn't notice that it's ordered now

46 ↗(On Diff #348465)

you can move this few lines below, or even better closer to the call and remove __asan:: prefixes

This revision is now accepted and ready to land.Jun 1 2021, 10:23 AM
vitalybuka requested changes to this revision.Jun 1 2021, 10:25 AM
This revision now requires changes to proceed.Jun 1 2021, 10:25 AM
vitalybuka added inline comments.Jun 1 2021, 10:26 AM
llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp
2650

what we are going to do if different modules inserted the global with different values?

kda updated this revision to Diff 349016.Jun 1 2021, 10:29 AM

move InitAsanOptionDetectStackUseAfterReturn.

vitalybuka added a comment.EditedJun 1 2021, 10:32 AM

and then
asan_use_after_return_mode -> asan_use_after_return_always

kda added inline comments.Jun 1 2021, 10:32 AM
compiler-rt/lib/asan/asan_rtl.cpp
46 ↗(On Diff #348465)

Moved to just above AsanInitInternal.

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

I don't know. I'm open to ideas.
How is it solved elsewhere?
Although, this is a very specific global.

vitalybuka added inline comments.Jun 1 2021, 10:45 AM
llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp
2650

BTW, it changes pass so we need some IR test in llvm/tests

Also there is alternative to Lazy allocate stack in runtime. Would you like to try?

kda updated this revision to Diff 349143.Jun 1 2021, 5:26 PM

add test for global generation.

kda marked an inline comment as done.Jun 1 2021, 5:31 PM

Also there is alternative to Lazy allocate stack in runtime. Would you like to try?

Not this time around. I would rather finish this round, then attempt to "lazy allocate".

kda added a comment.Jun 1 2021, 5:33 PM

and then
asan_use_after_return_mode -> asan_use_after_return_always

Are you suggesting renaming this flag now or later?
The new name seems boolean, but this is a tri-state.

kda updated this revision to Diff 349145.Jun 1 2021, 5:42 PM

bring back lost changes.

kda updated this revision to Diff 349208.Jun 2 2021, 2:42 AM
  • Optionally create weak variable __asan_detect_use_after_return_always to resolve conflicting compilations.
kda edited the summary of this revision. (Show Details)Jun 2 2021, 2:45 AM
kda added inline comments.
compiler-rt/lib/asan/asan_interface.inc
17

I don't think this is right, but I could not determine a better course of action.

morehouse added inline comments.Jun 2 2021, 1:04 PM
compiler-rt/lib/asan/asan_rtl.cpp
402 ↗(On Diff #349208)

According to the comment above, we should not override the runtime flag when this is 1.

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

I guess currently the linker would arbitrarily pick one value.

The question is when would we expect to compile modules with different values of the -asan_use_after_return flag? If this is a valid and common use case, we might want to address it in DFSan as well.

2656

The constant value 1 is also inconsistent with the comment in the runtime (should be 2).

kda added inline comments.Jun 2 2021, 2:16 PM
compiler-rt/lib/asan/asan_rtl.cpp
402 ↗(On Diff #349208)

Check the code in AddressSanitizer, this global (__asan_detect_use_after_return_always) is only created when ClUseAfterReturn is set to 2.

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

I could change it if you felt it made the code clearer. __asan_detect_use_after_return_always is functionally a boolean. It is only created if ClUseAfterReturn is equal to Always (2).

morehouse added inline comments.Jun 2 2021, 2:19 PM
llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp
2656

Maybe just change the comment in asan_rtl.cpp. Seems simplest.

eugenis added a subscriber: eugenis.Jun 2 2021, 2:21 PM

__asan_detect_use_after_return, any variant of it, is not entirely correct. First, using the presence of the global is better than its value, because the linker will pick a random instance in case they disagree, while &(...) != nullptr gives reliable OR semantics.

Second, this does not handle dlopen out of the box. It can be almost fixed by calling something from a library constructor (like __asan_init) and passing the address/value of the UAR setting, but even that is not 100% correct as code from a library may run before any of that library's constructors. It will also require late-initialization of fake stack on all existing threads at the time of dlopen.

Lazy init would work, but need to make sure that fake stack init is async signal safe, because the first use in a thread may be in a signal context. Another option is to make sure that unused fake stack is cheap, and initialize it always. I don't know if that is the case right now.

Having said all this, the implementation in this revision will kind of work in most cases, and the worst consequence of a mistake is some performance loss, so I'm fine with the change as is.

vitalybuka accepted this revision.EditedJun 2 2021, 5:01 PM

Other then comment at asan_rtl.cpp:39 LGTM

__asan_detect_use_after_return, any variant of it, is not entirely correct. First, using the presence of the global is better than its value, because the linker will pick a random instance in case they disagree, while &(...) != nullptr gives reliable OR semantics.

Second, this does not handle dlopen out of the box. It can be almost fixed by calling something from a library constructor (like __asan_init) and passing the address/value of the UAR setting, but even that is not 100% correct as code from a library may run before any of that library's constructors. It will also require late-initialization of fake stack on all existing threads at the time of dlopen.

Lazy init would work, but need to make sure that fake stack init is async signal safe, because the first use in a thread may be in a signal context. Another option is to make sure that unused fake stack is cheap, and initialize it always. I don't know if that is the case right now.

Having said all this, the implementation in this revision will kind of work in most cases, and the worst consequence of a mistake is some performance loss, so I'm fine with the change as is.

We discussed this disadvantages with @kda already offline.
I guess patch like this does not add any difficulties to switch to Lazy one after we we investigate signal safety or other possible implications.

compiler-rt/lib/asan/asan_rtl.cpp
402 ↗(On Diff #349208)

I guess @morehouse comment is about comment on the line 39.
It makes impression that value stored makes a difference, but as we discussed before only presence matters.
I would put there just:
if __asan_detect_use_after_return_always is defined, runtime must not check detect_stack_use_after_return and create FakeStack

We don't expect 0 there

if (&__asan_detect_use_after_return_always) {
  CHECK_EQ(1, __asan_detect_use_after_return_always);
This revision is now accepted and ready to land.Jun 2 2021, 5:01 PM
morehouse added inline comments.Jun 2 2021, 5:06 PM
compiler-rt/lib/asan/asan_rtl.cpp
402 ↗(On Diff #349208)

Yes my main concern was the inaccurate comment.

But my understanding was that @kda wanted 3 options: always, never, and decided-by-runtime-flag. In that case, we *do* expect a zero value to indicate the "never" option.

kda updated this revision to Diff 349585.Jun 3 2021, 9:29 AM
kda marked an inline comment as done.
  • improved comments and validated state, instead of checking.
compiler-rt/lib/asan/asan_interface.inc
17

No one complained. I'm leaving it.

compiler-rt/lib/asan/asan_rtl.cpp
402 ↗(On Diff #349208)

Okay, I tried to clear up the comments above. and purged the test for non-zero.

vitalybuka accepted this revision.Jun 3 2021, 10:43 AM
vitalybuka added inline comments.
compiler-rt/lib/asan/asan_rtl.cpp
39–48 ↗(On Diff #349585)

This comment explain more instrumented code.
I'd rather inverted it:
asan_detect_use_after_return_always is undefined: all instrumented modules either compiled with asan_use_after_return 1 or 0
asan_detect_use_after_return_always is defined: at least one of modules compiled with asan_use_after_return 2

kda updated this revision to Diff 349649.Jun 3 2021, 12:40 PM
  • Revised comment according to feedback.
kda marked an inline comment as done.Jun 3 2021, 12:41 PM
This revision was landed with ongoing or failed builds.Jun 3 2021, 1:13 PM
This revision was automatically updated to reflect the committed changes.

@kda This change has broken our internal builds on macOS. I'm not sure why it hasn't broken the public ones. If you add a new weak symbol it needs to be added to lib/asan/weak_symbols.txt so that the linker on macOS knowns it's okay for the symbol to not be defined. We'll put up a patch to fix this shortly.

thakis added a subscriber: thakis.Jun 3 2021, 5:21 PM

Hi, this seems to not build on macOS, see http://45.33.8.238/macm1/10715/step_4.txt or http://45.33.8.238/mac/32177/summary.html

Please take a look and revert for now if it takes a while to fix.

thakis added a comment.Jun 3 2021, 6:01 PM

Oh, I see that that was already reported over an hour ago. Reverted for now in 5c600dc6d4b75bc71dc3033f37ea187b3fd454d7

Oh, I see that that was already reported over an hour ago. Reverted for now in 5c600dc6d4b75bc71dc3033f37ea187b3fd454d7

@thakis Thanks for reverting.

@kda This change has broken our internal builds on macOS. I'm not sure why it hasn't broken the public ones. If you add a new weak symbol it needs to be added to lib/asan/weak_symbols.txt so that the linker on macOS knowns it's okay for the symbol to not be defined. We'll put up a patch to fix this shortly.

@kda Seeing as this patch was reverted it doesn't make sense for me to put up a patch to fix it. If you try to reland this please update lib/asan/weak_symbols.txt as I mentioned in previous comments.

FWIW, this patch also broke building for windows. Weak symbols overall is a tricky area on windows, and I don't think this particular usage (the asan lib having a weak undefined symbol, which the executable may or may not proivide) works with windows DLLs at all.

kda added a comment.Jun 4 2021, 12:56 PM

FWIW, this patch also broke building for windows. Weak symbols overall is a tricky area on windows, and I don't think this particular usage (the asan lib having a weak undefined symbol, which the executable may or may not proivide) works with windows DLLs at all.

@mstorsjo Is there a short-term work around?
FYI: I do plan to follow with a late-initialization solution.

FWIW, this patch also broke building for windows. Weak symbols overall is a tricky area on windows, and I don't think this particular usage (the asan lib having a weak undefined symbol, which the executable may or may not proivide) works with windows DLLs at all.

@mstorsjo Is there a short-term work around?
FYI: I do plan to follow with a late-initialization solution.

I'm not well versed in the asan internals to know all the tricks that are used so far, but if this mechanism is a new thing and we've done without it so far and seems hard to do, can we just ifdef it out on windows and keep doing things like they were before there?

kda reopened this revision.Jun 4 2021, 1:07 PM

In an attempt to fix for macOS and Windows.

This revision is now accepted and ready to land.Jun 4 2021, 1:07 PM
kda updated this revision to Diff 349972.Jun 4 2021, 2:31 PM
  • Remove weak variable from Windows implementation.
This revision was landed with ongoing or failed builds.Jun 4 2021, 4:31 PM
This revision was automatically updated to reflect the committed changes.
thakis added a comment.Jun 4 2021, 4:43 PM

Looks like this relanded. It still doesn't build on mac: http://45.33.8.238/macm1/10837/step_4.txt

Please take a look and revert for now if it takes a while to fix.

thakis added a comment.Jun 4 2021, 4:46 PM

Wait, this might be a bot config problem this time, looking

thakis added a comment.Jun 4 2021, 4:50 PM

Yes, it was a problem on my end, all good now.

Why is this a weak symbol? Most asan symbols aren't, and it looks like the mac and win troubles are due to you making this a weak symbol.

kda added a comment.Jun 4 2021, 4:57 PM

discussion begins: https://reviews.llvm.org/D103304#2794683
tl;dr: modules can be built with different flag settings, weak symbol
allows resolution in runtime. Long term (in 2 weeks) solution, late
initialization of fake stack.

vitalybuka reopened this revision.Jun 4 2021, 8:20 PM
This revision is now accepted and ready to land.Jun 4 2021, 8:20 PM
vitalybuka updated this revision to Diff 350013.Jun 4 2021, 8:23 PM

Upload the last reverted version

vitalybuka requested changes to this revision.EditedJun 4 2021, 11:56 PM

I looked at Lazy approach and it's simpler then I thought. Asan already contains all needed pieces.
Considering that we have not idea how to handle Windows and Darwin we should do that in this patch.

Cloning of GetFakeStackFast -> GetFakeStackFastAlways which does not check __asan_option_detect_stack_use_after_return should be enough.

static FakeStack *GetFakeStackFast() {
  if (FakeStack *fs = GetTLSFakeStack())
    return fs;
  if (!__asan_option_detect_stack_use_after_return)
    return nullptr;
  return GetFakeStack();
}


static FakeStack *GetFakeStackFastAlways() {
  if (FakeStack *fs = GetTLSFakeStack())
    return fs;
  return GetFakeStack();
}

And same for all callers.
Anything __asan_detect_use_after_return_always related can be reverted.

This revision now requires changes to proceed.Jun 4 2021, 11:56 PM
vitalybuka accepted this revision.Jun 5 2021, 12:18 AM

Oh, I missed

Yes, it was a problem on my end, all good now.

I'll re-land reverted changes back.

This revision is now accepted and ready to land.Jun 5 2021, 12:18 AM
This revision was landed with ongoing or failed builds.Jun 5 2021, 12:26 AM
This revision was automatically updated to reflect the committed changes.
vitalybuka reopened this revision.Jun 5 2021, 12:40 AM
This revision is now accepted and ready to land.Jun 5 2021, 12:40 AM
kda added a comment.Jun 5 2021, 7:59 AM

Regarding below, I had this previously: https://reviews.llvm.org/differential/changeset/?ref=2601358

The problem I don't know how to navigate is that GetFakeStackFast is only called from one place (at runtime, the other is for testing only).
That call is in OnMalloc. Which, in turn, is only called from one place: __asan_stack_malloc_<##class_id>

How do I have the runtime code pick the Always version of GetFakeStackFast without examining the global?
Do I inject the function ptr when generating the call to __asan_stack_malloc?

I looked at Lazy approach and it's simpler then I thought. Asan already contains all needed pieces.
Considering that we have not idea how to handle Windows and Darwin we should do that in this patch.

Cloning of GetFakeStackFast -> GetFakeStackFastAlways which does not check __asan_option_detect_stack_use_after_return should be enough.

static FakeStack *GetFakeStackFast() {
  if (FakeStack *fs = GetTLSFakeStack())
    return fs;
  if (!__asan_option_detect_stack_use_after_return)
    return nullptr;
  return GetFakeStack();
}


static FakeStack *GetFakeStackFastAlways() {
  if (FakeStack *fs = GetTLSFakeStack())
    return fs;
  return GetFakeStack();
}

And same for all callers.
Anything __asan_detect_use_after_return_always related can be reverted.

vitalybuka added a comment.EditedJun 7 2021, 11:04 AM

Regarding below, I had this previously: https://reviews.llvm.org/differential/changeset/?ref=2601358

Correct, at that time I thought we are doing WEAK asan_use_after_return_mode, for which new fictions are not needed.
Sorry, we'd save some time if I asked to drop
asan_use_after_return_mode instead.
If you are going to recover that one I'd recommencement Flagless -> Always to be consistent with naming?

The problem I don't know how to navigate is that GetFakeStackFast is only called from one place (at runtime, the other is for testing only).
That call is in OnMalloc. Which, in turn, is only called from one place: __asan_stack_malloc_<##class_id>

How do I have the runtime code pick the Always version of GetFakeStackFast without examining the global?
Do I inject the function ptr when generating the call to __asan_stack_malloc?

No, AddressSanitizer.cpp Always branch will call only __asan_stack_malloc_always_<class_id> functions Runtime branch will continue to call __asan_stack_malloc_<class_id>

I looked at Lazy approach and it's simpler then I thought. Asan already contains all needed pieces.
Considering that we have not idea how to handle Windows and Darwin we should do that in this patch.

Cloning of GetFakeStackFast -> GetFakeStackFastAlways which does not check __asan_option_detect_stack_use_after_return should be enough.

static FakeStack *GetFakeStackFast() {
  if (FakeStack *fs = GetTLSFakeStack())
    return fs;
  if (!__asan_option_detect_stack_use_after_return)
    return nullptr;
  return GetFakeStack();
}


static FakeStack *GetFakeStackFastAlways() {
  if (FakeStack *fs = GetTLSFakeStack())
    return fs;
  return GetFakeStack();
}

And same for all callers.
Anything __asan_detect_use_after_return_always related can be reverted.

kda updated this revision to Diff 350607.Jun 8 2021, 8:26 AM
  • change from flagless to always in function names.
  • fix up tests, add TOOD for removing unnecessary method.
kda added a comment.Jun 8 2021, 8:27 AM

Alright, please give it another look.

vitalybuka accepted this revision.Jun 8 2021, 9:50 AM

Thanks. LGTM with some nits.

compiler-rt/lib/asan/asan_fake_stack.cpp
219

static ALWAYS_INLINE
siblings as well.

246

Just insert 3rd one here, and please clang format

llvm/test/Instrumentation/AddressSanitizer/stack-poisoning.ll
1–2

You can add now into =never cases "FileCheck ... --implicit-check-not __asan_stack_malloc"

kda updated this revision to Diff 350694.Jun 8 2021, 12:46 PM
kda marked 2 inline comments as done.
  • a little clean-up: static methods, formatting, improved tests
kda added inline comments.Jun 8 2021, 1:35 PM
compiler-rt/lib/asan/asan_fake_stack.cpp
219

Although, with ALWAYS_INLINE, I'm not sure 'static' makes any difference, as the code is already local to the call point.

This revision was landed with ongoing or failed builds.Jun 8 2021, 2:39 PM
This revision was automatically updated to reflect the committed changes.
vitalybuka added inline comments.Jun 8 2021, 4:50 PM
compiler-rt/lib/asan/asan_fake_stack.cpp
219

with inline it still need needs provide external version of the symbol

219

with "inline-no-static" it still need needs provide external version of the symbol

241

I asked to remove DEFINE_STACK_MALLOC_ALWAYS_WITH_CLASS_ID and just have:

using namespace __asan;
#define DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(class_id)                       \
  extern "C" SANITIZER_INTERFACE_ATTRIBUTE uptr                                \
      __asan_stack_malloc_##class_id(uptr size) {                              \
    return OnMalloc(class_id, size);                                           \
  }                                                                            \
  extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __asan_stack_free_##class_id(  \
      uptr ptr, uptr size) {                                                   \
    OnFree(ptr, class_id, size);                                               \
  }
  extern "C" SANITIZER_INTERFACE_ATTRIBUTE uptr            \
      __asan_stack_malloc_always_##class_id(uptr size) {   \
    return OnMallocAlways(class_id, size);                 \
  }

DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(0)
DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(1)
DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(2)
DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(3)
DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(4)
DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(5)
DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(6)
DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(7)
DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(8)
DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(9)
DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(10)
kda added inline comments.Jun 9 2021, 7:29 AM
compiler-rt/lib/asan/asan_fake_stack.cpp
241