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

Asan doesn't work with exceptions on Windows #749

Open
adamf88 opened this issue Dec 4, 2016 · 17 comments
Open

Asan doesn't work with exceptions on Windows #749

adamf88 opened this issue Dec 4, 2016 · 17 comments

Comments

@adamf88
Copy link

adamf88 commented Dec 4, 2016

If I run this code with -fsanitize=address then I get an error message like below.
What is the status of exception support on Windows by address sanitizer ?

#include <cstdio>
#include <exception>
int main()
{
	try	{
		throw std::exception("test");
	}catch (const std::exception& ex){
		puts(ex.what());
	}
	return 0;
}

=================================================================
==6620==ERROR: AddressSanitizer: access-violation on unknown address 0x1024448f (pc 0x00061285 bp 0x003aff1c sp 0x003af620 T0)
==6620==The signal is caused by a READ memory access.
#0 0x61284 in main D:\Private\asan_exception\AsanExcpetion\AsanExcpetion\Source.cpp:9
#1 0x616eb in __scrt_common_main_seh f:\dd\vctools\crt\vcstartup\src\startup\exe_common.inl:253
#2 0x76b33369 in BaseThreadInitThunk+0x11 (C:\Windows\syswow64\kernel32.dll+0x7dd73369)
#3 0x77539901 in RtlInitializeExceptionChain+0x62 (C:\Windows\SysWOW64\ntdll.dll+0x7dea9901)
#4 0x775398d4 in RtlInitializeExceptionChain+0x35 (C:\Windows\SysWOW64\ntdll.dll+0x7dea98d4)
AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: access-violation D:\Private\asan_exception\AsanExcpetion\AsanExcpetion\Source.cpp:9 in ma
in
==6620==ABORTING

@kcc
Copy link
Contributor

kcc commented Dec 5, 2016

@rnk

@rnk
Copy link
Contributor

rnk commented Dec 7, 2016

A simpler example:

extern "C" int printf(const char *, ...);
int main() {
  try {
    throw 1;
  } catch (int e) {
    printf("caught %d\n", e);
  }
  return 0;
}

With ASan this prints "caught 1561575566", and "caught 1" without. I think ASan instrumentation is interfering with catch object stack objects. It's attempting to instrument them, when they must appear at some fixed offset from the stack pointer. In your example, this interference results in a null dereference while evaluating ex.what().

@rnk
Copy link
Contributor

rnk commented Dec 7, 2016

Also, ASan instrumentation isn't inserting calls into EH pads with the right funclet token bundle, so any attempts to do ASan checks inside funclets will be removed by WinEHPrepare. This will require significant work to fix.

@morehouse
Copy link
Contributor

@rnk Are exceptions supported on Windows?

@rnk
Copy link
Contributor

rnk commented Jun 8, 2018

No, the comment about EH pads and tokens is still relevant. It is more likely that we will change the way windows EH funclets work to make it so that ASan's instrumentation is more naturally compatible with Windows EH than that we will fix ASan to deal with the current system.

@jrozansk
Copy link

jrozansk commented Jan 10, 2019

Is there any workaround for this problem?
@rnk ?

Would __try __except __throw usage help here?

@rnk
Copy link
Contributor

rnk commented Jan 14, 2019

Is there any workaround for this problem?

Well, the workaround would be to apply __attribute__((no_sanitize_address)) to every function that uses EH, and if your application doesn't use EH in normal operation, things will work.

Would __try __except __throw usage help here?

What did you have in mind? Functions that use SEH (__try / __except) already have asan disabled for other reasons, so I don't think it would help.

@0dminnimda
Copy link

Damn, I've spent a whole day trying to understand what's failing in my code and I finally got here. I think there should be at least some compiler warning about this.

@0dminnimda
Copy link

Well, the workaround would be to apply __attribute__((no_sanitize_address)) to every function that uses EH, and if your application doesn't use EH in normal operation, things will work.

It doesn't sound very nice to not sanitize the whole functions, so a slightly better workaround is to wrap the try/catch in a lambda and execute it immediately.

#include <iostream>
#include <exception>

int main() {
    []() __attribute__((no_sanitize_address)) {
        try {
            throw std::runtime_error("test");
        } catch (const std::runtime_error &ex) {
            std::cout << ex.what() << std::endl;
        }
    }();

    std::cout << "end" << std::endl;
    return 0;
}

