[lldb] Fix evaluating expressions without JIT in an object context (#145599)

If a server does not support allocating memory in an inferior process or
when debugging a core file, evaluating an expression in the context of a
value object results in an error:

```
error: <lldb wrapper prefix>:43:1: use of undeclared identifier '$__lldb_class'
   43 | $__lldb_class::$__lldb_expr(void *$__lldb_arg)
      | ^
```

Such expressions require a live address to be stored in the value
object. However, `EntityResultVariable::Dematerialize()` only sets
`ret->m_live_sp` if JIT is available, even if the address points to the
process memory and no custom allocations were made. Similarly,
`EntityPersistentVariable::Dematerialize()` tries to deallocate memory
based on the same check, resulting in an error if the memory was not
previously allocated in `EntityPersistentVariable::Materialize()`.

As an unintended bonus, the patch also fixes a FIXME case in
`TestCxxChar8_t.py`.
This commit is contained in:
Igor Kudrin
2025-06-27 14:30:24 -07:00
committed by GitHub
parent 9f5061d4f0
commit 442f99d769
8 changed files with 105 additions and 36 deletions

View File

@@ -319,10 +319,10 @@ IRMemoryMap::Allocation::Allocation(lldb::addr_t process_alloc,
}
}
llvm::Expected<lldb::addr_t> IRMemoryMap::Malloc(size_t size, uint8_t alignment,
uint32_t permissions,
AllocationPolicy policy,
bool zero_memory) {
llvm::Expected<lldb::addr_t>
IRMemoryMap::Malloc(size_t size, uint8_t alignment, uint32_t permissions,
AllocationPolicy policy, bool zero_memory,
AllocationPolicy *used_policy) {
lldb_private::Log *log(GetLog(LLDBLog::Expressions));
lldb::ProcessSP process_sp;
@@ -454,6 +454,9 @@ llvm::Expected<lldb::addr_t> IRMemoryMap::Malloc(size_t size, uint8_t alignment,
(uint64_t)permissions, policy_string, aligned_address);
}
if (used_policy)
*used_policy = policy;
return aligned_address;
}

View File

@@ -75,11 +75,12 @@ public:
// contents.
const bool zero_memory = false;
IRMemoryMap::AllocationPolicy used_policy;
auto address_or_error = map.Malloc(
llvm::expectedToOptional(m_persistent_variable_sp->GetByteSize())
.value_or(0),
8, lldb::ePermissionsReadable | lldb::ePermissionsWritable,
IRMemoryMap::eAllocationPolicyMirror, zero_memory);
IRMemoryMap::eAllocationPolicyMirror, zero_memory, &used_policy);
if (!address_or_error) {
err = Status::FromErrorStringWithFormat(
"couldn't allocate a memory area to store %s: %s",
@@ -101,14 +102,22 @@ public:
m_persistent_variable_sp->GetName(), mem, eAddressTypeLoad,
map.GetAddressByteSize());
// Clear the flag if the variable will never be deallocated.
if (m_persistent_variable_sp->m_flags &
ExpressionVariable::EVKeepInTarget) {
Status leak_error;
map.Leak(mem, leak_error);
m_persistent_variable_sp->m_flags &=
~ExpressionVariable::EVNeedsAllocation;
if (used_policy == IRMemoryMap::eAllocationPolicyMirror) {
// Clear the flag if the variable will never be deallocated.
Status leak_error;
map.Leak(mem, leak_error);
m_persistent_variable_sp->m_flags &=
~ExpressionVariable::EVNeedsAllocation;
} else {
// If the variable cannot be kept in target, clear this flag...
m_persistent_variable_sp->m_flags &=
~ExpressionVariable::EVKeepInTarget;
// ...and set the flag to copy the value during dematerialization.
m_persistent_variable_sp->m_flags |=
ExpressionVariable::EVNeedsFreezeDry;
}
}
// Write the contents of the variable to the area.
@@ -327,22 +336,10 @@ public:
return;
}
lldb::ProcessSP process_sp =
map.GetBestExecutionContextScope()->CalculateProcess();
if (!process_sp || !process_sp->CanJIT()) {
// Allocations are not persistent so persistent variables cannot stay
// materialized.
m_persistent_variable_sp->m_flags |=
ExpressionVariable::EVNeedsAllocation;
DestroyAllocation(map, err);
if (!err.Success())
return;
} else if (m_persistent_variable_sp->m_flags &
ExpressionVariable::EVNeedsAllocation &&
!(m_persistent_variable_sp->m_flags &
ExpressionVariable::EVKeepInTarget)) {
if (m_persistent_variable_sp->m_flags &
ExpressionVariable::EVNeedsAllocation &&
!(m_persistent_variable_sp->m_flags &
ExpressionVariable::EVKeepInTarget)) {
DestroyAllocation(map, err);
if (!err.Success())
return;
@@ -1082,9 +1079,8 @@ public:
m_delegate->DidDematerialize(ret);
}
bool can_persist =
(m_is_program_reference && process_sp && process_sp->CanJIT() &&
!(address >= frame_bottom && address < frame_top));
bool can_persist = m_is_program_reference &&
!(address >= frame_bottom && address < frame_top);
if (can_persist && m_keep_in_memory) {
ret->m_live_sp = ValueObjectConstResult::Create(exe_scope, m_type, name,
@@ -1114,7 +1110,9 @@ public:
map.Free(m_temporary_allocation, free_error);
}
} else {
ret->m_flags |= ExpressionVariable::EVIsLLDBAllocated;
ret->m_flags |= m_is_program_reference
? ExpressionVariable::EVIsProgramReference
: ExpressionVariable::EVIsLLDBAllocated;
}
m_temporary_allocation = LLDB_INVALID_ADDRESS;