Style.Width()/Height() panic ("makeslice: len out of range") on extreme values instead of clamping
Style.Width() and Style.Height() accept an unbounded int that flows straight into strings.Repeat with no upper bound, so a large-enough value crashes the whole program with an unrecoverable runtime panic instead of degrading gracefully (e.g. clamping or truncating).
Repro
package main
import (
"math"
"github.com/charmbracelet/lipgloss"
)
func main() {
lipgloss.NewStyle().Width(math.MaxInt).Render("hi")
}panic: runtime error: makeslice: len out of range
goroutine 1 [running]:
internal/bytealg.MakeNoZero(...)
strings.(*Builder).grow(...)
strings.(*Builder).Grow(...)
strings.Repeat({0x596460?, 0x1}, 0x2?)
github.com/charmbracelet/lipgloss.alignTextHorizontal(...)
align.go:44
github.com/charmbracelet/lipgloss.Style.Render(...)
style.go:496Same crash for .Height(math.MaxInt), via alignTextVertical's strings.Repeat("\n", height-strHeight) a few lines below.
Root cause
align.go:
func alignTextHorizontal(str string, pos Position, width int, style *ansi.Style) string {
...
shortAmount := widestLine - lineWidth
shortAmount += max(0, width-(shortAmount+lineWidth))
if shortAmount > 0 {
...
s := strings.Repeat(" ", shortAmount) // align.go:44 (Left/Right), similar for Centerand alignTextVertical:
case Top:
return str + strings.Repeat("\n", height-strHeight)Neither function bounds width/height before it's used as a strings.Repeat count. With a pathological value, shortAmount (or height-strHeight) becomes large enough that the Go runtime refuses the allocation outright — this isn't a slow-but-technically-possible allocation, it's a hard makeslice: len out of range rejection, so there's no configuration or amount of RAM that makes this succeed.
Why I think this is worth guarding against, not just a fuzz-only value
I hit this by intentionally probing extreme values, but the shape of bug that produces one isn't exotic: this library is a low-level building block for terminal-width-driven layout, so a caller computing a width from term.GetSize() plus/minus some arithmetic (subtracting borders, margins, a miscomputed "remaining space" in a flex-style layout, etc.) is exactly the kind of code that can accidentally produce an extreme or wrapped-around value one step removed from the actual mistake — and right now that turns into a hard, unrecoverable process crash here rather than a visibly wrong-but-survivable render. (For context: I ran into the same general failure shape — an unbounded width/count flowing into an unchecked allocation or subtraction — independently in eza, bat, and muesli/reflow this week, so it seems to be a fairly common blind spot in terminal-formatting code generally, not specific to this codebase.)
Suggested fix
Clamp shortAmount / height-strHeight to something sane (or just skip the repeat when the value exceeds a reasonable bound, e.g. some multiple of math.MaxInt32 or an internal max-terminal-width constant) before calling strings.Repeat. Happy to send a PR if a specific clamp value/approach is preferred — didn't want to guess at the right ceiling without checking first.
Versions
github.com/charmbracelet/lipglossat currentmain(module resolved to require Go >= 1.25 at time of testing)- Go 1.25.0, linux/amd64
Source: charmbracelet/lipgloss