Incorrect conversion between integer types¶
ID: go/incorrect-integer-conversion Kind: path-problem Security severity: 8.1 Severity: warning Precision: 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
Click to see the query in the CodeQL repository
If a string is parsed into an int using strconv.Atoi
, and subsequently that int is converted into another integer type of a smaller size, the result can produce unexpected values.
This also applies to the results of strconv.ParseInt
and strconv.ParseUint
when the specified size is larger than the size of the type that number is converted to.
Recommendation¶
If you need to parse integer values with specific bit sizes, avoid strconv.Atoi
, and instead use strconv.ParseInt
or strconv.ParseUint
, which also allow specifying the bit size.
When using those functions, be careful to not convert the result to another type with a smaller bit size than the bit size you specified when parsing the number.
If this is not possible, then add upper (and lower) bound checks specific to each type and bit size (you can find the minimum and maximum value for each type in the math
package).
Note that CodeQL is only able to identify bounds checks that compare against a constant value. When a variable is used in the comparison, CodeQL is unable to determine the value of the variable at runtime and will not recognize the bounds check.
Example¶
In the first example, assume that an input string is passed to parseAllocateBad1
function, parsed by strconv.Atoi
, and then converted into an int32
type:
packagemainimport("strconv")funcparseAllocateBad1(wantedstring)int32{parsed,err:=strconv.Atoi(wanted)iferr!=nil{panic(err)}returnint32(parsed)}funcparseAllocateBad2(wantedstring)int32{parsed,err:=strconv.ParseInt(wanted,10,64)iferr!=nil{panic(err)}returnint32(parsed)}
The bounds are not checked, so this means that if the provided number is greater than the maximum value of type int32
, the resulting value from the conversion will be different from the actual provided value.
To avoid unexpected values, you should either use the other functions provided by the strconv
package to parse the specific types and bit sizes as shown in the parseAllocateGood2
function; or check bounds as in the parseAllocateGood1
function.
packagemainimport("math""strconv")funcmain(){}constDefaultAllocateint32=256funcparseAllocateGood1(desiredstring)int32{parsed,err:=strconv.Atoi(desired)iferr!=nil{returnDefaultAllocate}// GOOD: check for lower and upper boundsifparsed>0&&parsed<=math.MaxInt32{returnint32(parsed)}returnDefaultAllocate}funcparseAllocateGood2(desiredstring)int32{// GOOD: parse specifying the bit sizeparsed,err:=strconv.ParseInt(desired,10,32)iferr!=nil{returnDefaultAllocate}returnint32(parsed)}funcparseAllocateGood3(wantedstring)int32{parsed,err:=strconv.ParseInt(wanted,10,32)iferr!=nil{panic(err)}returnint32(parsed)}funcparseAllocateGood4(wantedstring)int32{parsed,err:=strconv.ParseInt(wanted,10,64)iferr!=nil{panic(err)}// GOOD: check for lower and uppper boundsifparsed>0&&parsed<=math.MaxInt32{returnint32(parsed)}returnDefaultAllocate}
Example¶
In the second example, assume that an input string is passed to parseAllocateBad2
function, parsed by strconv.ParseInt
with a bit size set to 64, and then converted into an int32
type:
packagemainimport("strconv")funcparseAllocateBad1(wantedstring)int32{parsed,err:=strconv.Atoi(wanted)iferr!=nil{panic(err)}returnint32(parsed)}funcparseAllocateBad2(wantedstring)int32{parsed,err:=strconv.ParseInt(wanted,10,64)iferr!=nil{panic(err)}returnint32(parsed)}
If the provided number is greater than the maximum value of type int32
, the resulting value from the conversion will be different from the actual provided value.
To avoid unexpected values, you should specify the correct bit size as in parseAllocateGood3
; or check bounds before making the conversion as in parseAllocateGood4
.
packagemainimport("math""strconv")funcmain(){}constDefaultAllocateint32=256funcparseAllocateGood1(desiredstring)int32{parsed,err:=strconv.Atoi(desired)iferr!=nil{returnDefaultAllocate}// GOOD: check for lower and upper boundsifparsed>0&&parsed<=math.MaxInt32{returnint32(parsed)}returnDefaultAllocate}funcparseAllocateGood2(desiredstring)int32{// GOOD: parse specifying the bit sizeparsed,err:=strconv.ParseInt(desired,10,32)iferr!=nil{returnDefaultAllocate}returnint32(parsed)}funcparseAllocateGood3(wantedstring)int32{parsed,err:=strconv.ParseInt(wanted,10,32)iferr!=nil{panic(err)}returnint32(parsed)}funcparseAllocateGood4(wantedstring)int32{parsed,err:=strconv.ParseInt(wanted,10,64)iferr!=nil{panic(err)}// GOOD: check for lower and uppper boundsifparsed>0&&parsed<=math.MaxInt32{returnint32(parsed)}returnDefaultAllocate}
References¶
Wikipedia Integer overflow.
Go language specification Integer overflow.
Documentation for strconv.Atoi.
Documentation for strconv.ParseInt.
Documentation for strconv.ParseUint.
Common Weakness Enumeration: CWE-190.
Common Weakness Enumeration: CWE-681.