`lower_throw!` treats any function whose name contains `jl_error` etc. as a throw (kernel becomes a trap / segfault)

Abierto Apto para principiantes
#1,088 0 comentarios 0 reacciones 0 asignados Ver en GitHub

Los mantenedores suelen responder en 1 día

@sasmith-14 ya está trabajando en esto.

Desde el 12/11/2026.

  • #1089 de @sasmith-14 — abierto

Evaluación

Dificultad
2/5
Tiempo estimado
1-3 horas
Aptitud para principiantes
75/100
Tipo de issue
Error
Claridad
Bien especificado
Estado de actividad
Activo
Stack tecnológico
julia
Área
compilers

Línea de trabajo

Empieza con lower_throw! en src/irgen.jl, alrededor de las líneas 180–198, y con los helpers de pruebas PTX mencionados en el issue. Comprueba cómo la coincidencia del nombre de la función trata las declaraciones frente a las funciones con cuerpo y, después, añade una prueba de regresión usando el reproducer handle_jl_error indicado. El trabajo está terminado cuando la llamada a la función ordinaria y el store permanecen en el LLVM generado, mientras que las funciones throw reales siguen convirtiéndose en notificación de excepciones y un trap.

Escrito por el modelo de indexación a partir del texto del issue.

Descripción

lower_throw! picks the throw functions with a substring match on the name:
https://github.com/JuliaGPU/GPUCompiler.jl/blob/6c73a0ec7d0ac2a931e215f4954ce2373e72187e/src/irgen.jl#L180-L198

so a normal Julia function whose name contains jl_error, jl_throw, jl_bounds_error etc. is treated as a throw too: its calls get erased and replaced by an exception report + trap. on PTX the kernel just becomes a trap, and on Metal it segfaults during compilation.

i came across this while going through lower_throw! with claude, not by hitting it in real code, so it's a corner case. the Metal crash made it seem worth fixing though.

repro on PTX (no GPU needed, uses the test helpers; run from a GPUCompiler checkout with julia --project):

using GPUCompiler, LLVM
include("test/helpers/runtime.jl"); include("test/helpers/ptx.jl")

@noinline handle_ok(x::Int)       = x > 0 ? x + 1 : x - 1
@noinline handle_jl_error(x::Int) = x > 0 ? x + 1 : x - 1   # same body, only the name differs
k_ok(p::Ptr{Int}, x::Int)  = (unsafe_store!(p, handle_ok(x)); nothing)
k_bad(p::Ptr{Int}, x::Int) = (unsafe_store!(p, handle_jl_error(x)); nothing)

PTX.code_llvm(stdout, k_ok,  Tuple{Ptr{Int},Int}; dump_module=true)
PTX.code_llvm(stdout, k_bad, Tuple{Ptr{Int},Int}; dump_module=true)

k_ok keeps the call and the store:

  %0 = call fastcc i64 @julia_handle_ok_1536(i64 signext %"x::Int64")
  store i64 %0, ptr %"p::Ptr", align 1
  ret void

k_bad only has the trap left:

  call fastcc void @gpu_report_exception()
  call fastcc void @gpu_signal_exception()
  call void @llvm.trap()
  unreachable

on Metal (1.12.0) the same thing crashes Julia:

using Metal
@noinline handle_ok(x::Int)       = x > 0 ? x + 1 : x - 1
@noinline handle_jl_error(x::Int) = x > 0 ? x + 1 : x - 1
k_ok(a, x)  = (a[1] = handle_ok(x); nothing)
k_bad(a, x) = (a[1] = handle_jl_error(x); nothing)

a = Metal.zeros(Int, 1)
@metal k_ok(a, 5);  Array(a)[1]   # 6
@metal k_bad(a, 5)                # signal 11

the segfault is in llvm::Value::getContext while cloning a StoreInst. probably because the call is erased without replacing its uses, so the store ends up pointing at a deleted value.

the real throw functions are always declarations, so skipping functions that have a body (isdeclaration(f) || continue) fixes it and keeps the name matching as is. i'll open a PR with that and a test.

versions
Julia Version 1.13.3
Commit 67ac47b9cd8 (2026-10-25 15:28 UTC)
Platform Info:
  OS: macOS (arm64-apple-darwin27.0.0)
  CPU: 10 × Apple M5
  LLVM: libLLVM-20.1.8 (ORCJIT, apple-m1)

GPUCompiler v2.22.2 (main, 6c73a0e)
LLVM.jl v10.4.3
Metal.jl v1.12.0 (crashes with the registered GPUCompiler v2.22.2 and v2.22.0)
Lenguaje dominante
Julia
Estrellas
191
Forks
73
Merge medio
17 h 5 min
PR fusionados (30 d)
43

Preparar el entorno

Este proyecto no incluye contenedor de desarrollo, Dockerfile ni guía de contribución, así que la configuración corre por tu cuenta: empieza por su README y consulta nuestra guía para la primera contribución para los pasos generales.

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Más de JuliaGPU/GPUCompiler.jl

Todos los issues de JuliaGPU/GPUCompiler.jl

Issues similares

Más issues de Julia

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.