CodeQL 文档

整数类型之间的错误转换

ID: go/incorrect-integer-conversion
Kind: path-problem
Security severity: 8.1
Severity: warning
Precision: very-high
Tags:
   - security
   - external/cwe/cwe-190
   - external/cwe/cwe-681
Query suites:
   - go-code-scanning.qls
   - go-security-extended.qls
   - go-security-and-quality.qls

点击查看 CodeQL 存储库中的查询

如果使用 strconv.Atoi 将字符串解析为 int,并且随后将该 int 转换为较小大小的另一种整数类型,则结果可能会产生意外值。

当指定的 size 大于该数字转换到的类型的 size 时,这也适用于 strconv.ParseIntstrconv.ParseUint 的结果。

建议

如果需要解析具有特定位大小的整数值,请避免使用 strconv.Atoi,而应使用 strconv.ParseIntstrconv.ParseUint,它们也允许指定位大小。

使用这些函数时,请注意不要将结果转换为位大小小于解析数字时指定的位大小的另一种类型。

如果无法做到这一点,则添加特定于每种类型和位大小的上限(和下限)检查(您可以在 math 包中找到每种类型的最小值和最大值)。

示例

在第一个示例中,假设将输入字符串传递给 parseAllocateBad1 函数,由 strconv.Atoi 解析,然后转换为 int32 类型

package main

import (
	"strconv"
)

func parseAllocateBad1(wanted string) int32 {
	parsed, err := strconv.Atoi(wanted)
	if err != nil {
		panic(err)
	}
	return int32(parsed)
}
func parseAllocateBad2(wanted string) int32 {
	parsed, err := strconv.ParseInt(wanted, 10, 64)
	if err != nil {
		panic(err)
	}
	return int32(parsed)
}

未检查边界,因此这意味着如果提供的数字大于 int32 类型的最大值,则转换后的结果值将与实际提供的 值不同。

为了避免意外值,您应该使用 strconv 包提供的其他函数来解析特定的类型和位大小,如 parseAllocateGood2 函数所示;或像 parseAllocateGood1 函数那样检查边界。

package main

import (
	"math"
	"strconv"
)

func main() {

}

const DefaultAllocate int32 = 256

func parseAllocateGood1(desired string) int32 {
	parsed, err := strconv.Atoi(desired)
	if err != nil {
		return DefaultAllocate
	}
	// GOOD: check for lower and upper bounds
	if parsed > 0 && parsed <= math.MaxInt32 {
		return int32(parsed)
	}
	return DefaultAllocate
}
func parseAllocateGood2(desired string) int32 {
	// GOOD: parse specifying the bit size
	parsed, err := strconv.ParseInt(desired, 10, 32)
	if err != nil {
		return DefaultAllocate
	}
	return int32(parsed)
}

func parseAllocateGood3(wanted string) int32 {
	parsed, err := strconv.ParseInt(wanted, 10, 32)
	if err != nil {
		panic(err)
	}
	return int32(parsed)
}
func parseAllocateGood4(wanted string) int32 {
	parsed, err := strconv.ParseInt(wanted, 10, 64)
	if err != nil {
		panic(err)
	}
	// GOOD: check for lower and uppper bounds
	if parsed > 0 && parsed <= math.MaxInt32 {
		return int32(parsed)
	}
	return DefaultAllocate
}

示例

在第二个示例中,假设将输入字符串传递给 parseAllocateBad2 函数,由 strconv.ParseInt 解析,位大小设置为 64,然后转换为 int32 类型

package main

import (
	"strconv"
)

func parseAllocateBad1(wanted string) int32 {
	parsed, err := strconv.Atoi(wanted)
	if err != nil {
		panic(err)
	}
	return int32(parsed)
}
func parseAllocateBad2(wanted string) int32 {
	parsed, err := strconv.ParseInt(wanted, 10, 64)
	if err != nil {
		panic(err)
	}
	return int32(parsed)
}

如果提供的数字大于 int32 类型的最大值,则转换后的结果值将与实际提供的 值不同。

为了避免意外值,您应该像 parseAllocateGood3 中那样指定正确的位大小;或者在进行转换之前检查边界,如 parseAllocateGood4 中所示。

package main

import (
	"math"
	"strconv"
)

func main() {

}

const DefaultAllocate int32 = 256

func parseAllocateGood1(desired string) int32 {
	parsed, err := strconv.Atoi(desired)
	if err != nil {
		return DefaultAllocate
	}
	// GOOD: check for lower and upper bounds
	if parsed > 0 && parsed <= math.MaxInt32 {
		return int32(parsed)
	}
	return DefaultAllocate
}
func parseAllocateGood2(desired string) int32 {
	// GOOD: parse specifying the bit size
	parsed, err := strconv.ParseInt(desired, 10, 32)
	if err != nil {
		return DefaultAllocate
	}
	return int32(parsed)
}

func parseAllocateGood3(wanted string) int32 {
	parsed, err := strconv.ParseInt(wanted, 10, 32)
	if err != nil {
		panic(err)
	}
	return int32(parsed)
}
func parseAllocateGood4(wanted string) int32 {
	parsed, err := strconv.ParseInt(wanted, 10, 64)
	if err != nil {
		panic(err)
	}
	// GOOD: check for lower and uppper bounds
	if parsed > 0 && parsed <= math.MaxInt32 {
		return int32(parsed)
	}
	return DefaultAllocate
}

参考资料

  • ©GitHub 公司
  • 条款
  • 隐私