Summary
BoolWithInverseFlag.String() panics with slice bounds out of range [-1:] when the FlagStringer function returns a string that does not contain a tab character. Since FlagStringer is a public variable that users are encouraged to override, this panic is reachable through documented API usage.
Version: cli/v3 (commit ef08e2e)
Go: 1.22
Affected Code
// flag_bool_with_inverse.go:170-183
func (bif *BoolWithInverseFlag) String() string {
out := FlagStringer(bif)
i := strings.Index(out, "\t")
prefix := "--"
// single character flags are prefixed with `-` instead of `--`
if len(bif.Name) == 1 {
prefix = "-"
}
return fmt.Sprintf("%s[%s]%s%s", prefix, bif.inversePrefix(), bif.Name, out[i:])
}
When FlagStringer returns a string without \t, strings.Index returns -1, and out[-1:] panics. The default stringifyFlag can also return "" (no tab) when the flag doesn't satisfy DocGenerationFlag.
Reproduction
package main
import (
"fmt"
"github.com/urfave/cli/v3"
)
func main() {
cli.FlagStringer = func(f cli.Flag) string {
return "custom output without tab"
}
flag := &cli.BoolWithInverseFlag{
BoolFlag: cli.BoolFlag{
Name: "verbose",
},
}
fmt.Println(flag.String())
// panic: runtime error: slice bounds out of range [-1:]
}
Why This Matters
BoolWithInverseFlag.String() is an exported method implementing fmt.Stringer — called implicitly by fmt.Print, logging, error messages
FlagStringer is a documented public variable that users are encouraged to override for custom help output
- The panic is undocumented and cannot be anticipated by users setting a custom
FlagStringer
- Note:
FlagBase[T].String() in flag_impl.go:226 calls FlagStringer(f) directly without tab parsing, so it is not affected — only BoolWithInverseFlag has this issue
Suggested Fix
Guard against strings.Index returning -1:
func (bif *BoolWithInverseFlag) String() string {
out := FlagStringer(bif)
i := strings.Index(out, "\t")
if i == -1 {
return out
}
prefix := "--"
if len(bif.Name) == 1 {
prefix = "-"
}
return fmt.Sprintf("%s[%s]%s%s", prefix, bif.inversePrefix(), bif.Name, out[i:])
}
Summary
BoolWithInverseFlag.String()panics withslice bounds out of range [-1:]when theFlagStringerfunction returns a string that does not contain a tab character. SinceFlagStringeris a public variable that users are encouraged to override, this panic is reachable through documented API usage.Version: cli/v3 (commit ef08e2e)
Go: 1.22
Affected Code
When
FlagStringerreturns a string without\t,strings.Indexreturns-1, andout[-1:]panics. The defaultstringifyFlagcan also return""(no tab) when the flag doesn't satisfyDocGenerationFlag.Reproduction
Why This Matters
BoolWithInverseFlag.String()is an exported method implementingfmt.Stringer— called implicitly byfmt.Print, logging, error messagesFlagStringeris a documented public variable that users are encouraged to override for custom help outputFlagStringerFlagBase[T].String()in flag_impl.go:226 callsFlagStringer(f)directly without tab parsing, so it is not affected — onlyBoolWithInverseFlaghas this issueSuggested Fix
Guard against
strings.Indexreturning-1: