[lldb] Avoid returning a stale AddressOf (#212915)
The 'ValueObject::AddressOf()' method assumes that the address of a value object cannot change, so when it is calculated once, it does not need to be updated afterwards. However, this is not the case if the 'ValueObject' is a dependent object obtained by calling 'Dereference()' of another 'ValueObject'. If the latter object is changed, the dependent value object should return a new address from the 'AddressOf()' method to reflect the change.
This commit is contained in:
parent
e423bace20
commit
320164daab
4 changed files with 103 additions and 3 deletions
|
|
@ -2913,9 +2913,6 @@ ValueObjectSP ValueObject::Dereference(Status &error) {
|
|||
}
|
||||
|
||||
ValueObjectSP ValueObject::AddressOf(Status &error) {
|
||||
if (m_addr_of_valobj_sp)
|
||||
return m_addr_of_valobj_sp;
|
||||
|
||||
auto [addr, address_type] = GetAddressOf(/*scalar_is_load_address=*/false);
|
||||
error.Clear();
|
||||
if (addr != LLDB_INVALID_ADDRESS && address_type != eAddressTypeHost) {
|
||||
|
|
@ -2929,6 +2926,10 @@ ValueObjectSP ValueObject::AddressOf(Status &error) {
|
|||
|
||||
case eAddressTypeFile:
|
||||
case eAddressTypeLoad: {
|
||||
if (m_addr_of_valobj_sp &&
|
||||
m_addr_of_valobj_sp->GetValueAsUnsigned(LLDB_INVALID_ADDRESS) == addr)
|
||||
return m_addr_of_valobj_sp;
|
||||
m_addr_of_valobj_sp.reset();
|
||||
CompilerType compiler_type = GetCompilerType();
|
||||
if (compiler_type) {
|
||||
std::string name(1, '&');
|
||||
|
|
|
|||
3
lldb/test/API/python_api/value/change_ptr/Makefile
Normal file
3
lldb/test/API/python_api/value/change_ptr/Makefile
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
C_SOURCES := main.c
|
||||
|
||||
include Makefile.rules
|
||||
65
lldb/test/API/python_api/value/change_ptr/TestChangePtr.py
Normal file
65
lldb/test/API/python_api/value/change_ptr/TestChangePtr.py
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
import lldb
|
||||
from lldbsuite.test.decorators import *
|
||||
from lldbsuite.test.lldbtest import *
|
||||
from lldbsuite.test import lldbutil
|
||||
|
||||
|
||||
class ChangePtrTest(TestBase):
|
||||
def test(self):
|
||||
self.build()
|
||||
|
||||
src_file = lldb.SBFileSpec("main.c")
|
||||
_, process, thread, _ = lldbutil.run_to_source_breakpoint(
|
||||
self, "// break here 1", src_file
|
||||
)
|
||||
|
||||
## Test 1: The AddressOf of a dereferenced value should change when
|
||||
## the pointer value is updated.
|
||||
|
||||
frame = thread.GetFrameAtIndex(0)
|
||||
p = frame.FindVariable("p")
|
||||
deref = p.Dereference()
|
||||
self.assertEqual(deref.GetValueAsUnsigned(), 5)
|
||||
self.assertEqual(deref.AddressOf().GetValueAsUnsigned(), p.GetValueAsUnsigned())
|
||||
thread.StepOver()
|
||||
self.assertEqual(deref.GetValueAsUnsigned(), 7)
|
||||
self.assertEqual(deref.AddressOf().GetValueAsUnsigned(), p.GetValueAsUnsigned())
|
||||
|
||||
## Test 2: The AddressOf of a child value of a dereferenced value should
|
||||
## change when the base pointer updates.
|
||||
|
||||
lldbutil.continue_to_source_breakpoint(
|
||||
self, process, "// break here 2", src_file
|
||||
)
|
||||
frame = thread.GetFrameAtIndex(0)
|
||||
p = frame.FindVariable("p")
|
||||
deref_child = p.Dereference().GetChildMemberWithName("b")
|
||||
self.assertEqual(deref_child.GetValue(), "'b'")
|
||||
self.assertEqual(
|
||||
deref_child.AddressOf().GetValueAsUnsigned(), p.GetValueAsUnsigned() + 1
|
||||
)
|
||||
thread.StepOver()
|
||||
self.assertEqual(deref_child.GetValue(), "'d'")
|
||||
self.assertEqual(
|
||||
deref_child.AddressOf().GetValueAsUnsigned(), p.GetValueAsUnsigned() + 1
|
||||
)
|
||||
|
||||
## Test 3: Verify AddressOf updates correctly with persistent expression results.
|
||||
lldbutil.continue_to_source_breakpoint(
|
||||
self, process, "// break here 3", src_file
|
||||
)
|
||||
frame = thread.GetFrameAtIndex(0)
|
||||
frame.EvaluateExpression("int *$ptr = &a")
|
||||
ptr = frame.FindValue("$ptr", lldb.eValueTypeConstResult)
|
||||
deref = ptr.Dereference()
|
||||
self.assertEqual(deref.GetValueAsUnsigned(), 5)
|
||||
self.assertEqual(
|
||||
deref.AddressOf().GetValueAsUnsigned(),
|
||||
frame.FindVariable("a").AddressOf().GetValueAsUnsigned(),
|
||||
)
|
||||
frame.EvaluateExpression("$ptr = &b")
|
||||
self.assertEqual(deref.GetValueAsUnsigned(), 7)
|
||||
self.assertEqual(
|
||||
deref.AddressOf().GetValueAsUnsigned(),
|
||||
frame.FindVariable("b").AddressOf().GetValueAsUnsigned(),
|
||||
)
|
||||
31
lldb/test/API/python_api/value/change_ptr/main.c
Normal file
31
lldb/test/API/python_api/value/change_ptr/main.c
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
int test1() {
|
||||
int a = 5;
|
||||
int b = 7;
|
||||
int *p = &a;
|
||||
p = &b; // break here 1
|
||||
return *p;
|
||||
}
|
||||
|
||||
char test2() {
|
||||
struct S {
|
||||
char a;
|
||||
char b;
|
||||
};
|
||||
struct S arr[2] = {{'a', 'b'}, {'c', 'd'}};
|
||||
struct S *p = arr;
|
||||
++p; // break here 2
|
||||
return p->b;
|
||||
}
|
||||
|
||||
int test3() {
|
||||
int a = 5;
|
||||
int b = 7;
|
||||
return a + b; // break here 3
|
||||
}
|
||||
|
||||
int main() {
|
||||
test1();
|
||||
test2();
|
||||
test3();
|
||||
return 0;
|
||||
}
|
||||
Loading…
Reference in a new issue