Skip to content

Commit d858a13

Browse files
committed
Support resolving small_typeof type tags
This avoids a segmentation fault when exploring these special type tags, which are not valid pointers on their own.
1 parent 172d10b commit d858a13

File tree

2 files changed

+42
-9
lines changed

2 files changed

+42
-9
lines changed

src/classify.jl

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -108,12 +108,37 @@ end
108108
"""
109109
Returns `nothing` if the value could not be resolved statically.
110110
"""
111-
function resolve_static_jl_value_t(val::LLVM.Value)
111+
function resolve_static_uint(val::LLVM.Value)
112112
val = unwrap_ptr_casts(val)
113113
val = look_through_loads(val)
114114
!isa(val, ConstantInt) && return nothing
115-
ptr = reinterpret(Ptr{Cvoid}, convert(UInt, val))
116-
return Base.unsafe_pointer_to_objref(ptr)
115+
return convert(UInt, val)
116+
end
117+
118+
"""
119+
Returns `nothing` if the value could not be resolved statically.
120+
"""
121+
function resolve_static_jl_value(val::LLVM.Value)
122+
addr = resolve_static_uint(val)
123+
addr === nothing && return nothing
124+
return Base.unsafe_pointer_to_objref(Ptr{Cvoid}(addr))
125+
end
126+
127+
"""
128+
Returns `nothing` if the value could not be resolved statically.
129+
"""
130+
function resolve_static_type_tag(val::LLVM.Value)
131+
type_tag = resolve_static_uint(val)
132+
type_tag === nothing && return nothing
133+
type_addr = if type_tag < (JL_MAX_TAGS << 4)
134+
# "small" type tags are indices into a special array
135+
jl_small_typeof = Ptr{Ptr{Cvoid}}(cglobal(:jl_small_typeof))
136+
type_idx = type_tag ÷ Core.sizeof(Ptr{Cvoid})
137+
unsafe_load(jl_small_typeof, type_idx + 1)
138+
else
139+
Ptr{Cvoid}(type_tag)
140+
end
141+
return Base.unsafe_pointer_to_objref(type_addr)
117142
end
118143

119144
function transitive_uses(inst::LLVM.Instruction; unwrap = (use)->false)
@@ -128,6 +153,8 @@ function transitive_uses(inst::LLVM.Instruction; unwrap = (use)->false)
128153
return uses_
129154
end
130155

156+
const JL_MAX_TAGS = 64 # see `enum jl_small_typeof_tags` in julia.h
157+
131158
"""
132159
Returns `nothing` if the type could not be resolved statically.
133160
"""
@@ -144,10 +171,10 @@ function resolve_allocations(call::LLVM.Value)
144171
name = match_[2]
145172

146173
if name in ("gc_pool_alloc_instrumented", "gc_small_alloc_instrumented", "gc_big_alloc_instrumented", "gc_alloc_typed")
147-
type = resolve_static_jl_value_t(operands(call)[end-1])
174+
type = resolve_static_type_tag(operands(call)[end-1])
148175
return type !== nothing ? [(call, type)] : nothing
149176
elseif name in ("alloc_array_1d", "alloc_array_2d", "alloc_array_3d")
150-
type = resolve_static_jl_value_t(operands(call)[1])
177+
type = resolve_static_jl_value(operands(call)[1])
151178
return type!== nothing ? [(call, type)] : nothing
152179
elseif name == "alloc_string"
153180
return [(call, String)]
@@ -160,10 +187,10 @@ function resolve_allocations(call::LLVM.Value)
160187
@assert VERSION > v"1.11.0-DEV.753"
161188
return [(call, Memory{UInt8})]
162189
elseif name == "alloc_genericmemory"
163-
type = resolve_static_jl_value_t(operands(call)[1])
190+
type = resolve_static_jl_value(operands(call)[1])
164191
return [(call, type !== nothing ? type : Memory)]
165192
elseif name == "alloc_genericmemory_unchecked"
166-
type = resolve_static_jl_value_t(operands(call)[3])
193+
type = resolve_static_jl_value(operands(call)[3])
167194
return [(call, type !== nothing ? type : Memory)]
168195
elseif occursin(r"^box_(.*)", name)
169196
typestr = match(r"^box_(.*)", name).captures[end]
@@ -207,8 +234,7 @@ function resolve_allocations(call::LLVM.Value)
207234
# It is possible for the optimizer to merge multiple distinct `gc_pool_alloc`
208235
# allocations which actually have distinct types, so here we count each type
209236
# tag store as a separate allocation.
210-
type_tag = operands(store)[1]
211-
type = resolve_static_jl_value_t(type_tag)
237+
type = resolve_static_type_tag(operands(store)[1])
212238
if type === nothing
213239
type = Any
214240
end

test/runtests.jl

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,10 @@ end
340340
end
341341
end
342342

343+
function svec_alloc(x)
344+
return Core.svec(x, 1)
345+
end
346+
343347
@testset "issues" begin
344348
# issue #64
345349
let io = IOBuffer()
@@ -353,4 +357,7 @@ end
353357
@test x === nothing || x === (1.0, 1.5)
354358
x = foo_with_union_rt((1.0, 1.5))
355359
@test x === nothing || x === (1.0, 1.5)
360+
361+
# issue #96
362+
@test length(check_allocs(svec_alloc, (ErrorException,))) > 0
356363
end

0 commit comments

Comments
 (0)