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

1.7 KiB

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":

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:

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:

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, ...}.