Files
gosec/testutils/g602_samples.go
T
Cosmin Cojocar 5b580c76e4 Fix G602 regression coverage for issue #1545 and stabilize G117 TOML test dependency (#1546)
This PR adds regression coverage for the G602 false-positive reported in
issue #1545 by introducing two sample cases: one valid range-over-array
indexing pattern that should not trigger, and one true out-of-bounds
variant that should still be detected.

It also fixes test instability in the rules suite by adding the missing
BurntSushi TOML module metadata required by G117 sample compilation in
the test harness.

Signed-off-by: Cosmin Cojocar <cosmin@cojocar.ch>
2026-02-25 15:01:01 +01:00

744 lines
10 KiB
Go

package testutils
import "github.com/securego/gosec/v2"
// SampleCodeG602 - Slice access out of bounds
var SampleCodeG602 = []CodeSample{
{[]string{`
package main
import "fmt"
func main() {
s := make([]byte, 0)
fmt.Println(s[:3])
}
`}, 1, gosec.NewConfig()},
{[]string{`
package main
import "fmt"
func main() {
s := make([]byte, 0)
fmt.Println(s[3:])
}
`}, 1, gosec.NewConfig()},
{[]string{`
package main
import "fmt"
func main() {
s := make([]byte, 16)
fmt.Println(s[:17])
}
`}, 1, gosec.NewConfig()},
{[]string{`
package main
import "fmt"
func main() {
s := make([]byte, 16)
fmt.Println(s[:16])
}
`}, 0, gosec.NewConfig()},
{[]string{`
package main
import "fmt"
func main() {
s := make([]byte, 16)
fmt.Println(s[5:17])
}
`}, 1, gosec.NewConfig()},
{[]string{`
package main
import "fmt"
func main() {
s := make([]byte, 4)
fmt.Println(s[3])
}
`}, 0, gosec.NewConfig()},
{[]string{`
package main
import "fmt"
func main() {
s := make([]byte, 4)
fmt.Println(s[5])
}
`}, 1, gosec.NewConfig()},
{[]string{`
package main
import "fmt"
func main() {
s := make([]byte, 0)
s = make([]byte, 3)
fmt.Println(s[:3])
}
`}, 0, gosec.NewConfig()},
{[]string{`
package main
import "fmt"
func main() {
s := make([]byte, 0, 4)
fmt.Println(s[:3])
fmt.Println(s[3])
}
`}, 0, gosec.NewConfig()},
{[]string{`
package main
import "fmt"
func main() {
s := make([]byte, 0, 4)
fmt.Println(s[:5])
fmt.Println(s[7])
}
`}, 2, gosec.NewConfig()},
{[]string{`
package main
import "fmt"
func main() {
s := make([]byte, 0, 4)
x := s[:2]
y := x[:10]
fmt.Println(y)
}
`}, 1, gosec.NewConfig()},
{[]string{`
package main
import "fmt"
func main() {
s := make([]int, 0, 4)
doStuff(s)
}
func doStuff(x []int) {
newSlice := x[:10]
fmt.Println(newSlice)
}
`}, 1, gosec.NewConfig()},
{[]string{`
package main
import "fmt"
func main() {
s := make([]int, 0, 30)
doStuff(s)
x := make([]int, 20)
y := x[10:]
doStuff(y)
z := y[5:]
doStuff(z)
}
func doStuff(x []int) {
newSlice := x[:10]
fmt.Println(newSlice)
newSlice2 := x[:6]
fmt.Println(newSlice2)
}
`}, 2, gosec.NewConfig()},
{[]string{`
package main
import "fmt"
func main() {
testMap := make(map[string]any, 0)
testMap["test1"] = map[string]interface{}{
"test2": map[string]interface{}{
"value": 0,
},
}
fmt.Println(testMap)
}
`}, 0, gosec.NewConfig()},
{[]string{`
package main
import "fmt"
func main() {
s := make([]byte, 0)
if len(s) > 0 {
fmt.Println(s[0])
}
}
`}, 0, gosec.NewConfig()},
{[]string{`
package main
import "fmt"
func main() {
s := make([]byte, 0)
if len(s) > 0 {
switch s[0] {
case 0:
fmt.Println("zero")
return
default:
fmt.Println(s[0])
return
}
}
}
`}, 0, gosec.NewConfig()},
{[]string{`
package main
import "fmt"
func main() {
s := make([]byte, 0)
if len(s) > 0 {
switch s[0] {
case 0:
b := true
if b == true {
// Should work for many-levels of nesting when the condition is not on the target slice
fmt.Println(s[0])
}
return
default:
fmt.Println(s[0])
return
}
}
}
`}, 0, gosec.NewConfig()},
{[]string{`
package main
import "fmt"
func main() {
s := make([]byte, 0)
if len(s) > 0 {
if len(s) > 1 {
fmt.Println(s[1])
}
fmt.Println(s[0])
}
}
`}, 0, gosec.NewConfig()},
{[]string{`
package main
import "fmt"
func main() {
s := make([]byte, 2)
fmt.Println(s[1])
s = make([]byte, 0)
fmt.Println(s[1])
}
`}, 1, gosec.NewConfig()},
{[]string{`
package main
import "fmt"
func main() {
s := make([]byte, 0)
if len(s) > 0 {
if len(s) > 4 {
fmt.Println(s[3])
} else {
// Should error
fmt.Println(s[2])
}
fmt.Println(s[0])
}
}
`}, 1, gosec.NewConfig()},
{[]string{`
package main
import "fmt"
func main() {
s := make([]byte, 0)
if len(s) > 0 {
fmt.Println("fake test")
}
fmt.Println(s[0])
}
`}, 1, gosec.NewConfig()},
{[]string{`
package main
import "fmt"
func main() {
s := make([]int, 16)
for i := 0; i < 17; i++ {
s = append(s, i)
}
if len(s) < 16 {
fmt.Println(s[10:16])
} else {
fmt.Println(s[3:18])
}
fmt.Println(s[0])
for i := range s {
fmt.Println(s[i])
}
}
`}, 0, gosec.NewConfig()},
{[]string{`
package main
func main() {
s := make([]int, 16)
for i := 10; i < 17; i++ {
s[i]=i
}
}
`}, 1, gosec.NewConfig()},
{[]string{`
package main
func main() {
var s []int
for i := 10; i < 17; i++ {
s[i]=i
}
}
`}, 1, gosec.NewConfig()},
{[]string{`
package main
func main() {
s := make([]int,5, 16)
for i := 1; i < 6; i++ {
s[i]=i
}
}
`}, 1, gosec.NewConfig()},
{[]string{`
package main
func main() {
var s [20]int
for i := 10; i < 17; i++ {
s[i]=i
}
}`}, 0, gosec.NewConfig()},
{[]string{`
package main
func main() {
var s [20]int
for i := 1; i < len(s); i++ {
s[i]=i
}
}
`}, 0, gosec.NewConfig()},
{[]string{`
package main
func main() {
var s [20]int
for i := 1; i <= len(s); i++ {
s[i]=i
}
}
`}, 1, gosec.NewConfig()},
{[]string{`
package main
func main() {
var s [20]int
for i := 18; i <= 22; i++ {
s[i]=i
}
}
`}, 1, gosec.NewConfig()},
{[]string{`
package main
func main() {
args := []any{"1"}
switch len(args) - 1 {
case 1:
_ = args[1]
}
}
`}, 0, gosec.NewConfig()},
{[]string{`
package main
import "fmt"
func main() {
value := "1234567890"
weight := []int{2, 3, 4, 5, 6, 7}
wLen := len(weight)
l := len(value) - 1
addr := make([]any, 7)
sum := 0
weight[2] = 3
for i := l; i >= 0; i-- {
v := int(value[i] - '0')
if v < 0 || v > 9 {
fmt.Println("invalid number at column", i+1)
break
}
addr[2] = v
sum += v * weight[(l-i)%wLen]
}
fmt.Println(sum)
}
`}, 0, gosec.NewConfig()},
{[]string{`
package main
import "fmt"
func pairwise(list []any) {
for i := 0; i < len(list)-1; i += 2 {
// Safe: i < len-1 implies i+1 < len
fmt.Printf("%v %v\n", list[i], list[i+1])
}
}
func main() {
// Calls with both even and odd lengths (and empty) to exercise the path
pairwise([]any{"a", "b", "c", "d"})
pairwise([]any{"x", "y", "z"})
pairwise([]any{})
}
`}, 0, gosec.NewConfig()},
{[]string{`
package main
import "fmt"
type Handler struct{}
func (h *Handler) HandleArgs(list []any) {
for i := 0; i < len(list)-1; i += 2 {
fmt.Printf("%v %v\n", list[i], list[i+1])
}
}
func main() {
// Empty main: no call to HandleArgs, mimicking library code or unreachable for constant prop
}
`}, 0, gosec.NewConfig()},
{[]string{`
package main
import "fmt"
func safeTriples(list []int) {
for i := 0; i < len(list)-2; i += 3 {
fmt.Println(list[i], list[i+1], list[i+2])
}
}
func main() {
safeTriples([]int{1,2,3,4,5,6,7})
safeTriples([]int{1,2,3,4,5})
}
`}, 0, gosec.NewConfig()},
{[]string{`
package main
import "fmt"
func pairwise(list []any) {
for i := 0; i+1 < len(list); i += 2 {
// Safe: i+1 < len implies i < len-1
fmt.Printf("%v %v\n", list[i], list[i+1])
}
}
func main() {
// Calls with both even and odd lengths (and empty) to exercise the path
pairwise([]any{"a", "b", "c", "d"})
pairwise([]any{"x", "y", "z"})
pairwise([]any{})
}
`}, 0, gosec.NewConfig()},
{[]string{`
package main
import "fmt"
func main() {
s := make([]byte, 0, 4)
// Extending length up to capacity is valid
x := s[:3]
fmt.Println(x)
}
`}, 0, gosec.NewConfig()},
{[]string{`
package main
import "fmt"
func main() {
s := make([]byte, 0, 4)
// 3-index slice exceeding capacity
x := s[:2:5]
fmt.Println(x)
}
`}, 1, gosec.NewConfig()},
{[]string{`
package main
import "fmt"
func main() {
s := make([]byte, 0, 10)
// 3-index slice within capacity
x := s[2:5:8]
fmt.Println(x)
}
`}, 0, gosec.NewConfig()},
{[]string{`
package main
import "fmt"
func main() {
s := make([]byte, 4)
for i := range 3 {
x := s[i+2]
fmt.Println(x)
}
}
`}, 1, gosec.NewConfig()},
{[]string{`
package main
import "fmt"
func main() {
s := make([]byte, 5)
for i := range 3 {
x := s[i+2]
fmt.Println(x)
}
}
`}, 0, gosec.NewConfig()},
{[]string{`
package main
import "fmt"
func main() {
s := make([]byte, 2)
for i := 0; i < 3; i++ {
x := s[i+2]
fmt.Println(x)
}
}
`}, 1, gosec.NewConfig()},
{[]string{`
package main
import "fmt"
func main() {
s := make([]byte, 2)
i := 0
// decomposeIndex should handle i + 1 + 2 = i + 3
fmt.Println(s[i+1+2])
}
`}, 1, gosec.NewConfig()},
{[]string{`
package main
import "fmt"
func main() {
s := make([]byte, 5)
for i := 0; i+1 < len(s); i++ {
// i+1 < 5 => i < 4. Max i = 3. i+1 = 4. s[4] is safe.
fmt.Println(s[i+1])
}
}
`}, 0, gosec.NewConfig()},
{[]string{`
package main
import "fmt"
func main() {
var a [10]int
idx := 12
fmt.Println(a[idx])
}
`}, 1, gosec.NewConfig()},
{[]string{`
package main
import "fmt"
func main() {
s := make([]byte, 4)
if 5 < len(s) {
fmt.Println(s[4])
}
}
`}, 0, gosec.NewConfig()},
{[]string{`
package main
func main() {
var a [10]int
k := 11
_ = a[:5:k]
}
`}, 1, gosec.NewConfig()},
{[]string{`
package main
import "fmt"
func main() {
s := make([]int, 5)
idx := -1
fmt.Println(s[idx])
}
`}, 1, gosec.NewConfig()},
// Issue #1495: G602 false positive for array element access with coexisting slice expression
{[]string{`
package main
import (
"log/slog"
"runtime"
"time"
)
func main() {
var pcs [1]uintptr
runtime.Callers(2, pcs[:])
r := slog.NewRecord(time.Now(), slog.LevelError, "test", pcs[0])
_ = r
}
`}, 0, gosec.NewConfig()},
{[]string{`
package main
func main() {
var buf [4]byte
copy(buf[:], []byte("test"))
_ = buf[0]
_ = buf[1]
_ = buf[2]
_ = buf[3]
}
`}, 0, gosec.NewConfig()},
{[]string{`
package main
func main() {
var buf [2]byte
copy(buf[:], []byte("ab"))
idx := 3
_ = buf[idx]
}
`}, 1, gosec.NewConfig()},
{[]string{`
package main
func doWork(s []int) {}
func main() {
var arr [5]int
doWork(arr[:])
_ = arr[0]
_ = arr[4]
}
`}, 0, gosec.NewConfig()},
// Issue #1525: G602 false positive for array index in range-over-array loops
{[]string{`
package main
func main() {
var arr [8]int
for i := range arr {
arr[i] = i
}
}
`}, 0, gosec.NewConfig()},
{[]string{`
package main
func main() {
var arr [8]int
for i := range arr {
_ = arr[i+1]
}
}
`}, 1, gosec.NewConfig()},
// Issue #1545: G602 false positive on range-over-array indexing into same-size array
{[]string{`
package main
func main() {
ranged := [1]int{1}
var accessed [1]*int
for i, r := range ranged {
accessed[i] = &r
}
}
`}, 0, gosec.NewConfig()},
{[]string{`
package main
func main() {
ranged := [2]int{1, 2}
var accessed [1]*int
for i, r := range ranged {
accessed[i] = &r
}
}
`}, 1, gosec.NewConfig()},
}