This is an archive of the discontinued LLVM Phabricator instance.

[CodeGenPrepare] Avoid out-of-bounds shift
ClosedPublic

Authored by bjope on Jan 31 2022, 5:37 AM.

Details

Summary

AddressingModeMatcher::matchOperationAddr may attempt to shift a
variable by the same amount of steps as found in the IR in a SHL
instruction. This was done without considering that there could be
undefined behavior in the IR, so the shift performed when compiling
could end up having undefined behavior as well.

This patch avoid UB in the codegenprepare by making sure that we
limit the shift amount used, in a similar way as already being done
in CodeGenPrepare::optimizeLoadExt.

Diff Detail

Event Timeline

bjope created this revision.Jan 31 2022, 5:37 AM
bjope requested review of this revision.Jan 31 2022, 5:37 AM
Herald added a project: Restricted Project. · View Herald TranscriptJan 31 2022, 5:37 AM
bjope added a reviewer: spatel.Feb 2 2022, 9:51 AM
bjope updated this revision to Diff 405592.Feb 3 2022, 5:27 AM

Fix typo (there was an extra "Scale =" that wasn't supposed to be there).

spatel added a comment.Feb 3 2022, 8:02 AM

This seems fine, but check my understanding: there's no difference in the test output with this fix if opt is not built with ubsan enabled?

Could/should we just exit if we detect malformed IR?

diff --git a/llvm/lib/CodeGen/CodeGenPrepare.cpp b/llvm/lib/CodeGen/CodeGenPrepare.cpp
index c888adeafca5..294a37689013 100644
--- a/llvm/lib/CodeGen/CodeGenPrepare.cpp
+++ b/llvm/lib/CodeGen/CodeGenPrepare.cpp
@@ -4551,9 +4551,12 @@ bool AddressingModeMatcher::matchOperationAddr(User *AddrInst, unsigned Opcode,
     if (!RHS || RHS->getBitWidth() > 64)
       return false;
     int64_t Scale = RHS->getSExtValue();
-    if (Opcode == Instruction::Shl)
+    if (Opcode == Instruction::Shl) {
+      // Bail out if the IR is not well-defined (overshift is poison).
+      if (RHS->getZExtValue() > 63)
+        return false;
       Scale = 1LL << Scale;
-
+    }
     return matchScaledValue(AddrInst->getOperand(0), Scale, Depth);
   }
   case Instruction::GetElementPtr: {
bjope added a comment.Feb 3 2022, 8:12 AM

This seems fine, but check my understanding: there's no difference in the test output with this fix if opt is not built with ubsan enabled?

Yes. Unfortunately the test case (as-is) doen't show any difference. I'm not sure exactly how to modify the test case to achive that.

Could/should we just exit if we detect malformed IR?

Yes, that is another option. I kind of copied how this was dealt with on line 6491 (another place where CGP is analyzing Shl), but bailing out when finding an OOB shift amount seems safe here. Is that preferred?

spatel accepted this revision.Feb 3 2022, 8:46 AM

Yes, that is another option. I kind of copied how this was dealt with on line 6491 (another place where CGP is analyzing Shl), but bailing out when finding an OOB shift amount seems safe here. Is that preferred?

I don't think it makes a difference either way. Since there's precedence for this code pattern, LGTM.

This revision is now accepted and ready to land.Feb 3 2022, 8:46 AM
This revision was landed with ongoing or failed builds.Feb 3 2022, 12:14 PM
This revision was automatically updated to reflect the committed changes.