Unfortunately, handling the exception in a separate function doesn't really help, as it only reduces the length of the ASan message.

If this

#include <iostream>
#include <exception>

int main() {
    try {
        throw std::runtime_error("test");
    } catch (const std::runtime_error &ex) {
        std::cout << ex.what() << std::endl;
    }

    std::cout << "end" << std::endl;
    return 0;
}

results in

asan.cpp:8:22: runtime error: upcast of misaligned address 0x00000000000e for type 'std::runtime_error', which requires 8 byte alignment
0x00000000000e: note: pointer points here
<memory cannot be printed>
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior asan.cpp:8:22 in
asan.cpp:8:25: runtime error: member call on misaligned address 0x00000000000e for type 'std::exception', which requires 8 byte alignment
0x00000000000e: note: pointer points here
<memory cannot be printed>
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior asan.cpp:8:25 in
=================================================================
==4384==ERROR: AddressSanitizer: access-violation on unknown address 0x00000000000e (pc 0x7ff74e3d12ca bp 0x008e4edcfaf0 sp 0x008e4edcd7f0 T0)
==4384==The signal is caused by a READ memory access.
==4384==Hint: address points to the zero page.
    #0 0x7ff74e3d12c9 in main C:\projects\test\asan.cpp:8
    #1 0x7ff74e478ccf in _CallSettingFrame d:\a01\_work\6\s\src\vctools\crt\vcruntime\src\eh\amd64\handlers.asm:49
    #2 0x7ff74e46e6bb in __FrameHandler3::CxxCallCatchBlock(struct _EXCEPTION_RECORD *) d:\a01\_work\6\s\src\vctools\crt\vcruntime\src\eh\frame.cpp:1521
    #3 0x7fffdfbb1715  (C:\WINDOWS\SYSTEM32\ntdll.dll+0x1800a1715)
    #4 0x7ff74e3d113b in main C:\projects\test\asan.cpp:6
    #5 0x7ff74e435d6b in invoke_main d:\a01\_work\6\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:78
    #6 0x7ff74e435d6b in __scrt_common_main_seh d:\a01\_work\6\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:288
    #7 0x7fffdf757613  (C:\WINDOWS\System32\KERNEL32.DLL+0x180017613)
    #8 0x7fffdfb626b0  (C:\WINDOWS\SYSTEM32\ntdll.dll+0x1800526b0)

AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: access-violation C:\projects\test\asan.cpp:8 in main
==4384==ABORTING

This

#include <iostream>
#include <exception>

__attribute__((no_sanitize_address)) void handle(const std::runtime_error &ex) noexcept {
    std::cout << ex.what() << std::endl;
}

int main() {
    try {
        throw std::runtime_error("test");
    } catch (const std::runtime_error &ex) {
        handle(ex);
    }

    std::cout << "end" << std::endl;
    return 0;
}

results in

asan.cpp:12:16: runtime error: reference binding to misaligned address 0x00000000000e for type 'const std::runtime_error', which requires 8 byte alignment
0x00000000000e: note: pointer points here
<memory cannot be printed>
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior asan.cpp:12:16 in
asan.cpp:5:18: runtime error: upcast of misaligned address 0x00000000000e for type 'std::runtime_error', which requires 8 byte alignment
0x00000000000e: note: pointer points here
<memory cannot be printed>
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior asan.cpp:5:18 in
asan.cpp:5:21: runtime error: member call on misaligned address 0x00000000000e for type 'std::exception', which requires 8 byte alignment
0x00000000000e: note: pointer points here
<memory cannot be printed>
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior asan.cpp:5:21 in
=================================================================
==33904==ERROR: AddressSanitizer: access-violation on unknown address 0x00000000000e (pc 0x7ff70b881070 bp 0x00c27556da20 sp 0x00c27556d9d0 T0)
==33904==The signal is caused by a READ memory access.
==33904==Hint: address points to the zero page.
    #0 0x7ff70b88106f in handle(class std::runtime_error const &) C:\projects\test\asan.cpp:5
    #1 0x7ff70b88138c in main C:\projects\test\asan.cpp:12
    #2 0xc27556faff  (<unknown module>)

AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: access-violation C:\projects\test\asan.cpp:5 in handle(class std::runtime_error const &)
==33904==ABORTING

