Skip to content

Commit 5ed9a4e

Browse files
tkfvtjnash
authored andcommitted
Fix stack pointer retrieval in jl_backtrace_from_here (JuliaLang#42585)
Co-authored-by: Jameson Nash <vtjnash@gmail.com>
1 parent 88c3aaa commit 5ed9a4e

File tree

2 files changed

+88
-3
lines changed

2 files changed

+88
-3
lines changed

src/stackwalk.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -114,8 +114,6 @@ static int jl_unw_stepn(bt_cursor_t *cursor, jl_bt_element_t *bt_data, size_t *b
114114
from_signal_handler = 0;
115115
continue;
116116
}
117-
if (sp)
118-
sp[n] = thesp;
119117
// For the purposes of looking up debug info for functions, we want
120118
// to harvest addresses for the *call* instruction `call_ip` during
121119
// stack walking. However, this information isn't directly
@@ -168,6 +166,8 @@ static int jl_unw_stepn(bt_cursor_t *cursor, jl_bt_element_t *bt_data, size_t *b
168166
}
169167
}
170168
bt_entry->uintptr = call_ip;
169+
if (sp)
170+
sp[n] = thesp;
171171
n++;
172172
}
173173
// NOTE: if we have some pgcstack entries remaining (because the
@@ -259,8 +259,8 @@ JL_DLLEXPORT jl_value_t *jl_backtrace_from_here(int returnsp, int skip)
259259
jl_array_grow_end(ip, maxincr);
260260
uintptr_t *sp_ptr = NULL;
261261
if (returnsp) {
262-
sp_ptr = (uintptr_t*)jl_array_data(sp) + offset;
263262
jl_array_grow_end(sp, maxincr);
263+
sp_ptr = (uintptr_t*)jl_array_data(sp) + offset;
264264
}
265265
size_t size_incr = 0;
266266
have_more_frames = jl_unw_stepn(&cursor, (jl_bt_element_t*)jl_array_data(ip) + offset,

test/backtrace.jl

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,3 +258,88 @@ let code = """
258258
@test occursin("InterpreterIP in top-level CodeInfo for Main.A", bt_str)
259259
end
260260

261+
"""
262+
_reformat_sp(bt_data...) -> sp::Vector{Ptr{Cvoid}}
263+
264+
Convert the output `bt_data` of `jl_backtrace_from_here` with `returnsp` flag set to a
265+
vector of valid stack pointers `sp`; i.e., `sp` is a subset of `bt_data[3]`.
266+
267+
See also `Base._reformat_bt`.
268+
"""
269+
function _reformat_sp(
270+
bt_raw::Array{Ptr{Cvoid},1},
271+
bt2::Array{Any,1},
272+
sp_raw::Array{Ptr{Cvoid},1},
273+
)
274+
bt = Base._reformat_bt(bt_raw, bt2)
275+
sp = empty!(similar(sp_raw))
276+
i = j = 0
277+
while true
278+
# Advance `i` such that `bt[i] isa Ptr{Cvoid}` (native pointer).
279+
local ip
280+
while true
281+
if i == lastindex(bt)
282+
return sp
283+
end
284+
i += 1
285+
x = bt[i]
286+
if x isa Ptr{Cvoid}
287+
ip = x
288+
break
289+
end
290+
end
291+
# Advance `j` such that `bt_raw[j] == bt[i]` to find a valid stack pointer.
292+
while true
293+
if j == lastindex(bt_raw)
294+
return sp
295+
end
296+
j += 1
297+
if bt_raw[j] == ip
298+
push!(sp, sp_raw[j])
299+
break
300+
end
301+
end
302+
end
303+
end
304+
305+
"""
306+
withframeaddress(f)
307+
308+
Call function `f` with an address `ptr::Ptr{Cvoid}` of an independent frame
309+
immediately outer to `f`.
310+
"""
311+
withframeaddress
312+
@eval @noinline function withframeaddress(f)
313+
sp = Core.Intrinsics.llvmcall(
314+
($"""
315+
declare i8* @llvm.frameaddress(i32)
316+
define private i$(Sys.WORD_SIZE) @frameaddr() {
317+
%1 = call i8* @llvm.frameaddress(i32 0)
318+
%2 = ptrtoint i8* %1 to i$(Sys.WORD_SIZE)
319+
ret i$(Sys.WORD_SIZE) %2
320+
}""", "frameaddr"),
321+
UInt,
322+
Tuple{},
323+
)
324+
@noinline f(Ptr{Cvoid}(sp))
325+
end
326+
327+
function sandwiched_backtrace()
328+
local ptr1, ptr2, bt
329+
withframeaddress() do p1
330+
ptr1 = p1
331+
bt = ccall(:jl_backtrace_from_here, Ref{Base.SimpleVector}, (Cint, Cint), true, 0)
332+
withframeaddress() do p2
333+
ptr2 = p2
334+
end
335+
end
336+
return ptr1, ptr2, bt
337+
end
338+
339+
@testset "stack pointers" begin
340+
ptr1, ptr2, bt_data = sandwiched_backtrace()
341+
sp = _reformat_sp(bt_data...)
342+
@test ptr2 < sp[2]
343+
@test sp[1] < ptr1
344+
@test all(diff(Int128.(UInt.(sp))) .> 0)
345+
end

0 commit comments

Comments
 (0)