Skip to content

Commit 2990b77

Browse files
committed
Align stack and instruction pointers
1 parent 2635252 commit 2990b77

File tree

3 files changed

+101
-2
lines changed

3 files changed

+101
-2
lines changed

base/error.jl

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,50 @@ function _reformat_bt(bt::Array{Ptr{Cvoid},1}, bt2::Array{Any,1})
9999
ret
100100
end
101101

102+
"""
103+
_reformat_sp(bt_data...) -> sp::Vector{Ptr{Cvoid}}
104+
105+
Convert the output `bt_data` of `jl_backtrace_from_here` with `returnsp` flag set to a
106+
vector of valid stack pointers `sp`; i.e., `sp` is a subset of `bt_data[3]`.
107+
108+
This function is used only in test.
109+
"""
110+
function _reformat_sp(
111+
bt_raw::Array{Ptr{Cvoid},1},
112+
bt2::Array{Any,1},
113+
sp_raw::Array{Ptr{Cvoid},1},
114+
)
115+
bt = _reformat_bt(bt_raw, bt2)
116+
sp = empty!(similar(sp_raw))
117+
i = j = 0
118+
while true
119+
# Advacne `i` such that `bt[i] isa Ptr{Cvoid}` (native poitner).
120+
local ip
121+
while true
122+
if i == lastindex(bt)
123+
return sp
124+
end
125+
i += 1
126+
x = bt[i]
127+
if x isa Ptr{Cvoid}
128+
ip = x
129+
break
130+
end
131+
end
132+
# Advance `j` such that `bt_raw[j] == bt[i]` to find a valid stack pointer.
133+
while true
134+
if j == lastindex(bt_raw)
135+
return sp
136+
end
137+
j += 1
138+
if bt_raw[j] == ip
139+
push!(sp, sp_raw[j])
140+
break
141+
end
142+
end
143+
end
144+
end
145+
102146
"""
103147
backtrace()
104148

src/stackwalk.c

Lines changed: 2 additions & 2 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

test/backtrace.jl

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

261+
"""
262+
withalloca(f, nbytes)
263+
264+
Call function `f` with a `ptr::Ptr{Cvoid}` pointing to `nbytes` bytes of a
265+
stack-allocated memory region.
266+
267+
NOTE: `f` and all functions reachable from `f` must not contain a yield point.
268+
"""
269+
function withalloca(f, nbytes)
270+
function wrapper(int)
271+
f(Ptr{Cvoid}(int))
272+
nothing
273+
end
274+
closure = @cfunction($wrapper, Cvoid, (UInt64,))
275+
GC.@preserve closure begin
276+
Base.llvmcall(
277+
(
278+
"""
279+
define void @entry(i64 %0, i64 %1) {
280+
top:
281+
%aptr = alloca i64, i64 %1
282+
%aint = ptrtoint i64* %aptr to i64
283+
%fptr = inttoptr i64 %0 to void (i64)*
284+
call void %fptr(i64 %aint)
285+
ret void
286+
}
287+
""",
288+
"entry",
289+
),
290+
Cvoid,
291+
Tuple{Ptr{Cvoid},Int64},
292+
Base.unsafe_convert(Ptr{Cvoid}, closure),
293+
nbytes,
294+
)
295+
end
296+
end
297+
298+
function sandwiched_backtrace()
299+
local ptr1, ptr2, bt
300+
withalloca(16) do p1
301+
ptr1 = p1
302+
bt = ccall(:jl_backtrace_from_here, Ref{Base.SimpleVector}, (Cint, Cint), true, 0)
303+
withalloca(16) do p2
304+
ptr2 = p2
305+
end
306+
end
307+
return ptr1, ptr2, bt
308+
end
309+
310+
@testset "stack pointers" begin
311+
ptr1, ptr2, bt_data = sandwiched_backtrace()
312+
sp = Base._reformat_sp(bt_data...)
313+
@test ptr2 < sp[1] < ptr1
314+
@test all(diff(Int128.(UInt.(sp))) .> 0)
315+
end

0 commit comments

Comments
 (0)