This is an archive of the discontinued LLVM Phabricator instance.

Fix MSan false positive due to select folding.
ClosedPublic

Authored by eugenis on Mar 17 2020, 3:40 PM.

Details

Summary

Select folding in JumpThreading can create a conditional branch on a
code patch that did not have one in the original program. This is not a
valid transformation in sanitize_memory functions.

Note that JumpThreading does select folding in 3 different places. Two
of them seem safe - they apply to a select instruction in a BB that ends
with an unconditional branch to another BB, which (in turn) ends with a
conditional branch or a switch with the same condition.

Fixes PR45220.

Diff Detail

Event Timeline

eugenis created this revision.Mar 17 2020, 3:40 PM
Herald added a project: Restricted Project. · View Herald TranscriptMar 17 2020, 3:40 PM
Herald added a subscriber: hiraditya. · View Herald Transcript

For the reference, this revision added the LangRef blurb about msan and conditional branches:
https://reviews.llvm.org/D67244

I'm not sure this transform is actually safe even outside of msan workflows.

I'm not sure this transform is actually safe even outside of msan workflows.

According to Alive2 (cc @regehr @aqjune ), it's not:
http://volta.cs.utah.edu:8080/z/53knD3
(Hopefully, I reduced the test posted here correctly.)

In this example, giving -disable-undef-input (which assumes the input is never undef) shows a clearer output: http://volta.cs.utah.edu:8080/z/N5eP_-
If %b is false, the source program does not have UB where as the optimized program has conditional branch on %x which can introduce UB.

Interesting. Poison semantics are very similar to MemorySanitizer model.
Should I remove TryToUnfoldSelectInCurrBB completely? I don't see how it can be saved.
Am I right about the other two instances of select folding in this pass being safe? They insert new conditional branches only on code paths that already had a branch with the same condition.

In this example, giving -disable-undef-input (which assumes the input is never undef) shows a clearer output: http://volta.cs.utah.edu:8080/z/N5eP_-
If %b is false, the source program does not have UB where as the optimized program has conditional branch on %x which can introduce UB.

I'm catching back up on my poison reading. :)
In the original program with select: if %b is false, then %v becomes poison. Then the select condition is poisoned, so the result must be poison, right? Is there some reason that we didn't make the select semantics for poison explicit in the LangRef?
https://bugs.llvm.org/show_bug.cgi?id=20895
https://lists.llvm.org/pipermail/llvm-dev/2014-September/076634.html

Interesting. Poison semantics are very similar to MemorySanitizer model.
Should I remove TryToUnfoldSelectInCurrBB completely? I don't see how it can be saved.

I'm looking at a similar question with D76153. Without 'freeze', I suspect we're going to hit perf regressions. But AFAIK, nobody has measured those.

Is there some reason that we didn't make the select semantics for poison explicit in the LangRef?

The exact semantics were evolving for a while, and nobody actually wrote up where we landed with Alive2.

Should I remove TryToUnfoldSelectInCurrBB completely? I don't see how it can be saved.

See the documentation comment on TryToUnfoldSelectInCurrBB. The ultimate transform we're actually hoping to perform, which is jump threading to simplify the select, is legal. So it's probably worth trying to do that, still, even if the intermediate step TryToUnfoldSelectInCurrBB actually implements isn't legal.

We already have some other code that tries to handle selects; I'm not sure how much of an optimization gap would remain if we just delete TryToUnfoldSelectInCurrBB.

Is there some reason that we didn't make the select semantics for poison explicit in the LangRef?

The exact semantics were evolving for a while, and nobody actually wrote up where we landed with Alive2.

Thanks - I pushed the text from the bug report here:
rGfaba1d034a04
If we need to amend/extend that in some way, let me know.

Should I remove TryToUnfoldSelectInCurrBB completely? I don't see how it can be saved.

See the documentation comment on TryToUnfoldSelectInCurrBB. The ultimate transform we're actually hoping to perform, which is jump threading to simplify the select, is legal. So it's probably worth trying to do that, still, even if the intermediate step TryToUnfoldSelectInCurrBB actually implements isn't legal.

We already have some other code that tries to handle selects; I'm not sure how much of an optimization gap would remain if we just delete TryToUnfoldSelectInCurrBB.

I added the reduced example from this report as a regression test, so we can adjust this patch to just delete the whole function without having to add an MSan-specific test:
rG22c66c1a28c0

(can use 'utils/update_test_checks.py --function=TryToUnfoldSelectInCurrBB' to auto-gen the new CHECK lines for that test only)

Going back to this change... It does not look like I'll have the cycles any time soon to reimplement TryToUnfoldSelectInCurrBB properly. Sorry about that.
WDYT about landing this change as-is to fix the immediate issue with MemorySanitizer?

Sure, we can land this in the meantime. But please update the code comment to note the result of this discussion.

eugenis updated this revision to Diff 253719.Mar 30 2020, 3:22 PM

updated the comment

This revision is now accepted and ready to land.Mar 30 2020, 4:06 PM
This revision was automatically updated to reflect the committed changes.