-
Notifications
You must be signed in to change notification settings - Fork 1.8k
BoolWithInverseFlag.String() panics when FlagStringer returns string without tab #2303
Copy link
Copy link
Open
Description
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 implementingfmt.Stringer— called implicitly byfmt.Print, logging, error messagesFlagStringeris 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 callsFlagStringer(f)directly without tab parsing, so it is not affected — onlyBoolWithInverseFlaghas 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:])
}Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels