Call instructions with musttail tag must be optimized as a tailcall, otherwise could lead to incorrect program behavior.
When TSAN is instrumenting functions, it broke the contract by adding a call to the tsan exit function inbetween the musttail call and return instruction, and also inserted exception handling code.
This happend throguh EscapeEnumerator, which adds exception handling code and returns ret instructions as the place to insert instrumentation calls.
This becomes especially problematic for coroutines, because coroutines rely on tail calls to do symmetric transfers properly.
To fix this, this patch moves the location to insert instrumentation calls prior to the musttail call for ret instructions that are following musttail calls, and also does not handle exception for musttail calls.
Details
Diff Detail
- Repository
- rG LLVM Github Monorepo
Unit Tests
Event Timeline
llvm/lib/Transforms/Utils/EscapeEnumerator.cpp | ||
---|---|---|
111 | Does TSAN rely on exit cleanup instrumentation for correctness? How does it work for existing Invoke? This patch would be fine if missing some exit instrumentation is ok in general.. |
llvm/lib/Transforms/Utils/EscapeEnumerator.cpp | ||
---|---|---|
111 | The change would just make the call to tsan exit function happen earlier, before the tail call. So we are not missing any exit instrumentation after this change. |
llvm/lib/Transforms/Utils/EscapeEnumerator.cpp | ||
---|---|---|
111 |
That's the part from AdjustMustTailCall. IIUC, the other part on line 82 would skip changing throwing tail call to invoke, which would also skip the clean up in landing pad. That's what I was referring to, |
llvm/lib/Transforms/Utils/EscapeEnumerator.cpp | ||
---|---|---|
111 | Ah I see. So the reason EscapeEnumerator tries to turn calls into invoke with an exception return path is so that when exceptions are thrown, it still has a chance to call the tsan exit function before propagating the exception back. |
llvm/lib/Transforms/Utils/EscapeEnumerator.cpp | ||
---|---|---|
111 | Ok, yeah. Tailcall is different in that it's always going to be the block terminator, so guaranteed to be covered by the loop over blocks, unlike regular calls. So we're not missing out exit cleanup here. (I'm still curious how pre-existing invoke is handled, because we don't add cleanup to existing landing pad. But that is not directly related to this patch) I think there's a still slight difference though for the order of cleanup. Now between cleanup for the caller of tail call and the actual return from the caller, there's the entire tail callee. I would think that is ok, but it really depends on the contract of TSAN, so would be nice if someone familiar with TSAN can confirm. Otherwise LGTM, accept to unblock. |
Does TSAN rely on exit cleanup instrumentation for correctness? How does it work for existing Invoke?
This patch would be fine if missing some exit instrumentation is ok in general..