-
Notifications
You must be signed in to change notification settings - Fork 345
[lldb] Fix HeapCFA comparison to be symmetric #10127
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -76,11 +76,40 @@ bool lldb_private::operator!=(const StackID &lhs, const StackID &rhs) { | |
} | ||
|
||
// BEGIN SWIFT | ||
/// Given two async contexts, source and maybe_parent, chase continuation | ||
/// pointers to check if maybe_parent can be reached from source. The search | ||
/// stops when it hits the end of the chain (parent_ctx == 0) or a safety limit | ||
/// in case of an invalid continuation chain. | ||
static llvm::Expected<bool> IsReachableParent(lldb::addr_t source, | ||
lldb::addr_t maybe_parent, | ||
Process &process) { | ||
auto max_num_frames = 512; | ||
for (lldb::addr_t parent_ctx = source; parent_ctx && max_num_frames; | ||
max_num_frames--) { | ||
Status error; | ||
lldb::addr_t old_parent_ctx = parent_ctx; | ||
// The continuation's context is the first field of an async context. | ||
parent_ctx = process.ReadPointerFromMemory(old_parent_ctx, error); | ||
if (error.Fail()) | ||
return llvm::createStringError(llvm::formatv( | ||
"Failed to read parent async context of: {0:x}. Error: {1}", | ||
old_parent_ctx, error.AsCString())); | ||
if (parent_ctx == maybe_parent) | ||
return true; | ||
} | ||
if (max_num_frames == 0) | ||
return llvm::createStringError( | ||
llvm::formatv("Failed to read continuation chain from {0:x} to " | ||
"possible parent {1:x}. Reached limit of frames.", | ||
source, maybe_parent)); | ||
return false; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I can do that, though I was hoping to just move the code as this is an NFC patch There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Tried it just now, it does look much better indeed! |
||
} | ||
|
||
enum class HeapCFAComparisonResult { Younger, Older, NoOpinion }; | ||
/// If at least one of the stack IDs (lhs, rhs) is a heap CFA, perform the | ||
/// swift-specific async frame comparison. Otherwise, returns NoOpinion. | ||
static HeapCFAComparisonResult | ||
IsYoungerHeapCFAs(const StackID &lhs, const StackID &rhs, Process &process) { | ||
CompareHeapCFAs(const StackID &lhs, const StackID &rhs, Process &process) { | ||
const bool lhs_cfa_on_stack = lhs.IsCFAOnStack(process); | ||
const bool rhs_cfa_on_stack = rhs.IsCFAOnStack(process); | ||
if (lhs_cfa_on_stack && rhs_cfa_on_stack) | ||
|
@@ -103,34 +132,26 @@ IsYoungerHeapCFAs(const StackID &lhs, const StackID &rhs, Process &process) { | |
|
||
// Both CFAs are on the heap and they are distinct. | ||
// LHS is younger if and only if its continuation async context is (directly | ||
// or indirectly) RHS. Chase continuation pointers to check this case, until | ||
// we hit the end of the chain (parent_ctx == 0) or a safety limit in case of | ||
// an invalid continuation chain. | ||
auto max_num_frames = 512; | ||
for (lldb::addr_t parent_ctx = lhs_cfa; parent_ctx && max_num_frames; | ||
max_num_frames--) { | ||
Status error; | ||
lldb::addr_t old_parent_ctx = parent_ctx; | ||
// The continuation's context is the first field of an async context. | ||
parent_ctx = process.ReadPointerFromMemory(old_parent_ctx, error); | ||
if (error.Fail()) { | ||
Log *log = GetLog(LLDBLog::Unwind); | ||
LLDB_LOGF(log, "Failed to read parent async context of: 0x%8.8" PRIx64, | ||
old_parent_ctx); | ||
break; | ||
} | ||
if (parent_ctx == rhs_cfa) | ||
return HeapCFAComparisonResult::Younger; | ||
} | ||
|
||
// or indirectly) RHS. | ||
llvm::Expected<bool> lhs_younger = | ||
IsReachableParent(lhs_cfa, rhs_cfa, process); | ||
if (auto E = lhs_younger.takeError()) | ||
LLDB_LOG_ERROR(GetLog(LLDBLog::Unwind), std::move(E), "{0}"); | ||
else if (*lhs_younger) | ||
return HeapCFAComparisonResult::Younger; | ||
llvm::Expected<bool> lhs_older = IsReachableParent(rhs_cfa, lhs_cfa, process); | ||
if (auto E = lhs_older.takeError()) | ||
LLDB_LOG_ERROR(GetLog(LLDBLog::Unwind), std::move(E), "{0}"); | ||
else if (*lhs_older) | ||
return HeapCFAComparisonResult::Older; | ||
return HeapCFAComparisonResult::NoOpinion; | ||
} | ||
// END SWIFT | ||
|
||
bool StackID::IsYounger(const StackID &lhs, const StackID &rhs, | ||
Process &process) { | ||
// BEGIN SWIFT | ||
switch (IsYoungerHeapCFAs(lhs, rhs, process)) { | ||
switch (CompareHeapCFAs(lhs, rhs, process)) { | ||
case HeapCFAComparisonResult::Younger: | ||
return true; | ||
case HeapCFAComparisonResult::Older: | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
code below is just copied from the old location