diff --git a/strutil/split.go b/strutil/split.go index 4961b9b..2b6b09a 100644 --- a/strutil/split.go +++ b/strutil/split.go @@ -166,6 +166,12 @@ func Substr(s string, pos, length int) string { stopIdx = strLn + length } + // A negative length can move stopIdx before pos; clamp to avoid an + // out-of-range slice. + if stopIdx < pos { + stopIdx = pos + } + return string(runes[pos:stopIdx]) } diff --git a/strutil/split_test.go b/strutil/split_test.go index 2a97caf..4e57ee7 100644 --- a/strutil/split_test.go +++ b/strutil/split_test.go @@ -120,6 +120,12 @@ func TestSubstr(t *testing.T) { assert.Eq(t, "", strutil.Substr("abcDEF", 23, 5)) assert.Eq(t, "cDEF12", strutil.Substr("abcDEF123", 2, -1)) assert.Eq(t, "cDEF", strutil.Substr("abcDEF123", 2, -3)) + + // negative length trimming more than the remaining substring must not + // panic; it should yield an empty string. + assert.Eq(t, "", strutil.Substr("hello", 4, -3)) + assert.Eq(t, "", strutil.Substr("hello", 3, -5)) + assert.Eq(t, "", strutil.Substr("abcDEF123", 8, -3)) } func TestSplitInlineComment(t *testing.T) {