[Lldb-commits] [lldb] [lldb] Add pointer arithmetics for addition and subtraction to DIL (PR #184652)
Ilia Kuklin via lldb-commits
lldb-commits at lists.llvm.org
Fri Mar 13 07:10:32 PDT 2026
https://github.com/kuilpd updated https://github.com/llvm/llvm-project/pull/184652
>From 18a38c88cb35c01e215def2659ad09b0945a2517 Mon Sep 17 00:00:00 2001
From: Ilia Kuklin <ikuklin at accesssoftek.com>
Date: Wed, 4 Mar 2026 19:46:38 +0500
Subject: [PATCH 1/4] [lldb] Add pointer arithmetics for addition and
subtraction to DIL
---
lldb/include/lldb/ValueObject/DILEval.h | 4 +
lldb/source/ValueObject/DILEval.cpp | 110 +++++++++++++++--
.../Arithmetic/TestFrameVarDILArithmetic.py | 12 --
.../TestFrameVarDILExprPointerArithmetic.py | 113 ++++++++++++++++++
.../var-dil/expr/PointerArithmetic/main.cpp | 19 +++
5 files changed, 239 insertions(+), 19 deletions(-)
diff --git a/lldb/include/lldb/ValueObject/DILEval.h b/lldb/include/lldb/ValueObject/DILEval.h
index a6223c4d998ab..f4506bf626ab4 100644
--- a/lldb/include/lldb/ValueObject/DILEval.h
+++ b/lldb/include/lldb/ValueObject/DILEval.h
@@ -89,6 +89,10 @@ class Interpreter : Visitor {
llvm::Expected<CompilerType> ArithmeticConversion(lldb::ValueObjectSP &lhs,
lldb::ValueObjectSP &rhs,
uint32_t location);
+ /// Add the offset to the pointer according to the pointee type byte size.
+ /// \returns A new `ValueObject` with a new pointer value.
+ llvm::Expected<lldb::ValueObjectSP>
+ PointerAdd(lldb::ValueObjectSP ptr, int64_t offset, uint32_t location);
llvm::Expected<lldb::ValueObjectSP> EvaluateScalarOp(BinaryOpKind kind,
lldb::ValueObjectSP lhs,
lldb::ValueObjectSP rhs,
diff --git a/lldb/source/ValueObject/DILEval.cpp b/lldb/source/ValueObject/DILEval.cpp
index ec9ea8b9618fc..b0c30e3b152de 100644
--- a/lldb/source/ValueObject/DILEval.cpp
+++ b/lldb/source/ValueObject/DILEval.cpp
@@ -538,6 +538,29 @@ Interpreter::Visit(const UnaryOpNode &node) {
node.GetLocation());
}
+llvm::Expected<lldb::ValueObjectSP>
+Interpreter::PointerAdd(lldb::ValueObjectSP ptr, int64_t offset,
+ uint32_t location) {
+ if (ptr->GetCompilerType().IsPointerToVoid())
+ return llvm::make_error<DILDiagnosticError>(
+ m_expr, "arithmetic on a pointer to void", location);
+ if (ptr->GetValueAsUnsigned(0) == 0 && offset != 0)
+ return llvm::make_error<DILDiagnosticError>(
+ m_expr, "arithmetic on a nullptr is undefined", location);
+
+ llvm::Expected<uint64_t> byte_size =
+ ptr->GetCompilerType().GetPointeeType().GetByteSize(
+ m_exe_ctx_scope.get());
+ if (!byte_size)
+ return byte_size.takeError();
+ uintptr_t addr = ptr->GetValueAsUnsigned(0) + offset * (*byte_size);
+
+ ExecutionContext exe_ctx(m_target.get(), false);
+ Scalar scalar(addr);
+ return ValueObject::CreateValueObjectFromScalar(
+ m_target, scalar, ptr->GetCompilerType(), "result");
+}
+
llvm::Expected<lldb::ValueObjectSP>
Interpreter::EvaluateScalarOp(BinaryOpKind kind, lldb::ValueObjectSP lhs,
lldb::ValueObjectSP rhs, CompilerType result_type,
@@ -569,7 +592,8 @@ llvm::Expected<lldb::ValueObjectSP> Interpreter::EvaluateBinaryAddition(
lldb::ValueObjectSP lhs, lldb::ValueObjectSP rhs, uint32_t location) {
// Operation '+' works for:
// {scalar,unscoped_enum} <-> {scalar,unscoped_enum}
- // TODO: Pointer arithmetics
+ // {integer,unscoped_enum} <-> pointer
+ // pointer <-> {integer,unscoped_enum}
auto orig_lhs_type = lhs->GetCompilerType();
auto orig_rhs_type = rhs->GetCompilerType();
auto type_or_err = ArithmeticConversion(lhs, rhs, location);
@@ -580,18 +604,34 @@ llvm::Expected<lldb::ValueObjectSP> Interpreter::EvaluateBinaryAddition(
if (result_type.IsScalarType())
return EvaluateScalarOp(BinaryOpKind::Add, lhs, rhs, result_type, location);
- std::string errMsg =
- llvm::formatv("invalid operands to binary expression ('{0}' and '{1}')",
- orig_lhs_type.GetTypeName(), orig_rhs_type.GetTypeName());
- return llvm::make_error<DILDiagnosticError>(m_expr, std::move(errMsg),
- location);
+ // Check for pointer arithmetics.
+ // One of the operands must be a pointer and the other one an integer.
+ lldb::ValueObjectSP ptr, offset;
+ if (lhs->GetCompilerType().IsPointerType()) {
+ ptr = lhs;
+ offset = rhs;
+ } else if (rhs->GetCompilerType().IsPointerType()) {
+ ptr = rhs;
+ offset = lhs;
+ }
+
+ if (!ptr || !offset->GetCompilerType().IsInteger()) {
+ std::string errMsg =
+ llvm::formatv("invalid operands to binary expression ('{0}' and '{1}')",
+ orig_lhs_type.GetTypeName(), orig_rhs_type.GetTypeName());
+ return llvm::make_error<DILDiagnosticError>(m_expr, std::move(errMsg),
+ location);
+ }
+
+ return PointerAdd(ptr, offset->GetValueAsUnsigned(0), location);
}
llvm::Expected<lldb::ValueObjectSP> Interpreter::EvaluateBinarySubtraction(
lldb::ValueObjectSP lhs, lldb::ValueObjectSP rhs, uint32_t location) {
// Operation '-' works for:
// {scalar,unscoped_enum} <-> {scalar,unscoped_enum}
- // TODO: Pointer arithmetics
+ // pointer <-> {integer,unscoped_enum}
+ // pointer <-> pointer (if pointee types are compatible)
auto orig_lhs_type = lhs->GetCompilerType();
auto orig_rhs_type = rhs->GetCompilerType();
auto type_or_err = ArithmeticConversion(lhs, rhs, location);
@@ -602,6 +642,62 @@ llvm::Expected<lldb::ValueObjectSP> Interpreter::EvaluateBinarySubtraction(
if (result_type.IsScalarType())
return EvaluateScalarOp(BinaryOpKind::Sub, lhs, rhs, result_type, location);
+ auto lhs_type = lhs->GetCompilerType();
+ auto rhs_type = rhs->GetCompilerType();
+
+ // "pointer - integer" operation.
+ if (lhs_type.IsPointerType() && rhs_type.IsInteger())
+ return PointerAdd(lhs, -rhs->GetValueAsUnsigned(0), location);
+
+ // "pointer - pointer" operation.
+ if (lhs_type.IsPointerType() && rhs_type.IsPointerType()) {
+ if (lhs_type.IsPointerToVoid() && rhs_type.IsPointerToVoid()) {
+ return llvm::make_error<DILDiagnosticError>(
+ m_expr, "arithmetic on pointers to void", location);
+ }
+ // Compare canonical unqualified pointer types.
+ CompilerType lhs_unqualified_type =
+ lhs_type.GetCanonicalType().GetFullyUnqualifiedType();
+ CompilerType rhs_unqualified_type =
+ rhs_type.GetCanonicalType().GetFullyUnqualifiedType();
+ bool comparable = lhs_unqualified_type.CompareTypes(rhs_unqualified_type);
+ if (!comparable) {
+ std::string errMsg = llvm::formatv(
+ "'{0}' and '{1}' are not pointers to compatible types",
+ orig_lhs_type.GetTypeName(), orig_rhs_type.GetTypeName());
+ return llvm::make_error<DILDiagnosticError>(m_expr, errMsg, location);
+ }
+
+ llvm::Expected<uint64_t> lhs_byte_size =
+ lhs_type.GetPointeeType().GetByteSize(m_exe_ctx_scope.get());
+ if (!lhs_byte_size)
+ return lhs_byte_size.takeError();
+ // Since pointers have compatible types, both have the same pointee size.
+ int64_t item_size = *lhs_byte_size;
+ int64_t diff = static_cast<int64_t>(lhs->GetValueAsUnsigned(0) -
+ rhs->GetValueAsUnsigned(0));
+ if (diff % item_size != 0) {
+ // If address difference isn't divisible by pointee size then performing
+ // the operation is undefined behaviour.
+ return llvm::make_error<DILDiagnosticError>(
+ m_expr, "undefined pointer arithmetic", location);
+ }
+ diff /= item_size;
+
+ llvm::Expected<lldb::TypeSystemSP> type_system =
+ GetTypeSystemFromCU(m_exe_ctx_scope);
+ if (!type_system)
+ return type_system.takeError();
+ CompilerType ptrdiff_t = type_system.get()->GetPointerDiffType(true);
+ if (!ptrdiff_t)
+ return llvm::make_error<DILDiagnosticError>(
+ m_expr, "unable to determine pointer diff type", location);
+
+ Scalar scalar(diff);
+ return ValueObject::CreateValueObjectFromScalar(m_target, scalar, ptrdiff_t,
+ "result");
+ }
+
std::string errMsg =
llvm::formatv("invalid operands to binary expression ('{0}' and '{1}')",
orig_lhs_type.GetTypeName(), orig_rhs_type.GetTypeName());
diff --git a/lldb/test/API/commands/frame/var-dil/expr/Arithmetic/TestFrameVarDILArithmetic.py b/lldb/test/API/commands/frame/var-dil/expr/Arithmetic/TestFrameVarDILArithmetic.py
index 03075314ab9b6..fb3b877209d16 100644
--- a/lldb/test/API/commands/frame/var-dil/expr/Arithmetic/TestFrameVarDILArithmetic.py
+++ b/lldb/test/API/commands/frame/var-dil/expr/Arithmetic/TestFrameVarDILArithmetic.py
@@ -102,15 +102,3 @@ def test_arithmetic(self):
self.expect_var_path("my_ref - 1", value="1")
self.expect_var_path("ref + my_ref", value="4")
self.expect_var_path("ref - my_ref", value="0")
-
- # TODO: Pointer arithmetics
- self.expect(
- "frame var -- 'p + 1'",
- error=True,
- substrs=["invalid operands to binary expression ('int *' and 'int')"],
- )
- self.expect(
- "frame var -- 'p - 1'",
- error=True,
- substrs=["invalid operands to binary expression ('int *' and 'int')"],
- )
diff --git a/lldb/test/API/commands/frame/var-dil/expr/PointerArithmetic/TestFrameVarDILExprPointerArithmetic.py b/lldb/test/API/commands/frame/var-dil/expr/PointerArithmetic/TestFrameVarDILExprPointerArithmetic.py
index 448cd5b1ec7e0..b027fab1e176f 100644
--- a/lldb/test/API/commands/frame/var-dil/expr/PointerArithmetic/TestFrameVarDILExprPointerArithmetic.py
+++ b/lldb/test/API/commands/frame/var-dil/expr/PointerArithmetic/TestFrameVarDILExprPointerArithmetic.py
@@ -22,8 +22,121 @@ def test_pointer_arithmetic(self):
self.expect_var_path("+array", type="int *")
self.expect_var_path("+array_ref", type="int *")
self.expect_var_path("+p_int0", type="int *")
+
+ # Binary operations
+ self.expect_var_path("p_char1", type="const char *")
+ self.expect_var_path("p_char1 + 1", type="const char *")
+ self.expect_var_path("p_char1 + offset", type="const char *")
+
+ self.expect_var_path("my_p_char1", type="my_char_ptr")
+ self.expect_var_path("my_p_char1 + 1", type="my_char_ptr")
+ self.expect_var_path("my_p_char1 + offset", type="my_char_ptr")
+
+ self.expect_var_path("*(p_char1 + 0)", value="'h'")
+ self.expect_var_path("*(4 + p_char1)", value="'o'")
+ self.expect_var_path("*(p_char1 + offset - 1)", value="'o'")
+
+ self.expect_var_path("*p_int0", value="0")
+ self.expect_var_path("*cp_int5", value="5")
+ self.expect_var_path("*(&*(cp_int5 + 1) - 1)", value="5")
+
+ self.expect_var_path("p_int0 - p_int0", value="0", type="__ptrdiff_t")
+ self.expect_var_path("cp_int5 - p_int0", value="5", type="__ptrdiff_t")
+ self.expect_var_path("cp_int5 - td_int_ptr0", value="5", type="__ptrdiff_t")
+ self.expect_var_path("td_int_ptr0 - cp_int5", value="-5", type="__ptrdiff_t")
+
+ # Check arrays
+ self.expect_var_path("array + 1", type="int *")
+ self.expect_var_path("1 + array", type="int *")
+ self.expect_var_path("array_ref + 1", type="int *")
+ self.expect_var_path("1 + array_ref", type="int *")
+ self.expect_var_path("array - 1", type="int *")
+ self.expect_var_path("array_ref - 1", type="int *")
+ self.expect_var_path("array - array", value="0", type="__ptrdiff_t")
+ self.expect_var_path("array - array_ref", value="0", type="__ptrdiff_t")
+ self.expect_var_path("array_ref - array_ref", value="0", type="__ptrdiff_t")
+
+ # Errors
self.expect(
"frame var -- '-p_int0'",
error=True,
substrs=["invalid argument type 'int *' to unary expression"],
)
+ self.expect(
+ "frame var -- 'cp_int5 - p_char1'",
+ error=True,
+ substrs=[
+ "'const int *' and 'const char *' are not pointers to compatible types"
+ ],
+ )
+ self.expect(
+ "frame var -- 'p_int0 + cp_int5'",
+ error=True,
+ substrs=[
+ "invalid operands to binary expression ('int *' and 'const int *')"
+ ],
+ )
+ self.expect(
+ "frame var -- 'p_void + 1'",
+ error=True,
+ substrs=["arithmetic on a pointer to void"],
+ )
+ self.expect(
+ "frame var -- 'p_void - 1'",
+ error=True,
+ substrs=["arithmetic on a pointer to void"],
+ )
+ self.expect(
+ "frame var -- 'p_void - p_char1'",
+ error=True,
+ substrs=[
+ "'void *' and 'const char *' are not pointers to compatible types"
+ ],
+ )
+ self.expect(
+ "frame var -- 'p_void - p_void'",
+ error=True,
+ substrs=["arithmetic on pointers to void"],
+ )
+ self.expect(
+ "frame var -- 'pp_void0 - p_char1'",
+ error=True,
+ substrs=[
+ "'void **' and 'const char *' are not pointers to compatible types"
+ ],
+ )
+ self.expect(
+ "frame var -- 'p_int0 - 1.0'",
+ error=True,
+ substrs=["invalid operands to binary expression ('int *' and 'double')"],
+ )
+ self.expect(
+ "frame var -- '1.0f + p_int0'",
+ error=True,
+ substrs=["invalid operands to binary expression ('float' and 'int *')"],
+ )
+ self.expect(
+ "frame var -- '1 - array'",
+ error=True,
+ substrs=["invalid operands to binary expression ('int' and 'int[10]')"],
+ )
+ self.expect(
+ "frame var -- 'array + array'",
+ error=True,
+ substrs=["invalid operands to binary expression ('int[10]' and 'int[10]')"],
+ )
+ self.expect(
+ "frame var -- 'array + array'",
+ error=True,
+ substrs=["invalid operands to binary expression ('int[10]' and 'int[10]')"],
+ )
+ self.expect(
+ "frame var -- 'int_null + 1'",
+ error=True,
+ substrs=["arithmetic on a nullptr is undefined"],
+ )
+ self.expect(
+ "frame var -- 'int_null - 1'",
+ error=True,
+ substrs=["arithmetic on a nullptr is undefined"],
+ )
diff --git a/lldb/test/API/commands/frame/var-dil/expr/PointerArithmetic/main.cpp b/lldb/test/API/commands/frame/var-dil/expr/PointerArithmetic/main.cpp
index b4e0e88b1ffc9..be1f3424f62dc 100644
--- a/lldb/test/API/commands/frame/var-dil/expr/PointerArithmetic/main.cpp
+++ b/lldb/test/API/commands/frame/var-dil/expr/PointerArithmetic/main.cpp
@@ -1,11 +1,30 @@
void stop() {}
int main(int argc, char **argv) {
+ int offset = 5;
int array[10];
array[0] = 0;
+ array[offset] = offset;
int (&array_ref)[10] = array;
int *p_int0 = &array[0];
+ const char *p_char1 = "hello";
+ typedef const char *my_char_ptr;
+ my_char_ptr my_p_char1 = p_char1;
+
+ int **pp_int0 = &p_int0;
+ const int *cp_int0 = &array[0];
+ const int *cp_int5 = &array[offset];
+
+ typedef int *td_int_ptr_t;
+ td_int_ptr_t td_int_ptr0 = &array[0];
+
+ void *p_void = (void *)p_char1;
+ void **pp_void0 = &p_void;
+ void **pp_void1 = pp_void0 + 1;
+
+ int *int_null = nullptr;
+
stop(); // Set a breakpoint here
return 0;
}
>From 04ab6908a755f2956777c662341cffa3b62411bb Mon Sep 17 00:00:00 2001
From: Ilia Kuklin <ikuklin at accesssoftek.com>
Date: Fri, 13 Mar 2026 16:14:30 +0500
Subject: [PATCH 2/4] Fixes after rebase
---
lldb/source/ValueObject/DILEval.cpp | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/lldb/source/ValueObject/DILEval.cpp b/lldb/source/ValueObject/DILEval.cpp
index b0c30e3b152de..8df4cce3ea970 100644
--- a/lldb/source/ValueObject/DILEval.cpp
+++ b/lldb/source/ValueObject/DILEval.cpp
@@ -558,7 +558,7 @@ Interpreter::PointerAdd(lldb::ValueObjectSP ptr, int64_t offset,
ExecutionContext exe_ctx(m_target.get(), false);
Scalar scalar(addr);
return ValueObject::CreateValueObjectFromScalar(
- m_target, scalar, ptr->GetCompilerType(), "result");
+ m_exe_ctx_scope, scalar, ptr->GetCompilerType(), "result");
}
llvm::Expected<lldb::ValueObjectSP>
@@ -694,8 +694,8 @@ llvm::Expected<lldb::ValueObjectSP> Interpreter::EvaluateBinarySubtraction(
m_expr, "unable to determine pointer diff type", location);
Scalar scalar(diff);
- return ValueObject::CreateValueObjectFromScalar(m_target, scalar, ptrdiff_t,
- "result");
+ return ValueObject::CreateValueObjectFromScalar(m_exe_ctx_scope, scalar,
+ ptrdiff_t, "result");
}
std::string errMsg =
>From e691eaaecec04d0df3a0169be778e746a5284872 Mon Sep 17 00:00:00 2001
From: Ilia Kuklin <ikuklin at accesssoftek.com>
Date: Fri, 13 Mar 2026 16:27:28 +0500
Subject: [PATCH 3/4] Fix adding/subtracting pointer with a negative value
---
lldb/include/lldb/ValueObject/DILEval.h | 9 ++--
lldb/source/ValueObject/DILEval.cpp | 21 +++++++---
.../TestFrameVarDILExprPointerArithmetic.py | 42 +++++++++++++------
.../var-dil/expr/PointerArithmetic/main.cpp | 7 ++--
4 files changed, 56 insertions(+), 23 deletions(-)
diff --git a/lldb/include/lldb/ValueObject/DILEval.h b/lldb/include/lldb/ValueObject/DILEval.h
index f4506bf626ab4..4140c011f1580 100644
--- a/lldb/include/lldb/ValueObject/DILEval.h
+++ b/lldb/include/lldb/ValueObject/DILEval.h
@@ -89,10 +89,13 @@ class Interpreter : Visitor {
llvm::Expected<CompilerType> ArithmeticConversion(lldb::ValueObjectSP &lhs,
lldb::ValueObjectSP &rhs,
uint32_t location);
- /// Add the offset to the pointer according to the pointee type byte size.
+ /// Add or subtract the offset to the pointer according to the pointee type
+ /// byte size.
/// \returns A new `ValueObject` with a new pointer value.
- llvm::Expected<lldb::ValueObjectSP>
- PointerAdd(lldb::ValueObjectSP ptr, int64_t offset, uint32_t location);
+ llvm::Expected<lldb::ValueObjectSP> PointerOffset(lldb::ValueObjectSP ptr,
+ lldb::ValueObjectSP offset,
+ bool positive,
+ uint32_t location);
llvm::Expected<lldb::ValueObjectSP> EvaluateScalarOp(BinaryOpKind kind,
lldb::ValueObjectSP lhs,
lldb::ValueObjectSP rhs,
diff --git a/lldb/source/ValueObject/DILEval.cpp b/lldb/source/ValueObject/DILEval.cpp
index 8df4cce3ea970..cc402f1863e2a 100644
--- a/lldb/source/ValueObject/DILEval.cpp
+++ b/lldb/source/ValueObject/DILEval.cpp
@@ -539,8 +539,8 @@ Interpreter::Visit(const UnaryOpNode &node) {
}
llvm::Expected<lldb::ValueObjectSP>
-Interpreter::PointerAdd(lldb::ValueObjectSP ptr, int64_t offset,
- uint32_t location) {
+Interpreter::PointerOffset(lldb::ValueObjectSP ptr, lldb::ValueObjectSP offset,
+ bool positive, uint32_t location) {
if (ptr->GetCompilerType().IsPointerToVoid())
return llvm::make_error<DILDiagnosticError>(
m_expr, "arithmetic on a pointer to void", location);
@@ -548,12 +548,23 @@ Interpreter::PointerAdd(lldb::ValueObjectSP ptr, int64_t offset,
return llvm::make_error<DILDiagnosticError>(
m_expr, "arithmetic on a nullptr is undefined", location);
+ bool success;
+ int64_t offset_int = offset->GetValueAsSigned(0, &success);
+ if (!success) {
+ std::string errMsg = llvm::formatv("could not get the offset: {0}",
+ offset->GetError().AsCString());
+ return llvm::make_error<DILDiagnosticError>(m_expr, std::move(errMsg),
+ location);
+ }
+
llvm::Expected<uint64_t> byte_size =
ptr->GetCompilerType().GetPointeeType().GetByteSize(
m_exe_ctx_scope.get());
if (!byte_size)
return byte_size.takeError();
- uintptr_t addr = ptr->GetValueAsUnsigned(0) + offset * (*byte_size);
+ if (!positive)
+ offset_int = -offset_int;
+ uintptr_t addr = ptr->GetValueAsUnsigned(0) + offset_int * (*byte_size);
ExecutionContext exe_ctx(m_target.get(), false);
Scalar scalar(addr);
@@ -623,7 +634,7 @@ llvm::Expected<lldb::ValueObjectSP> Interpreter::EvaluateBinaryAddition(
location);
}
- return PointerAdd(ptr, offset->GetValueAsUnsigned(0), location);
+ return PointerOffset(ptr, offset, true, location);
}
llvm::Expected<lldb::ValueObjectSP> Interpreter::EvaluateBinarySubtraction(
@@ -647,7 +658,7 @@ llvm::Expected<lldb::ValueObjectSP> Interpreter::EvaluateBinarySubtraction(
// "pointer - integer" operation.
if (lhs_type.IsPointerType() && rhs_type.IsInteger())
- return PointerAdd(lhs, -rhs->GetValueAsUnsigned(0), location);
+ return PointerOffset(lhs, rhs, false, location);
// "pointer - pointer" operation.
if (lhs_type.IsPointerType() && rhs_type.IsPointerType()) {
diff --git a/lldb/test/API/commands/frame/var-dil/expr/PointerArithmetic/TestFrameVarDILExprPointerArithmetic.py b/lldb/test/API/commands/frame/var-dil/expr/PointerArithmetic/TestFrameVarDILExprPointerArithmetic.py
index b027fab1e176f..5da79a29bad01 100644
--- a/lldb/test/API/commands/frame/var-dil/expr/PointerArithmetic/TestFrameVarDILExprPointerArithmetic.py
+++ b/lldb/test/API/commands/frame/var-dil/expr/PointerArithmetic/TestFrameVarDILExprPointerArithmetic.py
@@ -24,17 +24,25 @@ def test_pointer_arithmetic(self):
self.expect_var_path("+p_int0", type="int *")
# Binary operations
- self.expect_var_path("p_char1", type="const char *")
- self.expect_var_path("p_char1 + 1", type="const char *")
- self.expect_var_path("p_char1 + offset", type="const char *")
+ self.expect_var_path("p_char", type="const char *")
+ self.expect_var_path("p_char + 1", type="const char *")
+ self.expect_var_path("p_char + offset", type="const char *")
+ self.expect_var_path("p_char5 + -1", type="const char *")
+ self.expect_var_path("p_char5 - 1", type="const char *")
+ self.expect_var_path("p_char5 - offset", type="const char *")
- self.expect_var_path("my_p_char1", type="my_char_ptr")
- self.expect_var_path("my_p_char1 + 1", type="my_char_ptr")
- self.expect_var_path("my_p_char1 + offset", type="my_char_ptr")
+ self.expect_var_path("my_p_char", type="my_char_ptr")
+ self.expect_var_path("my_p_char + 1", type="my_char_ptr")
+ self.expect_var_path("my_p_char - 1", type="my_char_ptr")
- self.expect_var_path("*(p_char1 + 0)", value="'h'")
- self.expect_var_path("*(4 + p_char1)", value="'o'")
- self.expect_var_path("*(p_char1 + offset - 1)", value="'o'")
+ self.expect_var_path("*(p_char + 0)", value="'h'")
+ self.expect_var_path("*(5 + p_char)", value="'!'")
+ self.expect_var_path("*(p_char5 + -5)", value="'h'")
+ self.expect_var_path("*(p_char5 - 5)", value="'h'")
+ self.expect_var_path("*(p_char - -5)", value="'!'")
+ self.expect_var_path("*(p_char5 - offset + 5)", value="'!'")
+ self.expect_var_path("*((p_char + offset) - 5)", value="'h'")
+ self.expect_var_path("*(p_char + (offset - 5))", value="'h'")
self.expect_var_path("*p_int0", value="0")
self.expect_var_path("*cp_int5", value="5")
@@ -63,7 +71,7 @@ def test_pointer_arithmetic(self):
substrs=["invalid argument type 'int *' to unary expression"],
)
self.expect(
- "frame var -- 'cp_int5 - p_char1'",
+ "frame var -- 'cp_int5 - p_char'",
error=True,
substrs=[
"'const int *' and 'const char *' are not pointers to compatible types"
@@ -87,7 +95,7 @@ def test_pointer_arithmetic(self):
substrs=["arithmetic on a pointer to void"],
)
self.expect(
- "frame var -- 'p_void - p_char1'",
+ "frame var -- 'p_void - p_char'",
error=True,
substrs=[
"'void *' and 'const char *' are not pointers to compatible types"
@@ -99,7 +107,7 @@ def test_pointer_arithmetic(self):
substrs=["arithmetic on pointers to void"],
)
self.expect(
- "frame var -- 'pp_void0 - p_char1'",
+ "frame var -- 'pp_void0 - p_char'",
error=True,
substrs=[
"'void **' and 'const char *' are not pointers to compatible types"
@@ -140,3 +148,13 @@ def test_pointer_arithmetic(self):
error=True,
substrs=["arithmetic on a nullptr is undefined"],
)
+ self.expect(
+ "frame var -- 'p_char + *((int*) 0)'",
+ error=True,
+ substrs=["could not get the offset: parent is NULL"],
+ )
+ self.expect(
+ "frame var -- 'p_char - *((int*) 0)'",
+ error=True,
+ substrs=["could not get the offset: parent is NULL"],
+ )
diff --git a/lldb/test/API/commands/frame/var-dil/expr/PointerArithmetic/main.cpp b/lldb/test/API/commands/frame/var-dil/expr/PointerArithmetic/main.cpp
index be1f3424f62dc..02754e846f754 100644
--- a/lldb/test/API/commands/frame/var-dil/expr/PointerArithmetic/main.cpp
+++ b/lldb/test/API/commands/frame/var-dil/expr/PointerArithmetic/main.cpp
@@ -8,9 +8,10 @@ int main(int argc, char **argv) {
int (&array_ref)[10] = array;
int *p_int0 = &array[0];
- const char *p_char1 = "hello";
+ const char *p_char = "hello!";
+ const char *p_char5 = p_char + 5;
typedef const char *my_char_ptr;
- my_char_ptr my_p_char1 = p_char1;
+ my_char_ptr my_p_char = p_char;
int **pp_int0 = &p_int0;
const int *cp_int0 = &array[0];
@@ -19,7 +20,7 @@ int main(int argc, char **argv) {
typedef int *td_int_ptr_t;
td_int_ptr_t td_int_ptr0 = &array[0];
- void *p_void = (void *)p_char1;
+ void *p_void = (void *)p_char;
void **pp_void0 = &p_void;
void **pp_void1 = pp_void0 + 1;
>From 89114be1cfb255d12009ada2c6e007a03e493508 Mon Sep 17 00:00:00 2001
From: Ilia Kuklin <ikuklin at accesssoftek.com>
Date: Fri, 13 Mar 2026 18:07:50 +0500
Subject: [PATCH 4/4] Reduce comparing code, add assert, rename ptrdiff_t
---
lldb/source/ValueObject/DILEval.cpp | 16 +++++++---------
1 file changed, 7 insertions(+), 9 deletions(-)
diff --git a/lldb/source/ValueObject/DILEval.cpp b/lldb/source/ValueObject/DILEval.cpp
index cc402f1863e2a..447e4f637e84d 100644
--- a/lldb/source/ValueObject/DILEval.cpp
+++ b/lldb/source/ValueObject/DILEval.cpp
@@ -667,12 +667,9 @@ llvm::Expected<lldb::ValueObjectSP> Interpreter::EvaluateBinarySubtraction(
m_expr, "arithmetic on pointers to void", location);
}
// Compare canonical unqualified pointer types.
- CompilerType lhs_unqualified_type =
- lhs_type.GetCanonicalType().GetFullyUnqualifiedType();
- CompilerType rhs_unqualified_type =
- rhs_type.GetCanonicalType().GetFullyUnqualifiedType();
- bool comparable = lhs_unqualified_type.CompareTypes(rhs_unqualified_type);
- if (!comparable) {
+ CompilerType lhs_unqualified_type = lhs_type.GetCanonicalType();
+ CompilerType rhs_unqualified_type = rhs_type.GetCanonicalType();
+ if (!lhs_unqualified_type.CompareTypes(rhs_unqualified_type)) {
std::string errMsg = llvm::formatv(
"'{0}' and '{1}' are not pointers to compatible types",
orig_lhs_type.GetTypeName(), orig_rhs_type.GetTypeName());
@@ -687,6 +684,7 @@ llvm::Expected<lldb::ValueObjectSP> Interpreter::EvaluateBinarySubtraction(
int64_t item_size = *lhs_byte_size;
int64_t diff = static_cast<int64_t>(lhs->GetValueAsUnsigned(0) -
rhs->GetValueAsUnsigned(0));
+ assert(item_size > 0 && "Pointer size cannot be 0");
if (diff % item_size != 0) {
// If address difference isn't divisible by pointee size then performing
// the operation is undefined behaviour.
@@ -699,14 +697,14 @@ llvm::Expected<lldb::ValueObjectSP> Interpreter::EvaluateBinarySubtraction(
GetTypeSystemFromCU(m_exe_ctx_scope);
if (!type_system)
return type_system.takeError();
- CompilerType ptrdiff_t = type_system.get()->GetPointerDiffType(true);
- if (!ptrdiff_t)
+ CompilerType ptrdiff_type = type_system.get()->GetPointerDiffType(true);
+ if (!ptrdiff_type)
return llvm::make_error<DILDiagnosticError>(
m_expr, "unable to determine pointer diff type", location);
Scalar scalar(diff);
return ValueObject::CreateValueObjectFromScalar(m_exe_ctx_scope, scalar,
- ptrdiff_t, "result");
+ ptrdiff_type, "result");
}
std::string errMsg =
More information about the lldb-commits
mailing list