From 3b3b7ccd85b45db32b54c4692d72fea3e13ced0b Mon Sep 17 00:00:00 2001 From: Tim Besard Date: Tue, 13 Oct 2026 17:31:15 +0200 Subject: [PATCH] Test loops that exit when their counter wraps around The SPIR-V back-end lowers `i += 1; i == 0` to OpIAddCarry, and IGC's optimizer carries the {i64, i1} result through the loop PHI. IGC's legalization (libigc 2.34.4 through 2.41.5) then erased the intrinsic while the PHI still referenced it: a use-after-free that aborted the Julia 1.12 CI job in `findmax(abs, x)` under `--check-bounds=yes` and corrupted the heap silently elsewhere. Fixed by the IGC backport in libigc_jll 2.34.4+5. --- test/execution.jl | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/test/execution.jl b/test/execution.jl index 68487da8..44b21b9c 100644 --- a/test/execution.jl +++ b/test/execution.jl @@ -1068,3 +1068,30 @@ end @test occursin(r"%heap\d* = alloca", sprint(io -> oneAPI.code_llvm(io, ref_kernel, T; kernel = true))) @test !occursin(r"%heap\d* = alloca", sprint(io -> oneAPI.code_llvm(io, plain_kernel, T; kernel = true))) end + +@testset "loop exiting on counter wrap-around" begin + # The SPIR-V back-end turns `i += 1; i == 0` into OpIAddCarry, and IGC's optimizer sinks + # the extracts of its {i64, i1} result through the loop PHI. Before libigc_jll 2.34.4+5, + # IGC's legalization then erased the intrinsic while that PHI still referenced it, a + # use-after-free that crashed or silently corrupted the host + # (https://buildkite.com/julialang/oneapi-dot-jl/builds/1800). + function count_until_wrap(out, flags, n) + i = n + while true + i += one(i) + i == 0 && break + if @inbounds(flags[1]) + @inbounds out[1] = i + break + end + end + return + end + out = oneAPI.zeros(UInt64, 1) + flags = oneArray([false]) + @oneapi count_until_wrap(out, flags, typemax(UInt64) - 3) + @test Array(out) == [0] + copyto!(flags, [true]) + @oneapi count_until_wrap(out, flags, typemax(UInt64) - 3) + @test Array(out) == [typemax(UInt64) - 2] +end