From d1a552ccbc9cf438940bf473ef2888af9105c6a2 Mon Sep 17 00:00:00 2001 From: Ian Butterworth Date: Sun, 15 Mar 2026 20:06:07 -0400 Subject: [PATCH 1/4] precompilation: fix show_progress crash when bar.current goes negative There is a race between the print loop task and worker tasks: when a package is already up-to-date, a worker increments n_already_precomp[] before incrementing n_done[], so the print loop can observe a window where n_done[] - n_already_precomp[] is transiently negative. This caused show_progress to compute a negative n_filled and crash with "can't repeat a string -1 times". Guard both bar.current and bar.max with max(0, ...) to avoid this. Fixes #61333 Co-Authored-By: Claude --- base/precompilation.jl | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/base/precompilation.jl b/base/precompilation.jl index 0da757c9d73bd..7d0db3938e27e 100644 --- a/base/precompilation.jl +++ b/base/precompilation.jl @@ -998,8 +998,11 @@ function _precompilepkgs(pkgs::Union{Vector{String}, Vector{PkgId}}, if i_local > 1 print(iostr, ansi_cleartoend) end - bar.current = n_done[] - n_already_precomp[] - bar.max = n_total - n_already_precomp[] + # max(0,...) guards against a race where the print loop runs after + # n_already_precomp is incremented but before n_done is incremented, + # which would otherwise produce a negative value and crash repeat(). + bar.current = max(0, n_done[] - n_already_precomp[]) + bar.max = max(0, n_total - n_already_precomp[]) # when sizing to the terminal width subtract a little to give some tolerance to resizing the # window between print cycles termwidth = (displaysize(io)::Tuple{Int,Int})[2] - 4 From 96fa5157724fbd80ede7dc9a5f14eb82b31db650 Mon Sep 17 00:00:00 2001 From: Ian Butterworth Date: Mon, 16 Mar 2026 12:48:48 -0400 Subject: [PATCH 2/4] clamp Co-Authored-By: Claude --- base/precompilation.jl | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/base/precompilation.jl b/base/precompilation.jl index 7d0db3938e27e..20e305e9bd1a8 100644 --- a/base/precompilation.jl +++ b/base/precompilation.jl @@ -350,8 +350,9 @@ function show_progress(io::IO, p::MiniProgressBar; termwidth=nothing, carriagere end termwidth = @something termwidth (displaysize(io)::Tuple{Int,Int})[2] max_progress_width = max(0, min(termwidth - textwidth(p.header) - textwidth(progress_text) - 10 , p.width)) - n_filled = floor(Int, max_progress_width * perc / 100) - partial_filled = (max_progress_width * perc / 100) - n_filled + perc_clamped = clamp(perc, 0.0, 100.0) + n_filled = floor(Int, max_progress_width * perc_clamped / 100) + partial_filled = (max_progress_width * perc_clamped / 100) - n_filled n_left = max_progress_width - n_filled headers = split(p.header, ' ') to_print = sprint(; context=io) do io From ace85c182b0765b67423abd644f6388bf2522ffe Mon Sep 17 00:00:00 2001 From: Ian Butterworth Date: Mon, 16 Mar 2026 13:53:17 -0400 Subject: [PATCH 3/4] Update precompilation.jl Co-authored-by: Cody Tapscott <84105208+topolarity@users.noreply.github.com> --- base/precompilation.jl | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/base/precompilation.jl b/base/precompilation.jl index 20e305e9bd1a8..2799415772f7e 100644 --- a/base/precompilation.jl +++ b/base/precompilation.jl @@ -350,8 +350,7 @@ function show_progress(io::IO, p::MiniProgressBar; termwidth=nothing, carriagere end termwidth = @something termwidth (displaysize(io)::Tuple{Int,Int})[2] max_progress_width = max(0, min(termwidth - textwidth(p.header) - textwidth(progress_text) - 10 , p.width)) - perc_clamped = clamp(perc, 0.0, 100.0) - n_filled = floor(Int, max_progress_width * perc_clamped / 100) + n_filled = floor(Int, max_progress_width * clamp(perc / 100, 0.0, 1.0)) partial_filled = (max_progress_width * perc_clamped / 100) - n_filled n_left = max_progress_width - n_filled headers = split(p.header, ' ') From bde767f920f3e8944c02f036f5860398f5bdd542 Mon Sep 17 00:00:00 2001 From: Ian Butterworth Date: Mon, 16 Mar 2026 14:02:08 -0400 Subject: [PATCH 4/4] Update base/precompilation.jl Co-authored-by: Cody Tapscott <84105208+topolarity@users.noreply.github.com> --- base/precompilation.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/base/precompilation.jl b/base/precompilation.jl index 2799415772f7e..dc82d5021f06e 100644 --- a/base/precompilation.jl +++ b/base/precompilation.jl @@ -350,8 +350,8 @@ function show_progress(io::IO, p::MiniProgressBar; termwidth=nothing, carriagere end termwidth = @something termwidth (displaysize(io)::Tuple{Int,Int})[2] max_progress_width = max(0, min(termwidth - textwidth(p.header) - textwidth(progress_text) - 10 , p.width)) - n_filled = floor(Int, max_progress_width * clamp(perc / 100, 0.0, 1.0)) - partial_filled = (max_progress_width * perc_clamped / 100) - n_filled + filled = max_progress_width * clamp(perc / 100, 0.0, 1.0) + (partial_filled, n_filled::Int64) = modf(filled) # get fractional / integer part n_left = max_progress_width - n_filled headers = split(p.header, ' ') to_print = sprint(; context=io) do io