@0dminnimda
Copy link

And with more experementation we can see a wide array of interesting error messages

For code with handle():

using std::runtime_error &ex will result in

asan.cpp:12:16: runtime error: reference binding to misaligned address 0x7ff6d7a794b4 for type 'std::runtime_error', which requires 8 byte alignment
0x7ff6d7a794b4: note: pointer points here
  20 5b c3 cc 48 83 ec 28  48 8b 0d 69 87 9c 00 48  85 c9 74 29 48 8b 01 48  8b 40 10 ff 15 7f 0f 00
              ^
...
==4292==ERROR: AddressSanitizer: access-violation on unknown address 0xffffffffffffffff (pc 0x7ff6d7981073 bp 0x0091e7efd500 sp 0x0091e7efd4b0 T0)
==4292==The signal is caused by a READ memory access.
...

std::runtime_error ex will not trigger ASan, but will print Unknown exception
While std::exception ex will print gibberish Л╟HЛ\$0HГ─ _├╠HЙ\LЙL$ WHГь IЛ┘IЛ°Л
const std::exception ex will print Unknown exception again

For custom exception with handle():

class CustomException : public std::exception {
    const char *message;

public:
    CustomException(const char *msg) : message(msg) {}
    const char *what() const noexcept override { return message; }
};

const CustomException &ex results in

asan.cpp:20:16: runtime error: reference binding to misaligned address 0x7ff646c59894 for type 'const CustomException', which requires 8 byte alignment
0x7ff646c59894: note: pointer points here
  20 5b c3 cc 48 83 ec 28  48 8b 0d 89 96 9c 00 48  85 c9 74 29 48 8b 01 48  8b 40 10 ff 15 9f 0b 00
...
the rest is roughly the same

CustomException &ex results in

asan.cpp:20:16: runtime error: reference binding to misaligned address 0x00000000000e for type 'CustomException', which requires 8 byte alignment
0x00000000000e: note: pointer points here
<memory cannot be printed>
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior asan.cpp:20:16 in

CustomException ex and const CustomException ex results in no erros and gibberish @ўS∙3 and Л╟HЛ\$0HГ─ _├╠HЙ\LЙL$ WHГь IЛ┘IЛ°Л ш╝N

Gibberish does not change between runs and change only between compilations


And those cases compile and run perfectly fine without -fsanitize=address,undefined, so it doesn't just report false positives, it can negatively change the behavior in this case

@0dminnimda
Copy link

Also I check on several of the cases, fsanitize=undefined alone doesn't seem to change behavior / report problems

@0dminnimda
Copy link

I have finalized a solution workaround and posted it on SO, hours of pain should not go to waste :P

@rnk
Copy link
Contributor

rnk commented Aug 17, 2023

I can't speak to our help with the detailed problems you are having, but we can definitely improve the way this incompatibility is handled.

@smeenai , didn't we have some solution to this problem for other instrumentation tools? Alternatively, we can power-off ASan for functions using EH automatically, it's easy to detect a personality function and the presence of catchpad/cleanuppad.

@smeenai
Copy link

smeenai commented Aug 17, 2023

There's https://reviews.llvm.org/D143108, but it seems to have slipped through the cracks on everyone's ends. Would that help here?

@rnk
Copy link
Contributor

rnk commented Aug 17, 2023

Nice, that does look like a proper fix.

@sylvain-audi
Copy link

I'm sure the patch may help, but it seems to only be a part o the problem (trying the repro above with the patch still fails).
I created #64990 for the issue with funclets, that the review mentioned above addresses.

helly25 added a commit to helly25/mbo that referenced this issue Oct 28, 2023
This still cannot be enabled in asan mode due to google/sanitizers#749
still not being solved and the proposed workaround not actually working.
virt00l pushed a commit to virt00l/daScript that referenced this issue Feb 22, 2024
Workaround for google/sanitizers#749
Downstream commit - #453999
@sylvain-audi
Copy link

There's https://reviews.llvm.org/D143108, but it seems to have slipped through the cracks on everyone's ends. Would that help here?

That review was redone as a PR : llvm/llvm-project#82533
and was merged today.

It fixes one part of this issue: now Asan on Windows target should at least support the case of catch() without parameter. However catch(xxx) is still broken.

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

No branches or pull requests

9 participants