werat created this revision.
werat requested review of this revision.
Herald added a project: LLDB.
Herald added a subscriber: lldb-commits.

Operands to `getelementptr` can be constants or constant expressions. Check
that all operands can be constant-resolved and resolve them during the
evaluation. If some operands can't be resolved as constants -- the expression
evaluation will fallback to JIT.

Fixes: https://bugs.llvm.org/show_bug.cgi?id=52449


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D113498

Files:
  lldb/source/Expression/IRInterpreter.cpp
  lldb/test/API/lang/cpp/static_members/TestCPPStaticMembers.py
  lldb/test/API/lang/cpp/static_members/main.cpp

Index: lldb/test/API/lang/cpp/static_members/main.cpp
===================================================================
--- lldb/test/API/lang/cpp/static_members/main.cpp
+++ lldb/test/API/lang/cpp/static_members/main.cpp
@@ -11,6 +11,14 @@
 long A::s_b = 2;
 int A::s_c = 3;
 
+// class Foo
+// {
+// public:
+//     static int Bar;
+// };
+
+// int Foo::Bar = 10;
+
 int main() {
   A my_a;
   my_a.m_a = 1;
Index: lldb/test/API/lang/cpp/static_members/TestCPPStaticMembers.py
===================================================================
--- lldb/test/API/lang/cpp/static_members/TestCPPStaticMembers.py
+++ lldb/test/API/lang/cpp/static_members/TestCPPStaticMembers.py
@@ -41,3 +41,31 @@
         self.createTestTarget()
         self.expect("expression s_c", error=True,
                     startstr="error: use of undeclared identifier 's_d'")
+
+    def test_no_crash_in_IR_arithmetic(self):
+        """
+        Test that LLDB doesn't crash on evaluating specific expression involving
+        pointer arithmetic and taking the address of a static class member.
+        See https://bugs.llvm.org/show_bug.cgi?id=52449
+        """
+        self.build()
+        lldbutil.run_to_source_breakpoint(self, "// stop in main", lldb.SBFileSpec("main.cpp"))
+
+        # This expression contains the following IR code:
+        # ... i64 ptrtoint (i32* @_ZN1A3s_cE to i64)) ...
+        expr = "(int*)100 + (long long)(&A::s_c)"
+
+        # The IR interpreter doesn't support non-const operands to the
+        # `GetElementPtr` IR instruction, so verify that it correctly fails to
+        # evaluate expression.
+        opts = lldb.SBExpressionOptions()
+        opts.SetAllowJIT(False)
+        value = self.target().EvaluateExpression(expr, opts)
+        self.assertTrue(value.GetError().Fail())
+        self.assertIn(
+            "Can't evaluate the expression without a running target",
+            value.GetError().GetCString())
+
+        # Evaluating the expression via JIT should work fine.
+        value = self.target().EvaluateExpression(expr)
+        self.assertTrue(value.GetError().Success())
Index: lldb/source/Expression/IRInterpreter.cpp
===================================================================
--- lldb/source/Expression/IRInterpreter.cpp
+++ lldb/source/Expression/IRInterpreter.cpp
@@ -283,11 +283,30 @@
             return true; // no offset to apply!
 
           SmallVector<Value *, 8> indices(op_cursor, op_end);
+          SmallVector<Value *, 8> const_indices;
+
+          for (Value *idx : indices) {
+            Constant *constant_idx = dyn_cast<Constant>(idx);
+            if (!constant_idx)
+              return false;
+
+            ConstantInt *constant_int = dyn_cast<ConstantInt>(constant_idx);
+            if (!constant_int) {
+              APInt v;
+              if (!ResolveConstantValue(v, constant_idx))
+                return false;
+
+              constant_int =
+                  cast<ConstantInt>(ConstantInt::get(idx->getType(), v));
+            }
+
+            const_indices.push_back(constant_int);
+          }
 
           Type *src_elem_ty =
               cast<GEPOperator>(constant_expr)->getSourceElementType();
           uint64_t offset =
-              m_target_data.getIndexedOffsetInType(src_elem_ty, indices);
+              m_target_data.getIndexedOffsetInType(src_elem_ty, const_indices);
 
           const bool is_signed = true;
           value += APInt(value.getBitWidth(), offset, is_signed);
@@ -465,12 +484,18 @@
       case Instruction::BitCast:
         return CanResolveConstant(constant_expr->getOperand(0));
       case Instruction::GetElementPtr: {
-        ConstantExpr::const_op_iterator op_cursor = constant_expr->op_begin();
-        Constant *base = dyn_cast<Constant>(*op_cursor);
-        if (!base)
-          return false;
-
-        return CanResolveConstant(base);
+        // Check that all operands of `getelementptr` can be constant-resolved.
+        SmallVector<Value *, 8> operands(constant_expr->op_begin(),
+                                         constant_expr->op_end());
+        for (Value *op : operands) {
+          Constant *constant_op = dyn_cast<Constant>(op);
+          if (!constant_op)
+            return false;
+          if (!CanResolveConstant(constant_op)) {
+            return false;
+          }
+        }
+        return true;
       }
       }
     } else {
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to