modocache updated this revision to Diff 214370. modocache added a comment. Thanks for the review, @vsk! Sorry it took me so long to update this diff.
In the mailing list discussion, http://lists.llvm.org/pipermail/llvm-dev/2018-March/121925.html, you mentioned that I should use an allow-list of known good sanitizer options, rather than a deny-list of known bad ones (`-fsanitize=null`, in this case). However, at this time I'm only aware of problems with `-fsanitize=null`, so I don't know what else to exclude. In other words, an allow-list of known good sanitizers would, at this point, be every other sanitizer pass. So I figured for now, I'll just deny `-fsanitize=null`. Does that work for you? Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D44672/new/ https://reviews.llvm.org/D44672 Files: clang/lib/CodeGen/CodeGenFunction.cpp clang/test/CodeGenCXX/ubsan-coroutines.cpp Index: clang/test/CodeGenCXX/ubsan-coroutines.cpp =================================================================== --- /dev/null +++ clang/test/CodeGenCXX/ubsan-coroutines.cpp @@ -0,0 +1,49 @@ +// This test merely verifies that emitting the object file does not cause a +// crash when the LLVM coroutines passes are run. +// RUN: %clang_cc1 -emit-obj -std=c++2a -fsanitize=null %s -o %t.o + +namespace std::experimental { +template <typename R, typename... T> struct coroutine_traits { + using promise_type = typename R::promise_type; +}; + +template <class Promise = void> struct coroutine_handle; +template <> struct coroutine_handle<void> { + static coroutine_handle from_address(void *) noexcept; + coroutine_handle() = default; + template <class PromiseType> + coroutine_handle(coroutine_handle<PromiseType>) noexcept; +}; +template <class Promise> struct coroutine_handle : coroutine_handle<void> { + coroutine_handle() = default; + static coroutine_handle from_address(void *) noexcept; +}; +} + +struct suspend_always { + bool await_ready() noexcept; + void await_suspend(std::experimental::coroutine_handle<>) noexcept; + void await_resume() noexcept; +}; + +struct task { + struct promise_type { + task get_return_object() { return task(); } + suspend_always initial_suspend() { return {}; } + suspend_always final_suspend() { return {}; } + void return_void() {} + void unhandled_exception() {} + }; +}; + +struct awaitable { + task await() { (void)co_await *this; } + bool await_ready() { return false; } + bool await_suspend(std::experimental::coroutine_handle<> awaiter) { return false; } + bool await_resume() { return false; } +}; + +int main() { + awaitable a; + a.await(); +} Index: clang/lib/CodeGen/CodeGenFunction.cpp =================================================================== --- clang/lib/CodeGen/CodeGenFunction.cpp +++ clang/lib/CodeGen/CodeGenFunction.cpp @@ -732,6 +732,15 @@ SanOpts.Mask &= ~SanitizerKind::CFIUnrelatedCast; } + // Ignore null checks in coroutine functions since the coroutines passes + // are not aware of how to move the extra UBSan instructions across the split + // coroutine boundaries. + if (D && SanOpts.has(SanitizerKind::Null)) + if (const auto *FD = dyn_cast<FunctionDecl>(D)) + if (FD->getBody() && + FD->getBody()->getStmtClass() == Stmt::CoroutineBodyStmtClass) + SanOpts.Mask &= ~SanitizerKind::Null; + // Apply xray attributes to the function (as a string, for now) if (D) { if (const auto *XRayAttr = D->getAttr<XRayInstrumentAttr>()) {
Index: clang/test/CodeGenCXX/ubsan-coroutines.cpp =================================================================== --- /dev/null +++ clang/test/CodeGenCXX/ubsan-coroutines.cpp @@ -0,0 +1,49 @@ +// This test merely verifies that emitting the object file does not cause a +// crash when the LLVM coroutines passes are run. +// RUN: %clang_cc1 -emit-obj -std=c++2a -fsanitize=null %s -o %t.o + +namespace std::experimental { +template <typename R, typename... T> struct coroutine_traits { + using promise_type = typename R::promise_type; +}; + +template <class Promise = void> struct coroutine_handle; +template <> struct coroutine_handle<void> { + static coroutine_handle from_address(void *) noexcept; + coroutine_handle() = default; + template <class PromiseType> + coroutine_handle(coroutine_handle<PromiseType>) noexcept; +}; +template <class Promise> struct coroutine_handle : coroutine_handle<void> { + coroutine_handle() = default; + static coroutine_handle from_address(void *) noexcept; +}; +} + +struct suspend_always { + bool await_ready() noexcept; + void await_suspend(std::experimental::coroutine_handle<>) noexcept; + void await_resume() noexcept; +}; + +struct task { + struct promise_type { + task get_return_object() { return task(); } + suspend_always initial_suspend() { return {}; } + suspend_always final_suspend() { return {}; } + void return_void() {} + void unhandled_exception() {} + }; +}; + +struct awaitable { + task await() { (void)co_await *this; } + bool await_ready() { return false; } + bool await_suspend(std::experimental::coroutine_handle<> awaiter) { return false; } + bool await_resume() { return false; } +}; + +int main() { + awaitable a; + a.await(); +} Index: clang/lib/CodeGen/CodeGenFunction.cpp =================================================================== --- clang/lib/CodeGen/CodeGenFunction.cpp +++ clang/lib/CodeGen/CodeGenFunction.cpp @@ -732,6 +732,15 @@ SanOpts.Mask &= ~SanitizerKind::CFIUnrelatedCast; } + // Ignore null checks in coroutine functions since the coroutines passes + // are not aware of how to move the extra UBSan instructions across the split + // coroutine boundaries. + if (D && SanOpts.has(SanitizerKind::Null)) + if (const auto *FD = dyn_cast<FunctionDecl>(D)) + if (FD->getBody() && + FD->getBody()->getStmtClass() == Stmt::CoroutineBodyStmtClass) + SanOpts.Mask &= ~SanitizerKind::Null; + // Apply xray attributes to the function (as a string, for now) if (D) { if (const auto *XRayAttr = D->getAttr<XRayInstrumentAttr>()) {
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits