gosec/analyzers/conversion_overflow_test.go

140 lines
5.9 KiB
Go
Raw Normal View History

Improvement the int conversion overflow logic to handle bound checks (#1194) * add test cases Signed-off-by: czechbol <adamludes@gmail.com> * fix bounds check logic Signed-off-by: czechbol <adamludes@gmail.com> * tweak test cases Signed-off-by: czechbol <adamludes@gmail.com> * fix codestyle Signed-off-by: czechbol <adamludes@gmail.com> * improve bounds check logic Signed-off-by: czechbol <adamludes@gmail.com> * max recursion depth Signed-off-by: czechbol <adamludes@gmail.com> * add test case for len function Signed-off-by: czechbol <adamludes@gmail.com> * relax len function bounds checks Co-authored-by: Ben Krieger <ben.krieger@intel.com> * handle cases when convert instruction is after the if blocks Signed-off-by: czechbol <adamludes@gmail.com> * improve range check discovery, add tests Signed-off-by: czechbol <adamludes@gmail.com> * refactor for readability Signed-off-by: czechbol <adamludes@gmail.com> * add cap function test Signed-off-by: czechbol <adamludes@gmail.com> * calculate signed min without throwing overflow warnings Signed-off-by: czechbol <adamludes@gmail.com> * perform bounds checks int size calculations Signed-off-by: czechbol <adamludes@gmail.com> * basic equal operator logic Signed-off-by: czechbol <adamludes@gmail.com> * uintptr -> unsafe.Pointer test case Signed-off-by: czechbol <adamludes@gmail.com> * fix review comments Signed-off-by: czechbol <adamludes@gmail.com> * Rebase and fix go module Change-Id: I8da6495eaaf25b1739389aa98492bd7df338085b Signed-off-by: Cosmin Cojocar <ccojocar@google.com> * fix false positive for negated value Signed-off-by: czechbol <adamludes@gmail.com> * fix range conditions Signed-off-by: czechbol <adamludes@gmail.com> * Ignore the golangci/gosec G115 warning Change-Id: I0db56cb0a5f9ab6e815e2480ec0b66d7061b23d3 Signed-off-by: Cosmin Cojocar <ccojocar@google.com> --------- Signed-off-by: czechbol <adamludes@gmail.com> Signed-off-by: Cosmin Cojocar <ccojocar@google.com> Co-authored-by: Ben Krieger <ben.krieger@intel.com> Co-authored-by: Cosmin Cojocar <ccojocar@google.com>
2024-09-04 15:09:54 +01:00
package analyzers
import (
"math"
"strconv"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)
var _ = Describe("ParseIntType", func() {
Context("with valid input", func() {
DescribeTable("should correctly parse and calculate bounds for",
func(intType string, expectedSigned bool, expectedSize int, expectedMin int, expectedMax uint) {
result, err := parseIntType(intType)
Expect(err).NotTo(HaveOccurred())
Expect(result.signed).To(Equal(expectedSigned))
Expect(result.size).To(Equal(expectedSize))
Expect(result.min).To(Equal(expectedMin))
Expect(result.max).To(Equal(expectedMax))
},
Entry("uint8", "uint8", false, 8, 0, uint(math.MaxUint8)),
Entry("int8", "int8", true, 8, math.MinInt8, uint(math.MaxInt8)),
Entry("uint16", "uint16", false, 16, 0, uint(math.MaxUint16)),
Entry("int16", "int16", true, 16, math.MinInt16, uint(math.MaxInt16)),
Entry("uint32", "uint32", false, 32, 0, uint(math.MaxUint32)),
Entry("int32", "int32", true, 32, math.MinInt32, uint(math.MaxInt32)),
Entry("uint64", "uint64", false, 64, 0, uint(math.MaxUint64)),
Entry("int64", "int64", true, 64, math.MinInt64, uint(math.MaxInt64)),
)
It("should use system's int size for 'int' and 'uint'", func() {
intResult, err := parseIntType("int")
Expect(err).NotTo(HaveOccurred())
Expect(intResult.size).To(Equal(strconv.IntSize))
uintResult, err := parseIntType("uint")
Expect(err).NotTo(HaveOccurred())
Expect(uintResult.size).To(Equal(strconv.IntSize))
})
})
Context("with invalid input", func() {
DescribeTable("should return an error for",
func(intType string, expectedErrorString string) {
_, err := parseIntType(intType)
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring(expectedErrorString))
},
Entry("empty string", "", "no integer type match found for "),
Entry("invalid type", "float64", "no integer type match found for float64"),
Entry("invalid size", "int65", "invalid bit size: 65"),
Entry("negative size", "int-8", "no integer type match found for int-8"),
Entry("non-numeric size", "intABC", "no integer type match found for intABC"),
)
})
})
var _ = Describe("IsIntOverflow", func() {
DescribeTable("should correctly identify overflow scenarios on a 64-bit system",
func(src string, dst string, expectedOverflow bool) {
result := isIntOverflow(src, dst)
Expect(result).To(Equal(expectedOverflow))
},
// Unsigned to Signed conversions
Entry("uint8 to int8", "uint8", "int8", true),
Entry("uint8 to int16", "uint8", "int16", false),
Entry("uint8 to int32", "uint8", "int32", false),
Entry("uint8 to int64", "uint8", "int64", false),
Entry("uint16 to int8", "uint16", "int8", true),
Entry("uint16 to int16", "uint16", "int16", true),
Entry("uint16 to int32", "uint16", "int32", false),
Entry("uint16 to int64", "uint16", "int64", false),
Entry("uint32 to int8", "uint32", "int8", true),
Entry("uint32 to int16", "uint32", "int16", true),
Entry("uint32 to int32", "uint32", "int32", true),
Entry("uint32 to int64", "uint32", "int64", false),
Entry("uint64 to int8", "uint64", "int8", true),
Entry("uint64 to int16", "uint64", "int16", true),
Entry("uint64 to int32", "uint64", "int32", true),
Entry("uint64 to int64", "uint64", "int64", true),
// Unsigned to Unsigned conversions
Entry("uint8 to uint16", "uint8", "uint16", false),
Entry("uint8 to uint32", "uint8", "uint32", false),
Entry("uint8 to uint64", "uint8", "uint64", false),
Entry("uint16 to uint8", "uint16", "uint8", true),
Entry("uint16 to uint32", "uint16", "uint32", false),
Entry("uint16 to uint64", "uint16", "uint64", false),
Entry("uint32 to uint8", "uint32", "uint8", true),
Entry("uint32 to uint16", "uint32", "uint16", true),
Entry("uint32 to uint64", "uint32", "uint64", false),
Entry("uint64 to uint8", "uint64", "uint8", true),
Entry("uint64 to uint16", "uint64", "uint16", true),
Entry("uint64 to uint32", "uint64", "uint32", true),
// Signed to Unsigned conversions
Entry("int8 to uint8", "int8", "uint8", true),
Entry("int8 to uint16", "int8", "uint16", true),
Entry("int8 to uint32", "int8", "uint32", true),
Entry("int8 to uint64", "int8", "uint64", true),
Entry("int16 to uint8", "int16", "uint8", true),
Entry("int16 to uint16", "int16", "uint16", true),
Entry("int16 to uint32", "int16", "uint32", true),
Entry("int16 to uint64", "int16", "uint64", true),
Entry("int32 to uint8", "int32", "uint8", true),
Entry("int32 to uint16", "int32", "uint16", true),
Entry("int32 to uint32", "int32", "uint32", true),
Entry("int32 to uint64", "int32", "uint64", true),
Entry("int64 to uint8", "int64", "uint8", true),
Entry("int64 to uint16", "int64", "uint16", true),
Entry("int64 to uint32", "int64", "uint32", true),
Entry("int64 to uint64", "int64", "uint64", true),
// Signed to Signed conversions
Entry("int8 to int16", "int8", "int16", false),
Entry("int8 to int32", "int8", "int32", false),
Entry("int8 to int64", "int8", "int64", false),
Entry("int16 to int8", "int16", "int8", true),
Entry("int16 to int32", "int16", "int32", false),
Entry("int16 to int64", "int16", "int64", false),
Entry("int32 to int8", "int32", "int8", true),
Entry("int32 to int16", "int32", "int16", true),
Entry("int32 to int64", "int32", "int64", false),
Entry("int64 to int8", "int64", "int8", true),
Entry("int64 to int16", "int64", "int16", true),
Entry("int64 to int32", "int64", "int32", true),
// Same type conversions (should never overflow)
Entry("uint8 to uint8", "uint8", "uint8", false),
Entry("uint16 to uint16", "uint16", "uint16", false),
Entry("uint32 to uint32", "uint32", "uint32", false),
Entry("uint64 to uint64", "uint64", "uint64", false),
Entry("int8 to int8", "int8", "int8", false),
Entry("int16 to int16", "int16", "int16", false),
Entry("int32 to int32", "int32", "int32", false),
Entry("int64 to int64", "int64", "int64", false),
)
})