Files
gookit-config/PR.md
T
dualfroz 76e67fb3e0 fix(read): prevent panic on negative slice index in a key path
GetValue and Exists validated only the upper bound of a numeric key-path
segment, so a negative index such as "arr.-1" passed the check and indexed
the slice with -1, causing an index-out-of-range panic. Add a lower-bound
check (i < 0) to the []int, []string and []any cases in both functions.
2026-09-04 09:24:12 +02:00

59 lines
1.7 KiB
Markdown

# fix(read): prevent panic on negative slice index in a key path
## Problem
Looking up a key whose path contains a negative array index panics instead of
reporting "not found":
```go
c.LoadData(map[string]any{"arr": []any{"a", "b", "c"}})
c.GetValue("arr.-1") // panic: runtime error: index out of range [-1]
c.Exists("arr.-1") // panic: runtime error: index out of range [-1]
```
Key paths frequently come from user input or configuration, so a stray
negative index crashes the caller.
## Root cause
`read.go`, in both `GetValue` and `Exists`, the slice cases parse the path
segment with `strconv.Atoi` and validate only the upper bound:
```go
case []any: // is array(load from file)
i, err := strconv.Atoi(k)
if err != nil || len(typeData) <= i { // no lower-bound check
...
return
}
item = typeData[i] // typeData[-1] panics
```
`strconv.Atoi("-1")` succeeds with `i == -1`, which passes `len(typeData) <= i`
(`3 <= -1` is false), so `typeData[-1]` is evaluated and panics. This affects
the `[]int`, `[]string` and `[]any` cases in both functions (six sites).
## Fix
Add a lower-bound check (`i < 0`) to every slice-index guard so a negative
index is treated as not found:
```go
if err != nil || i < 0 || len(typeData) <= i { // GetValue
if err != nil || i < 0 || i >= len(typeData) { // Exists
```
## Test
Added `TestConfig_GetValue_negativeIndex` in `read_test.go`, asserting that both
`GetValue("arr.-1")` and `Exists("arr.-1")` do not panic and report not found.
- Gate: `go test ./...` -> ok (PASS, exit 0, all packages)
- `go vet ./...` -> exit 0
- `go build ./...` -> exit 0
- `gofmt -l read.go read_test.go` -> clean
Counterfactual: reverting `read.go` makes the test fail with
`Panic value: runtime.boundsError{x:-1, y:3, ...}`.