Skip to content

Commit 6f8291b

Browse files
committed
FIx 1
1 parent 09b458b commit 6f8291b

File tree

1 file changed

+30
-7
lines changed

1 file changed

+30
-7
lines changed

src/memray/_memray/ghost_stack/src/ghost_stack.cpp

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -133,18 +133,41 @@ class GhostStackImpl {
133133
/**
134134
* Reset the shadow stack, restoring all original return addresses.
135135
*
136-
* This is the normal reset path - it restores the original return addresses
137-
* to the stack before clearing the shadow stack entries.
136+
* On ARM64, stale trampolines may still fire after reset() because the LR
137+
* register may have already been loaded with the trampoline address before
138+
* we restored the stack location. We keep entries_ around to handle these
139+
* stale trampolines gracefully.
140+
*
141+
* We restore ALL entries (not just 0 to tail-1) but only if the location
142+
* still contains the trampoline address. This handles the case where a
143+
* location was reused by a new frame after its original trampoline fired.
138144
*/
139145
void reset() {
140146
if (trampolines_installed_) {
141-
size_t tail = tail_.load(std::memory_order_acquire);
142-
// With reversed order, iterate from 0 to tail (all entries below tail)
143-
for (size_t i = 0; i < tail; ++i) {
144-
*entries_[i].location = entries_[i].return_address;
147+
uintptr_t tramp_addr = reinterpret_cast<uintptr_t>(ghost_ret_trampoline);
148+
149+
// Restore ALL entries whose locations still contain the trampoline.
150+
// This handles both pending entries AND already-fired entries whose
151+
// locations haven't been reused by new frames.
152+
for (size_t i = 0; i < entries_.size(); ++i) {
153+
uintptr_t current_value = *entries_[i].location;
154+
// Strip PAC bits before comparison - on ARM64 with PAC enabled,
155+
// the value read from stack may be PAC-signed while tramp_addr is not
156+
uintptr_t stripped_value = ptrauth_strip(current_value);
157+
if (stripped_value == tramp_addr) {
158+
*entries_[i].location = entries_[i].return_address;
159+
}
145160
}
161+
162+
// Mark trampolines as not installed, but DON'T clear entries_!
163+
// On ARM64, stale trampolines may still fire because LR was loaded
164+
// before we restored the stack. Keep entries_ so we can still
165+
// return the correct address.
166+
trampolines_installed_ = false;
167+
168+
// Increment epoch to signal state change
169+
epoch_.fetch_add(1, std::memory_order_release);
146170
}
147-
clear_entries();
148171
}
149172

150173
public:

0 commit comments

Comments
 (0)