Open adamf88 opened 7 years ago
@rnk
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()
.
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.
@rnk Are exceptions supported on Windows?
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.
Is there any workaround for this problem? @rnk ?
Would try except __throw usage help here?
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.
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.
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
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
Also I check on several of the cases, fsanitize=undefined
alone doesn't seem to change behavior / report problems
I have finalized a ~solution~ workaround and posted it on SO, hours of pain should not go to waste :P
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.
There's https://reviews.llvm.org/D143108, but it seems to have slipped through the cracks on everyone's ends. Would that help here?
Nice, that does look like a proper fix.
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.
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 : https://github.com/llvm/llvm-project/pull/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.
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 ?