整数类型之间的错误转换¶
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
如果使用 strconv.Atoi
将字符串解析为 int,并且随后将该 int 转换为较小大小的另一种整数类型,则结果可能会产生意外值。
当指定的 size 大于该数字转换到的类型的 size 时,这也适用于 strconv.ParseInt
和 strconv.ParseUint
的结果。
建议¶
如果需要解析具有特定位大小的整数值,请避免使用 strconv.Atoi
,而应使用 strconv.ParseInt
或 strconv.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
}
参考资料¶
维基百科 整数溢出。
Go 语言规范 整数溢出。
strconv.Atoi 的文档。
strconv.ParseInt 的文档。
strconv.ParseUint 的文档。
常见弱点枚举:CWE-190。
常见弱点枚举:CWE-681。