diff --git a/Makefile b/Makefile index 6290cf67b47..da5040aa151 100644 --- a/Makefile +++ b/Makefile @@ -107,6 +107,7 @@ ql/src/go.dbscheme.stats: ql/src/go.dbscheme build/stats/src.stamp extractor test: all build/testdb/check-upgrade-path codeql test run ql/test --search-path . + env GOARCH=386 codeql$(EXE) test run ql/test/query-tests/Security/CWE-681 --search-path . cd extractor; go test -mod=vendor ./... | grep -vF "[no test files]" .PHONY: build/testdb/check-upgrade-path diff --git a/change-notes/2020-08-05-incorrect-integer-conversion.md b/change-notes/2020-08-05-incorrect-integer-conversion.md new file mode 100644 index 00000000000..258d8427f27 --- /dev/null +++ b/change-notes/2020-08-05-incorrect-integer-conversion.md @@ -0,0 +1,2 @@ +lgtm,codescanning +* Query "Incorrect integer conversion" (`go/incorrect-integer-conversion`) is promoted from experimental status. This checks for parsing a string to an integer and then assigning it to an integer type of a smaller bit size. diff --git a/ql/src/experimental/CWE-681/IncorrectNumericConversion.go b/ql/src/Security/CWE-681/IncorrectIntegerConversion.go similarity index 100% rename from ql/src/experimental/CWE-681/IncorrectNumericConversion.go rename to ql/src/Security/CWE-681/IncorrectIntegerConversion.go diff --git a/ql/src/Security/CWE-681/IncorrectIntegerConversion.qhelp b/ql/src/Security/CWE-681/IncorrectIntegerConversion.qhelp new file mode 100644 index 00000000000..c1e7801dd80 --- /dev/null +++ b/ql/src/Security/CWE-681/IncorrectIntegerConversion.qhelp @@ -0,0 +1,74 @@ + + + +

+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. +

+
+ + +

+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). +

+
+ + +

+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: +

+ +

+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. +

+ +
+ + +

+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: +

+ +

+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. +

+ +
+ +
  • Wikipedia Integer overflow.
  • +
  • Go language specification Integer overflow.
  • +
  • Documentation for strconv.Atoi.
  • +
  • Documentation for strconv.ParseInt.
  • +
  • Documentation for strconv.ParseUint.
  • +
    +
    diff --git a/ql/src/Security/CWE-681/IncorrectIntegerConversion.ql b/ql/src/Security/CWE-681/IncorrectIntegerConversion.ql new file mode 100644 index 00000000000..6a68c41501b --- /dev/null +++ b/ql/src/Security/CWE-681/IncorrectIntegerConversion.ql @@ -0,0 +1,203 @@ +/** + * @name Incorrect conversion between integer types + * @description Converting the result of `strconv.Atoi`, `strconv.ParseInt`, + * and `strconv.ParseUint` to integer types of smaller bit size + * can produce unexpected values. + * @kind path-problem + * @problem.severity warning + * @id go/incorrect-integer-conversion + * @tags security + * external/cwe/cwe-190 + * external/cwe/cwe-681 + * @precision very-high + */ + +import go +import DataFlow::PathGraph + +/** + * Gets the maximum value of an integer (signed if `isSigned` + * is true, unsigned otherwise) with `bitSize` bits. + */ +float getMaxIntValue(int bitSize, boolean isSigned) { + bitSize in [8, 16, 32] and + ( + isSigned = true and result = 2.pow(bitSize - 1) - 1 + or + isSigned = false and result = 2.pow(bitSize) - 1 + ) +} + +/** + * Get the size of `int` or `uint` in `file`, or 0 if it is + * architecture-specific. + */ +int getIntTypeBitSize(File file) { + file.constrainsIntBitSize(result) + or + not file.constrainsIntBitSize(_) and + result = 0 +} + +/** + * Holds if converting from an integer types with size `sourceBitSize` to + * one with size `sinkBitSize` can produce unexpected values, where 0 means + * architecture-dependent. + * + * Architecture-dependent bit sizes can be 32 or 64. To catch flows that + * only manifest on 64-bit architectures we consider an + * architecture-dependent source bit size to be 64. To catch flows that + * only happen on 32-bit architectures we consider an + * architecture-dependent sink bit size to be 32. We exclude the case where + * both source and sink have architecture-dependent bit sizes. + */ +private predicate isIncorrectIntegerConversion(int sourceBitSize, int sinkBitSize) { + sourceBitSize in [16, 32, 64] and + sinkBitSize in [8, 16, 32] and + sourceBitSize > sinkBitSize + or + // Treat `sourceBitSize = 0` like `sourceBitSize = 64`, and exclude `sinkBitSize = 0` + sourceBitSize = 0 and + sinkBitSize in [8, 16, 32] + or + // Treat `sinkBitSize = 0` like `sinkBitSize = 32`, and exclude `sourceBitSize = 0` + sourceBitSize = 64 and + sinkBitSize = 0 +} + +/** + * A taint-tracking configuration for reasoning about when an integer + * obtained from parsing a string flows to a type conversion to a smaller + * integer types, which could cause unexpected values. + */ +class ConversionWithoutBoundsCheckConfig extends TaintTracking::Configuration { + boolean sourceIsSigned; + int sourceBitSize; + int sinkBitSize; + + ConversionWithoutBoundsCheckConfig() { + sourceIsSigned in [true, false] and + isIncorrectIntegerConversion(sourceBitSize, sinkBitSize) and + this = "ConversionWithoutBoundsCheckConfig" + sourceBitSize + sourceIsSigned + sinkBitSize + } + + /** Gets the bit size of the source. */ + int getSourceBitSize() { result = sourceBitSize } + + override predicate isSource(DataFlow::Node source) { + exists( + DataFlow::CallNode c, IntegerParser::Range ip, int apparentBitSize, int effectiveBitSize + | + c.getTarget() = ip and source = c.getResult(0) + | + ( + if ip.getResultType(0) instanceof SignedIntegerType + then sourceIsSigned = true + else sourceIsSigned = false + ) and + ( + apparentBitSize = ip.getTargetBitSize() + or + // If we are reading a variable, check if it is + // `strconv.IntSize`, and use 0 if it is. + exists(DataFlow::Node rawBitSize | rawBitSize = ip.getTargetBitSizeInput().getNode(c) | + if rawBitSize = any(StrConv::IntSize intSize).getARead() + then apparentBitSize = 0 + else apparentBitSize = rawBitSize.getIntValue() + ) + ) and + ( + if apparentBitSize = 0 + then effectiveBitSize = getIntTypeBitSize(source.getFile()) + else effectiveBitSize = apparentBitSize + ) and + // `effectiveBitSize` could be any value between 0 and 64, but we + // can round it up to the nearest size of an integer type without + // changing behaviour. + sourceBitSize = min(int b | b in [0, 8, 16, 32, 64] and b >= effectiveBitSize) + ) + } + + /** + * Holds if `sink` is a typecast to an integer type with size `bitSize` (where + * 0 represents architecture-dependent) and the expression being typecast is + * not also in a right-shift expression. We allow this case because it is + * a common pattern to serialise `byte(v)`, `byte(v >> 8)`, and so on. + */ + predicate isSink(DataFlow::TypeCastNode sink, int bitSize) { + exists(IntegerType integerType | sink.getType().getUnderlyingType() = integerType | + bitSize = integerType.getSize() + or + not exists(integerType.getSize()) and + bitSize = getIntTypeBitSize(sink.getFile()) + ) and + not exists(ShrExpr shrExpr | + shrExpr.getLeftOperand().getGlobalValueNumber() = + sink.getOperand().asExpr().getGlobalValueNumber() or + shrExpr.getLeftOperand().(AndExpr).getAnOperand().getGlobalValueNumber() = + sink.getOperand().asExpr().getGlobalValueNumber() + ) + } + + override predicate isSink(DataFlow::Node sink) { isSink(sink, sinkBitSize) } + + override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { + // To catch flows that only happen on 32-bit architectures we + // consider an architecture-dependent sink bit size to be 32. + exists(int bitSize | if sinkBitSize != 0 then bitSize = sinkBitSize else bitSize = 32 | + guard.(UpperBoundCheckGuard).getBound() <= getMaxIntValue(bitSize, sourceIsSigned) + ) + } + + override predicate isSanitizerOut(DataFlow::Node node) { + exists(int bitSize | isIncorrectIntegerConversion(sourceBitSize, bitSize) | + isSink(node, bitSize) + ) + } +} + +/** An upper bound check that compares a variable to a constant value. */ +class UpperBoundCheckGuard extends DataFlow::BarrierGuard, DataFlow::RelationalComparisonNode { + UpperBoundCheckGuard() { count(expr.getAnOperand().getIntValue()) = 1 } + + /** + * Gets the constant value which this upper bound check ensures the + * other value is less than or equal to. + */ + float getBound() { + exists(int strictnessOffset | + if expr.isStrict() then strictnessOffset = 1 else strictnessOffset = 0 + | + result = expr.getAnOperand().getExactValue().toFloat() - strictnessOffset + ) + } + + override predicate checks(Expr e, boolean branch) { + this.leq(branch, DataFlow::exprNode(e), _, _) and + not exists(e.getIntValue()) + } +} + +/** Gets a string describing the size of the integer parsed. */ +string describeBitSize(int bitSize, int intTypeBitSize) { + intTypeBitSize in [0, 32, 64] and + if bitSize != 0 + then bitSize in [8, 16, 32, 64] and result = "a " + bitSize + "-bit integer" + else + if intTypeBitSize = 0 + then result = "an integer with architecture-dependent bit size" + else + result = + "a number with architecture-dependent bit-width, which is constrained to be " + + intTypeBitSize + "-bit by build constraints," +} + +from + DataFlow::PathNode source, DataFlow::PathNode sink, ConversionWithoutBoundsCheckConfig cfg, + DataFlow::CallNode call +where cfg.hasFlowPath(source, sink) and call.getResult(0) = source.getNode() +select sink.getNode(), source, sink, + "Incorrect conversion of " + + describeBitSize(cfg.getSourceBitSize(), getIntTypeBitSize(source.getNode().getFile())) + + " from $@ to a lower bit size type " + sink.getNode().getType().getUnderlyingType().getName() + + " without an upper bound check.", source, call.getTarget().getQualifiedName() diff --git a/ql/src/experimental/CWE-681/IncorrectNumericConversionGood.go b/ql/src/Security/CWE-681/IncorrectIntegerConversionGood.go similarity index 95% rename from ql/src/experimental/CWE-681/IncorrectNumericConversionGood.go rename to ql/src/Security/CWE-681/IncorrectIntegerConversionGood.go index 29c111cf54e..9227b2bf143 100644 --- a/ql/src/experimental/CWE-681/IncorrectNumericConversionGood.go +++ b/ql/src/Security/CWE-681/IncorrectIntegerConversionGood.go @@ -16,7 +16,7 @@ func parseAllocateGood1(desired string) int32 { if err != nil { return DefaultAllocate } - // GOOD: check for lower and uppper bounds + // GOOD: check for lower and upper bounds if parsed > 0 && parsed <= math.MaxInt32 { return int32(parsed) } diff --git a/ql/src/experimental/CWE-681/IncorrectNumericConversion.qhelp b/ql/src/experimental/CWE-681/IncorrectNumericConversion.qhelp deleted file mode 100644 index f978858ed89..00000000000 --- a/ql/src/experimental/CWE-681/IncorrectNumericConversion.qhelp +++ /dev/null @@ -1,65 +0,0 @@ - - - -

    - If a numeric value string is parsed using strconv.Atoi into an int, and subsequently that int - is converted into another type of a smaller size, the result can produce unexpected values. -

    -

    - This also applies to the results of strconv.ParseFloat, strconv.ParseInt, - and strconv.ParseUint when the specified size is larger than the size of the - type that number is converted to. -

    -
    - -

    - If you need to parse numeric values with specific bit sizes, avoid strconv.Atoi, and instead - use the functions specific to each type (strconv.ParseFloat, strconv.ParseInt, - strconv.ParseUint) that also allow to specify the wanted 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). -

    -
    - -

    - 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: -

    - -

    - 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. -

    - -
    - -

    - 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: -

    - -

    - 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. -

    - -
    -
    diff --git a/ql/src/experimental/CWE-681/IncorrectNumericConversion.ql b/ql/src/experimental/CWE-681/IncorrectNumericConversion.ql deleted file mode 100644 index def77b696e9..00000000000 --- a/ql/src/experimental/CWE-681/IncorrectNumericConversion.ql +++ /dev/null @@ -1,266 +0,0 @@ -/** - * @name Incorrect conversion between numeric types - * @description Converting the result of strconv.Atoi (and other parsers from strconv package) - * to numeric types of smaller bit size can produce unexpected values. - * @kind path-problem - * @problem.severity warning - * @id go/incorrect-numeric-conversion - * @tags security - * external/cwe/cwe-190 - * external/cwe/cwe-681 - */ - -import go -import DataFlow::PathGraph - -/** A function that parses integers. */ -class Atoi extends Function { - Atoi() { this.hasQualifiedName("strconv", "Atoi") } -} - -/** A function that parses floating-point numbers. */ -class ParseFloat extends Function { - ParseFloat() { this.hasQualifiedName("strconv", "ParseFloat") } -} - -/** A function that parses integers with a specifiable bitSize. */ -class ParseInt extends Function { - ParseInt() { this.hasQualifiedName("strconv", "ParseInt") } -} - -/** A function that parses unsigned integers with a specifiable bitSize. */ -class ParseUint extends Function { - ParseUint() { this.hasQualifiedName("strconv", "ParseUint") } -} - -/** Provides a class for modeling calls to number-parsing functions. */ -module ParserCall { - /** - * A data-flow call node that parses a number. - */ - abstract class Range extends DataFlow::CallNode { - /** Gets the bit size of the result number. */ - abstract int getTargetBitSize(); - - /** Gets the name of the parser function. */ - abstract string getParserName(); - } -} - -class ParserCall extends DataFlow::CallNode { - ParserCall::Range self; - - ParserCall() { this = self } - - int getTargetBitSize() { result = self.getTargetBitSize() } - - string getParserName() { result = self.getParserName() } -} - -class AtoiCall extends DataFlow::CallNode, ParserCall::Range { - AtoiCall() { exists(Atoi atoi | this = atoi.getACall()) } - - override int getTargetBitSize() { result = 0 } - - override string getParserName() { result = "strconv.Atoi" } -} - -class ParseIntCall extends DataFlow::CallNode, ParserCall::Range { - ParseIntCall() { exists(ParseInt parseInt | this = parseInt.getACall()) } - - override int getTargetBitSize() { result = this.getArgument(2).getIntValue() } - - override string getParserName() { result = "strconv.ParseInt" } -} - -class ParseUintCall extends DataFlow::CallNode, ParserCall::Range { - ParseUintCall() { exists(ParseUint parseUint | this = parseUint.getACall()) } - - override int getTargetBitSize() { result = this.getArgument(2).getIntValue() } - - override string getParserName() { result = "strconv.ParseUint" } -} - -class ParseFloatCall extends DataFlow::CallNode, ParserCall::Range { - ParseFloatCall() { exists(ParseFloat parseFloat | this = parseFloat.getACall()) } - - override int getTargetBitSize() { result = this.getArgument(1).getIntValue() } - - override string getParserName() { result = "strconv.ParseFloat" } -} - -class NumericConversionExpr extends ConversionExpr { - string fullTypeName; - int bitSize; - - NumericConversionExpr() { - exists(NumericType conv | - conv = getTypeExpr().getType().getUnderlyingType() and - fullTypeName = conv.getName() and - bitSize = conv.getSize() - ) - } - - string getFullTypeName() { result = fullTypeName } - - int getBitSize() { result = bitSize } -} - -/** - * An `if` statement with the condition being either a relational comparison, - * or one or more `&&`. - */ -class IfRelationalComparison extends IfStmt { - IfRelationalComparison() { - this.getCond() instanceof RelationalComparisonExpr or this.getCond() instanceof LandExpr - } - - RelationalComparisonExpr getComparison() { result = this.getCond().(RelationalComparisonExpr) } - - LandExpr getLandExpr() { result = this.getCond().(LandExpr) } -} - -/** - * Flow of result of parsing a 64 bit number, to conversion to lower bit numbers. - */ -class Lt64BitFlowConfig extends TaintTracking::Configuration, DataFlow::Configuration { - Lt64BitFlowConfig() { this = "Lt64BitFlowConfig" } - - override predicate isSource(DataFlow::Node source) { - exists(ParserCall call | call.getTargetBitSize() = [0, 64] | source = call) - } - - override predicate isSink(DataFlow::Node sink) { - exists(NumericConversionExpr conv | conv.getBitSize() = [32, 16, 8] | sink.asExpr() = conv) - } - - override predicate isSanitizerIn(DataFlow::Node node) { isSanitizedInsideAnIfBoundCheck(node) } -} - -/** - * Flow of result of parsing a 32 bit number, to conversion to lower bit numbers. - */ -class Lt32BitFlowConfig extends TaintTracking::Configuration, DataFlow::Configuration { - Lt32BitFlowConfig() { this = "Lt32BitFlowConfig" } - - override predicate isSource(DataFlow::Node source) { - // NOTE: target bit size 0 is already addressed in Lt64BitFlowConfig. - exists(ParserCall call | call.getTargetBitSize() = [/*0,*/ 32] | source = call) - } - - override predicate isSink(DataFlow::Node sink) { - exists(NumericConversionExpr conv | conv.getBitSize() = [16, 8] | sink.asExpr() = conv) - } - - override predicate isSanitizerIn(DataFlow::Node node) { isSanitizedInsideAnIfBoundCheck(node) } -} - -/** - * Flow of result of parsing a 16 bit number, to conversion to lower bit numbers. - */ -class Lt16BitFlowConfig extends TaintTracking::Configuration, DataFlow::Configuration { - Lt16BitFlowConfig() { this = "Lt16BitFlowConfig" } - - override predicate isSource(DataFlow::Node source) { - exists(ParserCall call | call.getTargetBitSize() = 16 | source = call) - } - - override predicate isSink(DataFlow::Node sink) { - exists(NumericConversionExpr conv | conv.getBitSize() = 8 | sink.asExpr() = conv) - } - - override predicate isSanitizerIn(DataFlow::Node node) { isSanitizedInsideAnIfBoundCheck(node) } -} - -/** - * Check if the node is a numeric conversion inside an `if` body, where - * the `if` condition contains an upper bound check on the conversion operand. - */ -predicate isSanitizedInsideAnIfBoundCheck(DataFlow::Node node) { - exists(IfRelationalComparison comp, NumericConversionExpr conv | - conv = node.asExpr().(NumericConversionExpr) and - conv.getBitSize() = [8, 16, 32] and - comp.getThen().getAChild*() = conv and - ( - // If the conversion is inside an `if` block that compares the source as - // `source > 0` or `source >= 0`, then that sanitizes conversion of int to int32; - conv.getFullTypeName() = "int32" and - comp.getComparison().getLesserOperand().getNumericValue() = 0 and - comp.getComparison().getGreaterOperand().getGlobalValueNumber() = - conv.getOperand().getGlobalValueNumber() - or - comparisonGreaterOperandValueIsEqual("int8", comp, conv, getMaxInt8()) - or - comparisonGreaterOperandValueIsEqual("int16", comp, conv, getMaxInt16()) - or - comparisonGreaterOperandValueIsEqual("int32", comp, conv, getMaxInt32()) - or - comparisonGreaterOperandValueIsEqual("uint8", comp, conv, getMaxUint8()) - or - comparisonGreaterOperandValueIsEqual("uint16", comp, conv, getMaxUint16()) - ) - ) -} - -int getMaxInt8() { result = 2.pow(7) - 1 } - -int getMaxInt16() { result = 2.pow(15) - 1 } - -int getMaxInt32() { result = 2.pow(31) - 1 } - -int getMaxUint8() { result = 2.pow(8) - 1 } - -int getMaxUint16() { result = 2.pow(16) - 1 } - -/** - * The `if` relational comparison (which can also be inside a `LandExpr`) stating that - * the greater operand is equal to `value`, and the lesses operand is the conversion operand. - */ -predicate comparisonGreaterOperandValueIsEqual( - string typeName, IfRelationalComparison ifExpr, NumericConversionExpr conv, int value -) { - conv.getFullTypeName() = typeName and - ( - // exclude cases like: if parsed < math.MaxInt8 {return int8(parsed)} - exists(RelationalComparisonExpr comp | comp = ifExpr.getComparison() | - // greater operand is equal to value: - comp.getGreaterOperand().getNumericValue() = value and - // and lesser is the conversion operand: - comp.getLesserOperand().getGlobalValueNumber() = conv.getOperand().getGlobalValueNumber() - ) - or - // exclude cases like: if err == nil && parsed < math.MaxInt8 {return int8(parsed)} - exists(RelationalComparisonExpr andExpr | - andExpr = ifExpr.getLandExpr().getAnOperand().(RelationalComparisonExpr) - | - // greater operand is equal to value: - andExpr.getGreaterOperand().getNumericValue() = value and - // and lesser is the conversion operand: - andExpr.getLesserOperand().getGlobalValueNumber() = conv.getOperand().getGlobalValueNumber() - ) - ) -} - -string formatBitSize(ParserCall call) { - call.getTargetBitSize() = 0 and result = "(arch-dependent)" - or - call.getTargetBitSize() > 0 and result = call.getTargetBitSize().toString() -} - -from DataFlow::PathNode source, DataFlow::PathNode sink -where - ( - exists(Lt64BitFlowConfig cfg | cfg.hasFlowPath(source, sink)) - or - exists(Lt32BitFlowConfig cfg | cfg.hasFlowPath(source, sink)) - or - exists(Lt16BitFlowConfig cfg | cfg.hasFlowPath(source, sink)) - ) and - // Exclude results in test files: - exists(File fl | fl = sink.getNode().asExpr().(NumericConversionExpr).getFile() | - not fl instanceof TestFile - ) -select source.getNode(), source, sink, - "Incorrect conversion of a " + formatBitSize(source.getNode().(ParserCall)) + "-bit number from " + - source.getNode().(ParserCall).getParserName() + " result to a lower bit size type " + - sink.getNode().asExpr().(NumericConversionExpr).getFullTypeName() diff --git a/ql/src/go.qll b/ql/src/go.qll index 0f497ac8c31..4a5f9186902 100644 --- a/ql/src/go.qll +++ b/ql/src/go.qll @@ -3,6 +3,7 @@ */ import Customizations +import semmle.go.Architectures import semmle.go.AST import semmle.go.Comments import semmle.go.Concepts diff --git a/ql/src/semmle/go/Architectures.qll b/ql/src/semmle/go/Architectures.qll new file mode 100644 index 00000000000..c2ea35acc4c --- /dev/null +++ b/ql/src/semmle/go/Architectures.qll @@ -0,0 +1,27 @@ +/** Provides classes for working with architectures. */ + +import go + +/** + * An architecture that is valid in a build constraint. + * + * Information obtained from + * https://github.com/golang/go/blob/98cbf45cfc6a5a50cc6ac2367f9572cb198b57c7/src/go/types/gccgosizes.go + * where the first field of the struct is 4 for 32-bit architectures + * and 8 for 64-bit architectures. + */ +class Architecture extends string { + int bitSize; + + Architecture() { + this in ["386", "amd64p32", "arm", "armbe", "mips", "mipsle", "mips64p32", "mips64p32le", "ppc", + "s390", "sparc"] and + bitSize = 32 + or + this in ["amd64", "arm64", "arm64be", "ppc64", "ppc64le", "mips64", "mips64le", "s390x", + "sparc64"] and + bitSize = 64 + } + + int getBitSize() { result = bitSize } +} diff --git a/ql/src/semmle/go/Comments.qll b/ql/src/semmle/go/Comments.qll index 3dce789efba..2a765c5e972 100644 --- a/ql/src/semmle/go/Comments.qll +++ b/ql/src/semmle/go/Comments.qll @@ -211,4 +211,10 @@ class BuildConstraintComment extends LineComment { } override string getAPrimaryQlClass() { result = "BuildConstraintComment" } + + /** Gets the body of this build constraint. */ + string getConstraintBody() { result = getText().splitAt("+build ", 1) } + + /** Gets a disjunct of this build constraint. */ + string getADisjunct() { result = getConstraintBody().splitAt(" ") } } diff --git a/ql/src/semmle/go/Files.qll b/ql/src/semmle/go/Files.qll index e157b80c9b6..7bf684cb9c7 100644 --- a/ql/src/semmle/go/Files.qll +++ b/ql/src/semmle/go/Files.qll @@ -203,6 +203,40 @@ class File extends Container, @file, Documentable, ExprParent, GoModExprParent, pragma[noinline] predicate hasBuildConstraints() { exists(BuildConstraintComment bc | this = bc.getFile()) } + /** + * Holds if this file contains build constraints that ensure that it + * is only built on architectures of bit size `bitSize`, which can be + * 32 or 64. + */ + predicate constrainsIntBitSize(int bitSize) { + explicitlyConstrainsIntBitSize(bitSize) or + implicitlyConstrainsIntBitSize(bitSize) + } + + /** + * Holds if this file contains explicit build constraints that ensure + * that it is only built on an architecture of bit size `bitSize`, + * which can be 32 or 64. + */ + predicate explicitlyConstrainsIntBitSize(int bitSize) { + exists(BuildConstraintComment bcc | this = bcc.getFile() | + forex(string disjunct | disjunct = bcc.getADisjunct() | + disjunct.splitAt(",").(Architecture).getBitSize() = bitSize + ) + ) + } + + /** + * Holds if this file has a name which acts as an implicit build + * constraint that ensures that it is only built on an + * architecture of bit size `bitSize`, which can be 32 or 64. + */ + predicate implicitlyConstrainsIntBitSize(int bitSize) { + exists(Architecture arch | arch.getBitSize() = bitSize | + this.getStem().regexpMatch("(?i).*_\\Q" + arch + "\\E(_test)?") + ) + } + override string toString() { result = Container.super.toString() } /** Gets the URL of this file. */ diff --git a/ql/src/semmle/go/controlflow/ControlFlowGraph.qll b/ql/src/semmle/go/controlflow/ControlFlowGraph.qll index abf5eab4682..caca0adea41 100644 --- a/ql/src/semmle/go/controlflow/ControlFlowGraph.qll +++ b/ql/src/semmle/go/controlflow/ControlFlowGraph.qll @@ -168,7 +168,7 @@ module ControlFlow { } /** - * A control-flow node recording the fact that a certain expression is has a known + * A control-flow node recording the fact that a certain expression has a known * Boolean value at this point in the program. */ class ConditionGuardNode extends IR::Instruction, MkConditionGuardNode { diff --git a/ql/src/semmle/go/frameworks/Stdlib.qll b/ql/src/semmle/go/frameworks/Stdlib.qll index 542535873b3..3f86b238cf0 100644 --- a/ql/src/semmle/go/frameworks/Stdlib.qll +++ b/ql/src/semmle/go/frameworks/Stdlib.qll @@ -512,6 +512,65 @@ module Path { } } +/** Provides a class for modeling functions which convert strings into integers. */ +module IntegerParser { + /** + * A function that converts strings into integers. + * + * Extend this class to model new APIs. If you want to refine existing API models, + * extend `IntegerParser` instead. + */ + abstract class Range extends Function { + /** + * Gets the maximum bit size of the return value, if this makes + * sense, where 0 represents the bit size of `int` and `uint`. + */ + int getTargetBitSize() { none() } + + /** + * Gets the `FunctionInput` containing the maximum bit size of the + * return value, if this makes sense. Note that if the value of the + * input is 0 then it means the bit size of `int` and `uint`. + */ + FunctionInput getTargetBitSizeInput() { none() } + } +} + +/** + * Provides classes for some functions in the `strconv` package for + * converting strings to numbers. + */ +module StrConv { + /** The `Atoi` function. */ + class Atoi extends IntegerParser::Range { + Atoi() { this.hasQualifiedName("strconv", "Atoi") } + + override int getTargetBitSize() { result = 0 } + } + + /** The `ParseInt` function. */ + class ParseInt extends IntegerParser::Range { + ParseInt() { this.hasQualifiedName("strconv", "ParseInt") } + + override FunctionInput getTargetBitSizeInput() { result.isParameter(2) } + } + + /** The `ParseUint` function. */ + class ParseUint extends IntegerParser::Range { + ParseUint() { this.hasQualifiedName("strconv", "ParseUint") } + + override FunctionInput getTargetBitSizeInput() { result.isParameter(2) } + } + + /** + * The `IntSize` constant, that gives the size in bits of an `int` or + * `uint` value on the current architecture (32 or 64). + */ + class IntSize extends DeclaredConstant { + IntSize() { this.hasQualifiedName("strconv", "IntSize") } + } +} + /** Provides models of commonly used functions in the `strings` package. */ module Strings { /** The `Join` function. */ diff --git a/ql/test/experimental/CWE-681/IncorrectNumericConversion.expected b/ql/test/experimental/CWE-681/IncorrectNumericConversion.expected deleted file mode 100644 index 64aa194012e..00000000000 --- a/ql/test/experimental/CWE-681/IncorrectNumericConversion.expected +++ /dev/null @@ -1,83 +0,0 @@ -edges -| IncorrectNumericConversion.go:26:14:26:28 | call to Atoi : tuple type | IncorrectNumericConversion.go:35:41:35:50 | type conversion | -| IncorrectNumericConversion.go:53:18:53:47 | call to ParseFloat : tuple type | IncorrectNumericConversion.go:57:7:57:19 | type conversion | -| IncorrectNumericConversion.go:60:18:60:47 | call to ParseFloat : tuple type | IncorrectNumericConversion.go:64:7:64:19 | type conversion | -| IncorrectNumericConversion.go:69:18:69:49 | call to ParseInt : tuple type | IncorrectNumericConversion.go:73:7:73:18 | type conversion | -| IncorrectNumericConversion.go:76:18:76:49 | call to ParseInt : tuple type | IncorrectNumericConversion.go:80:7:80:19 | type conversion | -| IncorrectNumericConversion.go:83:18:83:49 | call to ParseInt : tuple type | IncorrectNumericConversion.go:87:7:87:19 | type conversion | -| IncorrectNumericConversion.go:90:18:90:48 | call to ParseInt : tuple type | IncorrectNumericConversion.go:94:7:94:19 | type conversion | -| IncorrectNumericConversion.go:99:18:99:50 | call to ParseUint : tuple type | IncorrectNumericConversion.go:103:7:103:18 | type conversion | -| IncorrectNumericConversion.go:106:18:106:50 | call to ParseUint : tuple type | IncorrectNumericConversion.go:110:7:110:19 | type conversion | -| IncorrectNumericConversion.go:113:18:113:50 | call to ParseUint : tuple type | IncorrectNumericConversion.go:117:7:117:19 | type conversion | -| IncorrectNumericConversion.go:120:18:120:49 | call to ParseUint : tuple type | IncorrectNumericConversion.go:124:7:124:19 | type conversion | -| IncorrectNumericConversion.go:208:18:208:36 | call to Atoi : tuple type | IncorrectNumericConversion.go:212:7:212:18 | type conversion | -| IncorrectNumericConversion.go:215:18:215:36 | call to Atoi : tuple type | IncorrectNumericConversion.go:219:7:219:19 | type conversion | -| IncorrectNumericConversion.go:222:18:222:36 | call to Atoi : tuple type | IncorrectNumericConversion.go:226:7:226:19 | type conversion | -| IncorrectNumericConversion.go:229:18:229:36 | call to Atoi : tuple type | IncorrectNumericConversion.go:233:7:233:19 | type conversion | -| IncorrectNumericConversion.go:236:18:236:36 | call to Atoi : tuple type | IncorrectNumericConversion.go:240:7:240:20 | type conversion | -| IncorrectNumericConversion.go:243:18:243:36 | call to Atoi : tuple type | IncorrectNumericConversion.go:247:7:247:20 | type conversion | -| IncorrectNumericConversion.go:250:18:250:36 | call to Atoi : tuple type | IncorrectNumericConversion.go:254:7:254:21 | type conversion | -| IncorrectNumericConversion.go:257:18:257:36 | call to Atoi : tuple type | IncorrectNumericConversion.go:262:7:262:18 | type conversion | -| IncorrectNumericConversion.go:266:18:266:36 | call to Atoi : tuple type | IncorrectNumericConversion.go:270:7:270:23 | type conversion | -nodes -| IncorrectNumericConversion.go:26:14:26:28 | call to Atoi : tuple type | semmle.label | call to Atoi : tuple type | -| IncorrectNumericConversion.go:35:41:35:50 | type conversion | semmle.label | type conversion | -| IncorrectNumericConversion.go:53:18:53:47 | call to ParseFloat : tuple type | semmle.label | call to ParseFloat : tuple type | -| IncorrectNumericConversion.go:57:7:57:19 | type conversion | semmle.label | type conversion | -| IncorrectNumericConversion.go:60:18:60:47 | call to ParseFloat : tuple type | semmle.label | call to ParseFloat : tuple type | -| IncorrectNumericConversion.go:64:7:64:19 | type conversion | semmle.label | type conversion | -| IncorrectNumericConversion.go:69:18:69:49 | call to ParseInt : tuple type | semmle.label | call to ParseInt : tuple type | -| IncorrectNumericConversion.go:73:7:73:18 | type conversion | semmle.label | type conversion | -| IncorrectNumericConversion.go:76:18:76:49 | call to ParseInt : tuple type | semmle.label | call to ParseInt : tuple type | -| IncorrectNumericConversion.go:80:7:80:19 | type conversion | semmle.label | type conversion | -| IncorrectNumericConversion.go:83:18:83:49 | call to ParseInt : tuple type | semmle.label | call to ParseInt : tuple type | -| IncorrectNumericConversion.go:87:7:87:19 | type conversion | semmle.label | type conversion | -| IncorrectNumericConversion.go:90:18:90:48 | call to ParseInt : tuple type | semmle.label | call to ParseInt : tuple type | -| IncorrectNumericConversion.go:94:7:94:19 | type conversion | semmle.label | type conversion | -| IncorrectNumericConversion.go:99:18:99:50 | call to ParseUint : tuple type | semmle.label | call to ParseUint : tuple type | -| IncorrectNumericConversion.go:103:7:103:18 | type conversion | semmle.label | type conversion | -| IncorrectNumericConversion.go:106:18:106:50 | call to ParseUint : tuple type | semmle.label | call to ParseUint : tuple type | -| IncorrectNumericConversion.go:110:7:110:19 | type conversion | semmle.label | type conversion | -| IncorrectNumericConversion.go:113:18:113:50 | call to ParseUint : tuple type | semmle.label | call to ParseUint : tuple type | -| IncorrectNumericConversion.go:117:7:117:19 | type conversion | semmle.label | type conversion | -| IncorrectNumericConversion.go:120:18:120:49 | call to ParseUint : tuple type | semmle.label | call to ParseUint : tuple type | -| IncorrectNumericConversion.go:124:7:124:19 | type conversion | semmle.label | type conversion | -| IncorrectNumericConversion.go:208:18:208:36 | call to Atoi : tuple type | semmle.label | call to Atoi : tuple type | -| IncorrectNumericConversion.go:212:7:212:18 | type conversion | semmle.label | type conversion | -| IncorrectNumericConversion.go:215:18:215:36 | call to Atoi : tuple type | semmle.label | call to Atoi : tuple type | -| IncorrectNumericConversion.go:219:7:219:19 | type conversion | semmle.label | type conversion | -| IncorrectNumericConversion.go:222:18:222:36 | call to Atoi : tuple type | semmle.label | call to Atoi : tuple type | -| IncorrectNumericConversion.go:226:7:226:19 | type conversion | semmle.label | type conversion | -| IncorrectNumericConversion.go:229:18:229:36 | call to Atoi : tuple type | semmle.label | call to Atoi : tuple type | -| IncorrectNumericConversion.go:233:7:233:19 | type conversion | semmle.label | type conversion | -| IncorrectNumericConversion.go:236:18:236:36 | call to Atoi : tuple type | semmle.label | call to Atoi : tuple type | -| IncorrectNumericConversion.go:240:7:240:20 | type conversion | semmle.label | type conversion | -| IncorrectNumericConversion.go:243:18:243:36 | call to Atoi : tuple type | semmle.label | call to Atoi : tuple type | -| IncorrectNumericConversion.go:247:7:247:20 | type conversion | semmle.label | type conversion | -| IncorrectNumericConversion.go:250:18:250:36 | call to Atoi : tuple type | semmle.label | call to Atoi : tuple type | -| IncorrectNumericConversion.go:254:7:254:21 | type conversion | semmle.label | type conversion | -| IncorrectNumericConversion.go:257:18:257:36 | call to Atoi : tuple type | semmle.label | call to Atoi : tuple type | -| IncorrectNumericConversion.go:262:7:262:18 | type conversion | semmle.label | type conversion | -| IncorrectNumericConversion.go:266:18:266:36 | call to Atoi : tuple type | semmle.label | call to Atoi : tuple type | -| IncorrectNumericConversion.go:270:7:270:23 | type conversion | semmle.label | type conversion | -#select -| IncorrectNumericConversion.go:26:14:26:28 | call to Atoi | IncorrectNumericConversion.go:26:14:26:28 | call to Atoi : tuple type | IncorrectNumericConversion.go:35:41:35:50 | type conversion | Incorrect conversion of a (arch-dependent)-bit number from strconv.Atoi result to a lower bit size type int32 | -| IncorrectNumericConversion.go:53:18:53:47 | call to ParseFloat | IncorrectNumericConversion.go:53:18:53:47 | call to ParseFloat : tuple type | IncorrectNumericConversion.go:57:7:57:19 | type conversion | Incorrect conversion of a 32-bit number from strconv.ParseFloat result to a lower bit size type int16 | -| IncorrectNumericConversion.go:60:18:60:47 | call to ParseFloat | IncorrectNumericConversion.go:60:18:60:47 | call to ParseFloat : tuple type | IncorrectNumericConversion.go:64:7:64:19 | type conversion | Incorrect conversion of a 64-bit number from strconv.ParseFloat result to a lower bit size type int32 | -| IncorrectNumericConversion.go:69:18:69:49 | call to ParseInt | IncorrectNumericConversion.go:69:18:69:49 | call to ParseInt : tuple type | IncorrectNumericConversion.go:73:7:73:18 | type conversion | Incorrect conversion of a 16-bit number from strconv.ParseInt result to a lower bit size type int8 | -| IncorrectNumericConversion.go:76:18:76:49 | call to ParseInt | IncorrectNumericConversion.go:76:18:76:49 | call to ParseInt : tuple type | IncorrectNumericConversion.go:80:7:80:19 | type conversion | Incorrect conversion of a 32-bit number from strconv.ParseInt result to a lower bit size type int16 | -| IncorrectNumericConversion.go:83:18:83:49 | call to ParseInt | IncorrectNumericConversion.go:83:18:83:49 | call to ParseInt : tuple type | IncorrectNumericConversion.go:87:7:87:19 | type conversion | Incorrect conversion of a 64-bit number from strconv.ParseInt result to a lower bit size type int32 | -| IncorrectNumericConversion.go:90:18:90:48 | call to ParseInt | IncorrectNumericConversion.go:90:18:90:48 | call to ParseInt : tuple type | IncorrectNumericConversion.go:94:7:94:19 | type conversion | Incorrect conversion of a (arch-dependent)-bit number from strconv.ParseInt result to a lower bit size type int32 | -| IncorrectNumericConversion.go:99:18:99:50 | call to ParseUint | IncorrectNumericConversion.go:99:18:99:50 | call to ParseUint : tuple type | IncorrectNumericConversion.go:103:7:103:18 | type conversion | Incorrect conversion of a 16-bit number from strconv.ParseUint result to a lower bit size type int8 | -| IncorrectNumericConversion.go:106:18:106:50 | call to ParseUint | IncorrectNumericConversion.go:106:18:106:50 | call to ParseUint : tuple type | IncorrectNumericConversion.go:110:7:110:19 | type conversion | Incorrect conversion of a 32-bit number from strconv.ParseUint result to a lower bit size type int16 | -| IncorrectNumericConversion.go:113:18:113:50 | call to ParseUint | IncorrectNumericConversion.go:113:18:113:50 | call to ParseUint : tuple type | IncorrectNumericConversion.go:117:7:117:19 | type conversion | Incorrect conversion of a 64-bit number from strconv.ParseUint result to a lower bit size type int32 | -| IncorrectNumericConversion.go:120:18:120:49 | call to ParseUint | IncorrectNumericConversion.go:120:18:120:49 | call to ParseUint : tuple type | IncorrectNumericConversion.go:124:7:124:19 | type conversion | Incorrect conversion of a (arch-dependent)-bit number from strconv.ParseUint result to a lower bit size type int32 | -| IncorrectNumericConversion.go:208:18:208:36 | call to Atoi | IncorrectNumericConversion.go:208:18:208:36 | call to Atoi : tuple type | IncorrectNumericConversion.go:212:7:212:18 | type conversion | Incorrect conversion of a (arch-dependent)-bit number from strconv.Atoi result to a lower bit size type int8 | -| IncorrectNumericConversion.go:215:18:215:36 | call to Atoi | IncorrectNumericConversion.go:215:18:215:36 | call to Atoi : tuple type | IncorrectNumericConversion.go:219:7:219:19 | type conversion | Incorrect conversion of a (arch-dependent)-bit number from strconv.Atoi result to a lower bit size type int16 | -| IncorrectNumericConversion.go:222:18:222:36 | call to Atoi | IncorrectNumericConversion.go:222:18:222:36 | call to Atoi : tuple type | IncorrectNumericConversion.go:226:7:226:19 | type conversion | Incorrect conversion of a (arch-dependent)-bit number from strconv.Atoi result to a lower bit size type int32 | -| IncorrectNumericConversion.go:229:18:229:36 | call to Atoi | IncorrectNumericConversion.go:229:18:229:36 | call to Atoi : tuple type | IncorrectNumericConversion.go:233:7:233:19 | type conversion | Incorrect conversion of a (arch-dependent)-bit number from strconv.Atoi result to a lower bit size type uint8 | -| IncorrectNumericConversion.go:236:18:236:36 | call to Atoi | IncorrectNumericConversion.go:236:18:236:36 | call to Atoi : tuple type | IncorrectNumericConversion.go:240:7:240:20 | type conversion | Incorrect conversion of a (arch-dependent)-bit number from strconv.Atoi result to a lower bit size type uint16 | -| IncorrectNumericConversion.go:243:18:243:36 | call to Atoi | IncorrectNumericConversion.go:243:18:243:36 | call to Atoi : tuple type | IncorrectNumericConversion.go:247:7:247:20 | type conversion | Incorrect conversion of a (arch-dependent)-bit number from strconv.Atoi result to a lower bit size type uint32 | -| IncorrectNumericConversion.go:250:18:250:36 | call to Atoi | IncorrectNumericConversion.go:250:18:250:36 | call to Atoi : tuple type | IncorrectNumericConversion.go:254:7:254:21 | type conversion | Incorrect conversion of a (arch-dependent)-bit number from strconv.Atoi result to a lower bit size type float32 | -| IncorrectNumericConversion.go:257:18:257:36 | call to Atoi | IncorrectNumericConversion.go:257:18:257:36 | call to Atoi : tuple type | IncorrectNumericConversion.go:262:7:262:18 | type conversion | Incorrect conversion of a (arch-dependent)-bit number from strconv.Atoi result to a lower bit size type uint8 | -| IncorrectNumericConversion.go:266:18:266:36 | call to Atoi | IncorrectNumericConversion.go:266:18:266:36 | call to Atoi : tuple type | IncorrectNumericConversion.go:270:7:270:23 | type conversion | Incorrect conversion of a (arch-dependent)-bit number from strconv.Atoi result to a lower bit size type int16 | diff --git a/ql/test/experimental/CWE-681/IncorrectNumericConversion.go b/ql/test/experimental/CWE-681/IncorrectNumericConversion.go deleted file mode 100644 index cdabda91a4a..00000000000 --- a/ql/test/experimental/CWE-681/IncorrectNumericConversion.go +++ /dev/null @@ -1,355 +0,0 @@ -package main - -import ( - "math" - "strconv" -) - -func main() { - -} - -type Something struct { -} -type Config struct { -} -type Registry struct { -} - -func LookupTarget(conf *Config, num int32) (int32, error) { - return 567, nil -} -func LookupNumberByName(reg *Registry, name string) (int32, error) { - return 567, nil -} -func lab(s string) (*Something, error) { - num, err := strconv.Atoi(s) - - if err != nil { - number, err := LookupNumberByName(&Registry{}, s) - if err != nil { - return nil, err - } - num = int(number) - } - target, err := LookupTarget(&Config{}, int32(num)) - if err != nil { - return nil, err - } - - // convert the resolved target number back to a string - - s = strconv.Itoa(int(target)) - - return nil, nil -} - -const CustomMaxInt16 = 1<<15 - 1 - -type CustomInt int16 - -func badParseFloat() { - { - parsed, err := strconv.ParseFloat("1.32", 32) - if err != nil { - panic(err) - } - _ = int16(parsed) - } - { - parsed, err := strconv.ParseFloat("1.32", 64) - if err != nil { - panic(err) - } - _ = int32(parsed) - } -} -func badParseInt() { - { - parsed, err := strconv.ParseInt("3456", 10, 16) - if err != nil { - panic(err) - } - _ = int8(parsed) - } - { - parsed, err := strconv.ParseInt("3456", 10, 32) - if err != nil { - panic(err) - } - _ = int16(parsed) - } - { - parsed, err := strconv.ParseInt("3456", 10, 64) - if err != nil { - panic(err) - } - _ = int32(parsed) - } - { - parsed, err := strconv.ParseInt("3456", 10, 0) - if err != nil { - panic(err) - } - _ = int32(parsed) - } -} -func badParseUint() { - { - parsed, err := strconv.ParseUint("3456", 10, 16) - if err != nil { - panic(err) - } - _ = int8(parsed) - } - { - parsed, err := strconv.ParseUint("3456", 10, 32) - if err != nil { - panic(err) - } - _ = int16(parsed) - } - { - parsed, err := strconv.ParseUint("3456", 10, 64) - if err != nil { - panic(err) - } - _ = int32(parsed) - } - { - parsed, err := strconv.ParseUint("3456", 10, 0) - if err != nil { - panic(err) - } - _ = int32(parsed) - } -} - -func goodParseFloat() { - { - parsed, err := strconv.ParseFloat("1.32", 32) - if err != nil { - panic(err) - } - _ = int32(parsed) - } - { - parsed, err := strconv.ParseFloat("1.32", 64) - if err != nil { - panic(err) - } - _ = int64(parsed) - } -} -func goodParseInt() { - { - parsed, err := strconv.ParseInt("3456", 10, 16) - if err != nil { - panic(err) - } - _ = int16(parsed) - } - { - parsed, err := strconv.ParseInt("3456", 10, 32) - if err != nil { - panic(err) - } - _ = int32(parsed) - } - { - parsed, err := strconv.ParseInt("3456", 10, 64) - if err != nil { - panic(err) - } - _ = int64(parsed) - } - { - parsed, err := strconv.ParseInt("3456", 10, 0) - if err != nil { - panic(err) - } - _ = int64(parsed) - } -} -func goodParseUint() { - { - parsed, err := strconv.ParseUint("3456", 10, 16) - if err != nil { - panic(err) - } - _ = int16(parsed) - } - { - parsed, err := strconv.ParseUint("3456", 10, 32) - if err != nil { - panic(err) - } - _ = int32(parsed) - } - { - parsed, err := strconv.ParseUint("3456", 10, 64) - if err != nil { - panic(err) - } - _ = int64(parsed) - } - { - parsed, err := strconv.ParseUint("3456", 10, 0) - if err != nil { - panic(err) - } - _ = int64(parsed) - } -} - -// these should be caught: -func upperBoundIsNOTChecked(input string) { - { - parsed, err := strconv.Atoi(input) - if err != nil { - panic(err) - } - _ = int8(parsed) - } - { - parsed, err := strconv.Atoi(input) - if err != nil { - panic(err) - } - _ = int16(parsed) - } - { - parsed, err := strconv.Atoi(input) - if err != nil { - panic(err) - } - _ = int32(parsed) - } - { - parsed, err := strconv.Atoi(input) - if err != nil { - panic(err) - } - _ = uint8(parsed) - } - { - parsed, err := strconv.Atoi(input) - if err != nil { - panic(err) - } - _ = uint16(parsed) - } - { - parsed, err := strconv.Atoi(input) - if err != nil { - panic(err) - } - _ = uint32(parsed) - } - { - parsed, err := strconv.Atoi(input) - if err != nil { - panic(err) - } - _ = float32(parsed) - } - { - parsed, err := strconv.Atoi(input) - if err != nil { - panic(err) - } - // NOTE: byte is uint8 - _ = byte(parsed) - } - { - // using custom type: - parsed, err := strconv.Atoi(input) - if err != nil { - panic(err) - } - _ = CustomInt(parsed) - } - -} - -// these should NOT be caught: -func upperBoundIsChecked(input string) { - { - parsed, err := strconv.Atoi(input) - if err != nil { - panic(err) - } - if parsed < math.MaxInt8 { - _ = int8(parsed) - } - } - { - parsed, err := strconv.Atoi(input) - if err != nil { - panic(err) - } - if parsed < math.MaxInt16 { - _ = int16(parsed) - } - } - { - parsed, err := strconv.Atoi(input) - if err != nil { - panic(err) - } - if parsed > 0 { - _ = int32(parsed) - } - } - { - parsed, err := strconv.Atoi(input) - if err != nil { - panic(err) - } - if parsed < math.MaxInt32 { - _ = int32(parsed) - } - } - { - parsed, err := strconv.Atoi(input) - if err != nil { - panic(err) - } - if parsed < math.MaxUint8 { - _ = uint8(parsed) - } - } - { - parsed, err := strconv.Atoi(input) - if err != nil { - panic(err) - } - if parsed < math.MaxUint16 { - _ = uint16(parsed) - } - } - { - parsed, err := strconv.Atoi(input) - if err != nil { - panic(err) - } - if parsed < math.MaxUint8 { - _ = byte(parsed) - } - } - { // multiple `and` conditions - parsed, err := strconv.Atoi(input) - if err == nil && 1 == 1 && parsed < math.MaxInt8 { - _ = int8(parsed) - } - } - { // custom maxInt16 - parsed, err := strconv.Atoi(input) - if err != nil { - panic(err) - } - if parsed < CustomMaxInt16 { - _ = int16(parsed) - } - } -} diff --git a/ql/test/experimental/CWE-681/IncorrectNumericConversion.qlref b/ql/test/experimental/CWE-681/IncorrectNumericConversion.qlref deleted file mode 100644 index 884cf918f1c..00000000000 --- a/ql/test/experimental/CWE-681/IncorrectNumericConversion.qlref +++ /dev/null @@ -1 +0,0 @@ -experimental/CWE-681/IncorrectNumericConversion.ql diff --git a/ql/test/query-tests/Security/CWE-681/IncorrectIntegerConversion.expected b/ql/test/query-tests/Security/CWE-681/IncorrectIntegerConversion.expected new file mode 100644 index 00000000000..a1bf571c4d7 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-681/IncorrectIntegerConversion.expected @@ -0,0 +1,247 @@ +edges +| IncorrectIntegerConversion.go:26:2:26:28 | ... := ...[0] : int | IncorrectIntegerConversion.go:35:41:35:50 | type conversion | +| IncorrectIntegerConversion.go:65:3:65:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:69:7:69:18 | type conversion | +| IncorrectIntegerConversion.go:65:3:65:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:70:7:70:19 | type conversion | +| IncorrectIntegerConversion.go:81:3:81:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:85:7:85:18 | type conversion | +| IncorrectIntegerConversion.go:81:3:81:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:86:7:86:19 | type conversion | +| IncorrectIntegerConversion.go:81:3:81:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:87:7:87:19 | type conversion | +| IncorrectIntegerConversion.go:81:3:81:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:88:7:88:20 | type conversion | +| IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:101:7:101:18 | type conversion | +| IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:102:7:102:19 | type conversion | +| IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:103:7:103:19 | type conversion | +| IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:104:7:104:20 | type conversion | +| IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:105:7:105:19 | type conversion | +| IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:106:7:106:20 | type conversion | +| IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:109:7:109:17 | type conversion | +| IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:110:7:110:18 | type conversion | +| IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:117:7:117:18 | type conversion | +| IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:118:7:118:19 | type conversion | +| IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:119:7:119:19 | type conversion | +| IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:120:7:120:20 | type conversion | +| IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:121:7:121:19 | type conversion | +| IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:122:7:122:20 | type conversion | +| IncorrectIntegerConversion.go:148:3:148:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:152:7:152:18 | type conversion | +| IncorrectIntegerConversion.go:148:3:148:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:153:7:153:19 | type conversion | +| IncorrectIntegerConversion.go:164:3:164:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:168:7:168:18 | type conversion | +| IncorrectIntegerConversion.go:164:3:164:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:169:7:169:19 | type conversion | +| IncorrectIntegerConversion.go:164:3:164:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:170:7:170:19 | type conversion | +| IncorrectIntegerConversion.go:164:3:164:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:171:7:171:20 | type conversion | +| IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:184:7:184:18 | type conversion | +| IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:185:7:185:19 | type conversion | +| IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:186:7:186:19 | type conversion | +| IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:187:7:187:20 | type conversion | +| IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:188:7:188:19 | type conversion | +| IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:189:7:189:20 | type conversion | +| IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:192:7:192:17 | type conversion | +| IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:193:7:193:18 | type conversion | +| IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:200:7:200:18 | type conversion | +| IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:201:7:201:19 | type conversion | +| IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:202:7:202:19 | type conversion | +| IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:203:7:203:20 | type conversion | +| IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:204:7:204:19 | type conversion | +| IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:205:7:205:20 | type conversion | +| IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] : int | IncorrectIntegerConversion.go:218:6:218:17 | type conversion | +| IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] : int | IncorrectIntegerConversion.go:219:6:219:18 | type conversion | +| IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] : int | IncorrectIntegerConversion.go:220:6:220:18 | type conversion | +| IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] : int | IncorrectIntegerConversion.go:221:6:221:19 | type conversion | +| IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] : int | IncorrectIntegerConversion.go:222:6:222:18 | type conversion | +| IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] : int | IncorrectIntegerConversion.go:223:6:223:19 | type conversion | +| IncorrectIntegerConversion.go:235:3:235:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:240:7:240:18 | type conversion | +| IncorrectIntegerConversion.go:235:3:235:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:241:7:241:23 | type conversion | +| IncorrectIntegerConversion.go:247:3:247:36 | ... := ...[0] : int | IncorrectIntegerConversion.go:261:8:261:19 | type conversion | +| IncorrectIntegerConversion.go:268:3:268:49 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:282:8:282:21 | type conversion | +| IncorrectIntegerConversion.go:319:3:319:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:323:7:323:18 | type conversion | +| IncorrectIntegerConversion.go:330:3:330:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:334:9:334:21 | type conversion | +| IncorrectIntegerConversion.go:338:3:338:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:342:8:342:20 | type conversion | +| IncorrectIntegerConversion.go:346:3:346:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:350:9:350:21 | type conversion : int64 | +| IncorrectIntegerConversion.go:350:9:350:21 | type conversion : int64 | IncorrectIntegerConversion.go:351:9:351:17 | type conversion | +| IncorrectIntegerConversion.go:355:3:355:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:359:9:359:21 | type conversion : int64 | +| IncorrectIntegerConversion.go:359:9:359:21 | type conversion : int64 | IncorrectIntegerConversion.go:360:9:360:17 | type conversion : int64 | +| IncorrectIntegerConversion.go:360:9:360:17 | type conversion : int64 | IncorrectIntegerConversion.go:361:9:361:17 | type conversion : int64 | +| IncorrectIntegerConversion.go:361:9:361:17 | type conversion : int64 | IncorrectIntegerConversion.go:362:7:362:14 | type conversion | +| IncorrectIntegerConversion.go:367:2:367:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:371:6:371:17 | type conversion | +| IncorrectIntegerConversion.go:367:2:367:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:372:6:372:18 | type conversion | +| IncorrectIntegerConversion.go:367:2:367:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:373:6:373:18 | type conversion | +| IncorrectIntegerConversion.go:367:2:367:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:374:6:374:19 | type conversion | +| IncorrectIntegerConversion.go:367:2:367:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:375:6:375:18 | type conversion | +| IncorrectIntegerConversion.go:367:2:367:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:376:6:376:19 | type conversion | +| TestNoArchitectureBuildConstraints.go:12:3:12:48 | ... := ...[0] : int64 | TestNoArchitectureBuildConstraints.go:16:7:16:19 | type conversion | +| TestNoArchitectureBuildConstraints.go:12:3:12:48 | ... := ...[0] : int64 | TestNoArchitectureBuildConstraints.go:17:7:17:20 | type conversion | +| TestNoArchitectureBuildConstraints.go:20:3:20:49 | ... := ...[0] : int64 | TestNoArchitectureBuildConstraints.go:24:7:24:17 | type conversion | +| TestNoArchitectureBuildConstraints.go:20:3:20:49 | ... := ...[0] : int64 | TestNoArchitectureBuildConstraints.go:25:7:25:18 | type conversion | +nodes +| IncorrectIntegerConversion.go:26:2:26:28 | ... := ...[0] : int | semmle.label | ... := ...[0] : int | +| IncorrectIntegerConversion.go:35:41:35:50 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:65:3:65:49 | ... := ...[0] : int64 | semmle.label | ... := ...[0] : int64 | +| IncorrectIntegerConversion.go:69:7:69:18 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:70:7:70:19 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:81:3:81:49 | ... := ...[0] : int64 | semmle.label | ... := ...[0] : int64 | +| IncorrectIntegerConversion.go:81:3:81:49 | ... := ...[0] : int64 | semmle.label | ... := ...[0] : int64 | +| IncorrectIntegerConversion.go:85:7:85:18 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:86:7:86:19 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:87:7:87:19 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:88:7:88:20 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] : int64 | semmle.label | ... := ...[0] : int64 | +| IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] : int64 | semmle.label | ... := ...[0] : int64 | +| IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] : int64 | semmle.label | ... := ...[0] : int64 | +| IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] : int64 | semmle.label | ... := ...[0] : int64 | +| IncorrectIntegerConversion.go:101:7:101:18 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:102:7:102:19 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:103:7:103:19 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:104:7:104:20 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:105:7:105:19 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:106:7:106:20 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:109:7:109:17 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:110:7:110:18 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] : int64 | semmle.label | ... := ...[0] : int64 | +| IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] : int64 | semmle.label | ... := ...[0] : int64 | +| IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] : int64 | semmle.label | ... := ...[0] : int64 | +| IncorrectIntegerConversion.go:117:7:117:18 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:118:7:118:19 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:119:7:119:19 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:120:7:120:20 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:121:7:121:19 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:122:7:122:20 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:148:3:148:50 | ... := ...[0] : uint64 | semmle.label | ... := ...[0] : uint64 | +| IncorrectIntegerConversion.go:152:7:152:18 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:153:7:153:19 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:164:3:164:50 | ... := ...[0] : uint64 | semmle.label | ... := ...[0] : uint64 | +| IncorrectIntegerConversion.go:164:3:164:50 | ... := ...[0] : uint64 | semmle.label | ... := ...[0] : uint64 | +| IncorrectIntegerConversion.go:168:7:168:18 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:169:7:169:19 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:170:7:170:19 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:171:7:171:20 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] : uint64 | semmle.label | ... := ...[0] : uint64 | +| IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] : uint64 | semmle.label | ... := ...[0] : uint64 | +| IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] : uint64 | semmle.label | ... := ...[0] : uint64 | +| IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] : uint64 | semmle.label | ... := ...[0] : uint64 | +| IncorrectIntegerConversion.go:184:7:184:18 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:185:7:185:19 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:186:7:186:19 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:187:7:187:20 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:188:7:188:19 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:189:7:189:20 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:192:7:192:17 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:193:7:193:18 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] : uint64 | semmle.label | ... := ...[0] : uint64 | +| IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] : uint64 | semmle.label | ... := ...[0] : uint64 | +| IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] : uint64 | semmle.label | ... := ...[0] : uint64 | +| IncorrectIntegerConversion.go:200:7:200:18 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:201:7:201:19 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:202:7:202:19 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:203:7:203:20 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:204:7:204:19 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:205:7:205:20 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] : int | semmle.label | ... := ...[0] : int | +| IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] : int | semmle.label | ... := ...[0] : int | +| IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] : int | semmle.label | ... := ...[0] : int | +| IncorrectIntegerConversion.go:218:6:218:17 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:219:6:219:18 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:220:6:220:18 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:221:6:221:19 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:222:6:222:18 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:223:6:223:19 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:235:3:235:48 | ... := ...[0] : int64 | semmle.label | ... := ...[0] : int64 | +| IncorrectIntegerConversion.go:235:3:235:48 | ... := ...[0] : int64 | semmle.label | ... := ...[0] : int64 | +| IncorrectIntegerConversion.go:240:7:240:18 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:241:7:241:23 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:247:3:247:36 | ... := ...[0] : int | semmle.label | ... := ...[0] : int | +| IncorrectIntegerConversion.go:261:8:261:19 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:268:3:268:49 | ... := ...[0] : uint64 | semmle.label | ... := ...[0] : uint64 | +| IncorrectIntegerConversion.go:282:8:282:21 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:319:3:319:48 | ... := ...[0] : int64 | semmle.label | ... := ...[0] : int64 | +| IncorrectIntegerConversion.go:323:7:323:18 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:330:3:330:48 | ... := ...[0] : int64 | semmle.label | ... := ...[0] : int64 | +| IncorrectIntegerConversion.go:334:9:334:21 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:338:3:338:48 | ... := ...[0] : int64 | semmle.label | ... := ...[0] : int64 | +| IncorrectIntegerConversion.go:342:8:342:20 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:346:3:346:48 | ... := ...[0] : int64 | semmle.label | ... := ...[0] : int64 | +| IncorrectIntegerConversion.go:350:9:350:21 | type conversion : int64 | semmle.label | type conversion : int64 | +| IncorrectIntegerConversion.go:351:9:351:17 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:355:3:355:48 | ... := ...[0] : int64 | semmle.label | ... := ...[0] : int64 | +| IncorrectIntegerConversion.go:359:9:359:21 | type conversion : int64 | semmle.label | type conversion : int64 | +| IncorrectIntegerConversion.go:360:9:360:17 | type conversion : int64 | semmle.label | type conversion : int64 | +| IncorrectIntegerConversion.go:361:9:361:17 | type conversion : int64 | semmle.label | type conversion : int64 | +| IncorrectIntegerConversion.go:362:7:362:14 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:367:2:367:60 | ... := ...[0] : int64 | semmle.label | ... := ...[0] : int64 | +| IncorrectIntegerConversion.go:367:2:367:60 | ... := ...[0] : int64 | semmle.label | ... := ...[0] : int64 | +| IncorrectIntegerConversion.go:367:2:367:60 | ... := ...[0] : int64 | semmle.label | ... := ...[0] : int64 | +| IncorrectIntegerConversion.go:371:6:371:17 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:372:6:372:18 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:373:6:373:18 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:374:6:374:19 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:375:6:375:18 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:376:6:376:19 | type conversion | semmle.label | type conversion | +| TestNoArchitectureBuildConstraints.go:12:3:12:48 | ... := ...[0] : int64 | semmle.label | ... := ...[0] : int64 | +| TestNoArchitectureBuildConstraints.go:16:7:16:19 | type conversion | semmle.label | type conversion | +| TestNoArchitectureBuildConstraints.go:17:7:17:20 | type conversion | semmle.label | type conversion | +| TestNoArchitectureBuildConstraints.go:20:3:20:49 | ... := ...[0] : int64 | semmle.label | ... := ...[0] : int64 | +| TestNoArchitectureBuildConstraints.go:24:7:24:17 | type conversion | semmle.label | type conversion | +| TestNoArchitectureBuildConstraints.go:25:7:25:18 | type conversion | semmle.label | type conversion | +#select +| IncorrectIntegerConversion.go:35:41:35:50 | type conversion | IncorrectIntegerConversion.go:26:2:26:28 | ... := ...[0] : int | IncorrectIntegerConversion.go:35:41:35:50 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from $@ to a lower bit size type int32 without an upper bound check. | IncorrectIntegerConversion.go:26:2:26:28 | ... := ...[0] : int | strconv.Atoi | +| IncorrectIntegerConversion.go:69:7:69:18 | type conversion | IncorrectIntegerConversion.go:65:3:65:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:69:7:69:18 | type conversion | Incorrect conversion of a 16-bit integer from $@ to a lower bit size type int8 without an upper bound check. | IncorrectIntegerConversion.go:65:3:65:49 | ... := ...[0] : int64 | strconv.ParseInt | +| IncorrectIntegerConversion.go:70:7:70:19 | type conversion | IncorrectIntegerConversion.go:65:3:65:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:70:7:70:19 | type conversion | Incorrect conversion of a 16-bit integer from $@ to a lower bit size type uint8 without an upper bound check. | IncorrectIntegerConversion.go:65:3:65:49 | ... := ...[0] : int64 | strconv.ParseInt | +| IncorrectIntegerConversion.go:85:7:85:18 | type conversion | IncorrectIntegerConversion.go:81:3:81:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:85:7:85:18 | type conversion | Incorrect conversion of a 32-bit integer from $@ to a lower bit size type int8 without an upper bound check. | IncorrectIntegerConversion.go:81:3:81:49 | ... := ...[0] : int64 | strconv.ParseInt | +| IncorrectIntegerConversion.go:86:7:86:19 | type conversion | IncorrectIntegerConversion.go:81:3:81:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:86:7:86:19 | type conversion | Incorrect conversion of a 32-bit integer from $@ to a lower bit size type uint8 without an upper bound check. | IncorrectIntegerConversion.go:81:3:81:49 | ... := ...[0] : int64 | strconv.ParseInt | +| IncorrectIntegerConversion.go:87:7:87:19 | type conversion | IncorrectIntegerConversion.go:81:3:81:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:87:7:87:19 | type conversion | Incorrect conversion of a 32-bit integer from $@ to a lower bit size type int16 without an upper bound check. | IncorrectIntegerConversion.go:81:3:81:49 | ... := ...[0] : int64 | strconv.ParseInt | +| IncorrectIntegerConversion.go:88:7:88:20 | type conversion | IncorrectIntegerConversion.go:81:3:81:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:88:7:88:20 | type conversion | Incorrect conversion of a 32-bit integer from $@ to a lower bit size type uint16 without an upper bound check. | IncorrectIntegerConversion.go:81:3:81:49 | ... := ...[0] : int64 | strconv.ParseInt | +| IncorrectIntegerConversion.go:101:7:101:18 | type conversion | IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:101:7:101:18 | type conversion | Incorrect conversion of a 64-bit integer from $@ to a lower bit size type int8 without an upper bound check. | IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] : int64 | strconv.ParseInt | +| IncorrectIntegerConversion.go:102:7:102:19 | type conversion | IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:102:7:102:19 | type conversion | Incorrect conversion of a 64-bit integer from $@ to a lower bit size type uint8 without an upper bound check. | IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] : int64 | strconv.ParseInt | +| IncorrectIntegerConversion.go:103:7:103:19 | type conversion | IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:103:7:103:19 | type conversion | Incorrect conversion of a 64-bit integer from $@ to a lower bit size type int16 without an upper bound check. | IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] : int64 | strconv.ParseInt | +| IncorrectIntegerConversion.go:104:7:104:20 | type conversion | IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:104:7:104:20 | type conversion | Incorrect conversion of a 64-bit integer from $@ to a lower bit size type uint16 without an upper bound check. | IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] : int64 | strconv.ParseInt | +| IncorrectIntegerConversion.go:105:7:105:19 | type conversion | IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:105:7:105:19 | type conversion | Incorrect conversion of a 64-bit integer from $@ to a lower bit size type int32 without an upper bound check. | IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] : int64 | strconv.ParseInt | +| IncorrectIntegerConversion.go:106:7:106:20 | type conversion | IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:106:7:106:20 | type conversion | Incorrect conversion of a 64-bit integer from $@ to a lower bit size type uint32 without an upper bound check. | IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] : int64 | strconv.ParseInt | +| IncorrectIntegerConversion.go:109:7:109:17 | type conversion | IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:109:7:109:17 | type conversion | Incorrect conversion of a 64-bit integer from $@ to a lower bit size type int without an upper bound check. | IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] : int64 | strconv.ParseInt | +| IncorrectIntegerConversion.go:110:7:110:18 | type conversion | IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:110:7:110:18 | type conversion | Incorrect conversion of a 64-bit integer from $@ to a lower bit size type uint without an upper bound check. | IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] : int64 | strconv.ParseInt | +| IncorrectIntegerConversion.go:117:7:117:18 | type conversion | IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:117:7:117:18 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from $@ to a lower bit size type int8 without an upper bound check. | IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] : int64 | strconv.ParseInt | +| IncorrectIntegerConversion.go:118:7:118:19 | type conversion | IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:118:7:118:19 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from $@ to a lower bit size type uint8 without an upper bound check. | IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] : int64 | strconv.ParseInt | +| IncorrectIntegerConversion.go:119:7:119:19 | type conversion | IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:119:7:119:19 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from $@ to a lower bit size type int16 without an upper bound check. | IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] : int64 | strconv.ParseInt | +| IncorrectIntegerConversion.go:120:7:120:20 | type conversion | IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:120:7:120:20 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from $@ to a lower bit size type uint16 without an upper bound check. | IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] : int64 | strconv.ParseInt | +| IncorrectIntegerConversion.go:121:7:121:19 | type conversion | IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:121:7:121:19 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from $@ to a lower bit size type int32 without an upper bound check. | IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] : int64 | strconv.ParseInt | +| IncorrectIntegerConversion.go:122:7:122:20 | type conversion | IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:122:7:122:20 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from $@ to a lower bit size type uint32 without an upper bound check. | IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] : int64 | strconv.ParseInt | +| IncorrectIntegerConversion.go:152:7:152:18 | type conversion | IncorrectIntegerConversion.go:148:3:148:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:152:7:152:18 | type conversion | Incorrect conversion of a 16-bit integer from $@ to a lower bit size type int8 without an upper bound check. | IncorrectIntegerConversion.go:148:3:148:50 | ... := ...[0] : uint64 | strconv.ParseUint | +| IncorrectIntegerConversion.go:153:7:153:19 | type conversion | IncorrectIntegerConversion.go:148:3:148:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:153:7:153:19 | type conversion | Incorrect conversion of a 16-bit integer from $@ to a lower bit size type uint8 without an upper bound check. | IncorrectIntegerConversion.go:148:3:148:50 | ... := ...[0] : uint64 | strconv.ParseUint | +| IncorrectIntegerConversion.go:168:7:168:18 | type conversion | IncorrectIntegerConversion.go:164:3:164:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:168:7:168:18 | type conversion | Incorrect conversion of a 32-bit integer from $@ to a lower bit size type int8 without an upper bound check. | IncorrectIntegerConversion.go:164:3:164:50 | ... := ...[0] : uint64 | strconv.ParseUint | +| IncorrectIntegerConversion.go:169:7:169:19 | type conversion | IncorrectIntegerConversion.go:164:3:164:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:169:7:169:19 | type conversion | Incorrect conversion of a 32-bit integer from $@ to a lower bit size type uint8 without an upper bound check. | IncorrectIntegerConversion.go:164:3:164:50 | ... := ...[0] : uint64 | strconv.ParseUint | +| IncorrectIntegerConversion.go:170:7:170:19 | type conversion | IncorrectIntegerConversion.go:164:3:164:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:170:7:170:19 | type conversion | Incorrect conversion of a 32-bit integer from $@ to a lower bit size type int16 without an upper bound check. | IncorrectIntegerConversion.go:164:3:164:50 | ... := ...[0] : uint64 | strconv.ParseUint | +| IncorrectIntegerConversion.go:171:7:171:20 | type conversion | IncorrectIntegerConversion.go:164:3:164:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:171:7:171:20 | type conversion | Incorrect conversion of a 32-bit integer from $@ to a lower bit size type uint16 without an upper bound check. | IncorrectIntegerConversion.go:164:3:164:50 | ... := ...[0] : uint64 | strconv.ParseUint | +| IncorrectIntegerConversion.go:184:7:184:18 | type conversion | IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:184:7:184:18 | type conversion | Incorrect conversion of a 64-bit integer from $@ to a lower bit size type int8 without an upper bound check. | IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] : uint64 | strconv.ParseUint | +| IncorrectIntegerConversion.go:185:7:185:19 | type conversion | IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:185:7:185:19 | type conversion | Incorrect conversion of a 64-bit integer from $@ to a lower bit size type uint8 without an upper bound check. | IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] : uint64 | strconv.ParseUint | +| IncorrectIntegerConversion.go:186:7:186:19 | type conversion | IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:186:7:186:19 | type conversion | Incorrect conversion of a 64-bit integer from $@ to a lower bit size type int16 without an upper bound check. | IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] : uint64 | strconv.ParseUint | +| IncorrectIntegerConversion.go:187:7:187:20 | type conversion | IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:187:7:187:20 | type conversion | Incorrect conversion of a 64-bit integer from $@ to a lower bit size type uint16 without an upper bound check. | IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] : uint64 | strconv.ParseUint | +| IncorrectIntegerConversion.go:188:7:188:19 | type conversion | IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:188:7:188:19 | type conversion | Incorrect conversion of a 64-bit integer from $@ to a lower bit size type int32 without an upper bound check. | IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] : uint64 | strconv.ParseUint | +| IncorrectIntegerConversion.go:189:7:189:20 | type conversion | IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:189:7:189:20 | type conversion | Incorrect conversion of a 64-bit integer from $@ to a lower bit size type uint32 without an upper bound check. | IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] : uint64 | strconv.ParseUint | +| IncorrectIntegerConversion.go:192:7:192:17 | type conversion | IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:192:7:192:17 | type conversion | Incorrect conversion of a 64-bit integer from $@ to a lower bit size type int without an upper bound check. | IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] : uint64 | strconv.ParseUint | +| IncorrectIntegerConversion.go:193:7:193:18 | type conversion | IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:193:7:193:18 | type conversion | Incorrect conversion of a 64-bit integer from $@ to a lower bit size type uint without an upper bound check. | IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] : uint64 | strconv.ParseUint | +| IncorrectIntegerConversion.go:200:7:200:18 | type conversion | IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:200:7:200:18 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from $@ to a lower bit size type int8 without an upper bound check. | IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] : uint64 | strconv.ParseUint | +| IncorrectIntegerConversion.go:201:7:201:19 | type conversion | IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:201:7:201:19 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from $@ to a lower bit size type uint8 without an upper bound check. | IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] : uint64 | strconv.ParseUint | +| IncorrectIntegerConversion.go:202:7:202:19 | type conversion | IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:202:7:202:19 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from $@ to a lower bit size type int16 without an upper bound check. | IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] : uint64 | strconv.ParseUint | +| IncorrectIntegerConversion.go:203:7:203:20 | type conversion | IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:203:7:203:20 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from $@ to a lower bit size type uint16 without an upper bound check. | IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] : uint64 | strconv.ParseUint | +| IncorrectIntegerConversion.go:204:7:204:19 | type conversion | IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:204:7:204:19 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from $@ to a lower bit size type int32 without an upper bound check. | IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] : uint64 | strconv.ParseUint | +| IncorrectIntegerConversion.go:205:7:205:20 | type conversion | IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:205:7:205:20 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from $@ to a lower bit size type uint32 without an upper bound check. | IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] : uint64 | strconv.ParseUint | +| IncorrectIntegerConversion.go:218:6:218:17 | type conversion | IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] : int | IncorrectIntegerConversion.go:218:6:218:17 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from $@ to a lower bit size type int8 without an upper bound check. | IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] : int | strconv.Atoi | +| IncorrectIntegerConversion.go:219:6:219:18 | type conversion | IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] : int | IncorrectIntegerConversion.go:219:6:219:18 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from $@ to a lower bit size type uint8 without an upper bound check. | IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] : int | strconv.Atoi | +| IncorrectIntegerConversion.go:220:6:220:18 | type conversion | IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] : int | IncorrectIntegerConversion.go:220:6:220:18 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from $@ to a lower bit size type int16 without an upper bound check. | IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] : int | strconv.Atoi | +| IncorrectIntegerConversion.go:221:6:221:19 | type conversion | IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] : int | IncorrectIntegerConversion.go:221:6:221:19 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from $@ to a lower bit size type uint16 without an upper bound check. | IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] : int | strconv.Atoi | +| IncorrectIntegerConversion.go:222:6:222:18 | type conversion | IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] : int | IncorrectIntegerConversion.go:222:6:222:18 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from $@ to a lower bit size type int32 without an upper bound check. | IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] : int | strconv.Atoi | +| IncorrectIntegerConversion.go:223:6:223:19 | type conversion | IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] : int | IncorrectIntegerConversion.go:223:6:223:19 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from $@ to a lower bit size type uint32 without an upper bound check. | IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] : int | strconv.Atoi | +| IncorrectIntegerConversion.go:240:7:240:18 | type conversion | IncorrectIntegerConversion.go:235:3:235:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:240:7:240:18 | type conversion | Incorrect conversion of a 32-bit integer from $@ to a lower bit size type uint8 without an upper bound check. | IncorrectIntegerConversion.go:235:3:235:48 | ... := ...[0] : int64 | strconv.ParseInt | +| IncorrectIntegerConversion.go:241:7:241:23 | type conversion | IncorrectIntegerConversion.go:235:3:235:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:241:7:241:23 | type conversion | Incorrect conversion of a 32-bit integer from $@ to a lower bit size type int16 without an upper bound check. | IncorrectIntegerConversion.go:235:3:235:48 | ... := ...[0] : int64 | strconv.ParseInt | +| IncorrectIntegerConversion.go:261:8:261:19 | type conversion | IncorrectIntegerConversion.go:247:3:247:36 | ... := ...[0] : int | IncorrectIntegerConversion.go:261:8:261:19 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from $@ to a lower bit size type int8 without an upper bound check. | IncorrectIntegerConversion.go:247:3:247:36 | ... := ...[0] : int | strconv.Atoi | +| IncorrectIntegerConversion.go:282:8:282:21 | type conversion | IncorrectIntegerConversion.go:268:3:268:49 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:282:8:282:21 | type conversion | Incorrect conversion of a 32-bit integer from $@ to a lower bit size type uint16 without an upper bound check. | IncorrectIntegerConversion.go:268:3:268:49 | ... := ...[0] : uint64 | strconv.ParseUint | +| IncorrectIntegerConversion.go:323:7:323:18 | type conversion | IncorrectIntegerConversion.go:319:3:319:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:323:7:323:18 | type conversion | Incorrect conversion of a 16-bit integer from $@ to a lower bit size type uint8 without an upper bound check. | IncorrectIntegerConversion.go:319:3:319:48 | ... := ...[0] : int64 | strconv.ParseInt | +| IncorrectIntegerConversion.go:334:9:334:21 | type conversion | IncorrectIntegerConversion.go:330:3:330:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:334:9:334:21 | type conversion | Incorrect conversion of a 32-bit integer from $@ to a lower bit size type int16 without an upper bound check. | IncorrectIntegerConversion.go:330:3:330:48 | ... := ...[0] : int64 | strconv.ParseInt | +| IncorrectIntegerConversion.go:342:8:342:20 | type conversion | IncorrectIntegerConversion.go:338:3:338:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:342:8:342:20 | type conversion | Incorrect conversion of a 32-bit integer from $@ to a lower bit size type int16 without an upper bound check. | IncorrectIntegerConversion.go:338:3:338:48 | ... := ...[0] : int64 | strconv.ParseInt | +| IncorrectIntegerConversion.go:351:9:351:17 | type conversion | IncorrectIntegerConversion.go:346:3:346:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:351:9:351:17 | type conversion | Incorrect conversion of a 32-bit integer from $@ to a lower bit size type int16 without an upper bound check. | IncorrectIntegerConversion.go:346:3:346:48 | ... := ...[0] : int64 | strconv.ParseInt | +| IncorrectIntegerConversion.go:362:7:362:14 | type conversion | IncorrectIntegerConversion.go:355:3:355:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:362:7:362:14 | type conversion | Incorrect conversion of a 16-bit integer from $@ to a lower bit size type int8 without an upper bound check. | IncorrectIntegerConversion.go:355:3:355:48 | ... := ...[0] : int64 | strconv.ParseInt | +| IncorrectIntegerConversion.go:371:6:371:17 | type conversion | IncorrectIntegerConversion.go:367:2:367:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:371:6:371:17 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from $@ to a lower bit size type int8 without an upper bound check. | IncorrectIntegerConversion.go:367:2:367:60 | ... := ...[0] : int64 | strconv.ParseInt | +| IncorrectIntegerConversion.go:372:6:372:18 | type conversion | IncorrectIntegerConversion.go:367:2:367:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:372:6:372:18 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from $@ to a lower bit size type uint8 without an upper bound check. | IncorrectIntegerConversion.go:367:2:367:60 | ... := ...[0] : int64 | strconv.ParseInt | +| IncorrectIntegerConversion.go:373:6:373:18 | type conversion | IncorrectIntegerConversion.go:367:2:367:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:373:6:373:18 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from $@ to a lower bit size type int16 without an upper bound check. | IncorrectIntegerConversion.go:367:2:367:60 | ... := ...[0] : int64 | strconv.ParseInt | +| IncorrectIntegerConversion.go:374:6:374:19 | type conversion | IncorrectIntegerConversion.go:367:2:367:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:374:6:374:19 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from $@ to a lower bit size type uint16 without an upper bound check. | IncorrectIntegerConversion.go:367:2:367:60 | ... := ...[0] : int64 | strconv.ParseInt | +| IncorrectIntegerConversion.go:375:6:375:18 | type conversion | IncorrectIntegerConversion.go:367:2:367:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:375:6:375:18 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from $@ to a lower bit size type int32 without an upper bound check. | IncorrectIntegerConversion.go:367:2:367:60 | ... := ...[0] : int64 | strconv.ParseInt | +| IncorrectIntegerConversion.go:376:6:376:19 | type conversion | IncorrectIntegerConversion.go:367:2:367:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:376:6:376:19 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from $@ to a lower bit size type uint32 without an upper bound check. | IncorrectIntegerConversion.go:367:2:367:60 | ... := ...[0] : int64 | strconv.ParseInt | +| TestNoArchitectureBuildConstraints.go:16:7:16:19 | type conversion | TestNoArchitectureBuildConstraints.go:12:3:12:48 | ... := ...[0] : int64 | TestNoArchitectureBuildConstraints.go:16:7:16:19 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from $@ to a lower bit size type int32 without an upper bound check. | TestNoArchitectureBuildConstraints.go:12:3:12:48 | ... := ...[0] : int64 | strconv.ParseInt | +| TestNoArchitectureBuildConstraints.go:17:7:17:20 | type conversion | TestNoArchitectureBuildConstraints.go:12:3:12:48 | ... := ...[0] : int64 | TestNoArchitectureBuildConstraints.go:17:7:17:20 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from $@ to a lower bit size type uint32 without an upper bound check. | TestNoArchitectureBuildConstraints.go:12:3:12:48 | ... := ...[0] : int64 | strconv.ParseInt | +| TestNoArchitectureBuildConstraints.go:24:7:24:17 | type conversion | TestNoArchitectureBuildConstraints.go:20:3:20:49 | ... := ...[0] : int64 | TestNoArchitectureBuildConstraints.go:24:7:24:17 | type conversion | Incorrect conversion of a 64-bit integer from $@ to a lower bit size type int without an upper bound check. | TestNoArchitectureBuildConstraints.go:20:3:20:49 | ... := ...[0] : int64 | strconv.ParseInt | +| TestNoArchitectureBuildConstraints.go:25:7:25:18 | type conversion | TestNoArchitectureBuildConstraints.go:20:3:20:49 | ... := ...[0] : int64 | TestNoArchitectureBuildConstraints.go:25:7:25:18 | type conversion | Incorrect conversion of a 64-bit integer from $@ to a lower bit size type uint without an upper bound check. | TestNoArchitectureBuildConstraints.go:20:3:20:49 | ... := ...[0] : int64 | strconv.ParseInt | diff --git a/ql/test/query-tests/Security/CWE-681/IncorrectIntegerConversion.go b/ql/test/query-tests/Security/CWE-681/IncorrectIntegerConversion.go new file mode 100644 index 00000000000..b99f1f42691 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-681/IncorrectIntegerConversion.go @@ -0,0 +1,381 @@ +package main + +import ( + "math" + "strconv" +) + +func main() { + +} + +type something struct { +} +type config struct { +} +type registry struct { +} + +func lookupTarget(conf *config, num int32) (int32, error) { + return 567, nil +} +func lookupNumberByName(reg *registry, name string) (int32, error) { + return 567, nil +} +func lab(s string) (*something, error) { + num, err := strconv.Atoi(s) + + if err != nil { + number, err := lookupNumberByName(®istry{}, s) + if err != nil { + return nil, err + } + num = int(number) + } + target, err := lookupTarget(&config{}, int32(num)) // NOT OK + if err != nil { + return nil, err + } + + // convert the resolved target number back to a string + + s = strconv.Itoa(int(target)) + + return nil, nil +} + +func testParseInt() { + { + parsed, err := strconv.ParseInt("3456", 10, 8) + if err != nil { + panic(err) + } + _ = int8(parsed) // OK + _ = uint8(parsed) // OK + _ = int16(parsed) // OK + _ = uint16(parsed) // OK + _ = int32(parsed) // OK + _ = uint32(parsed) // OK + _ = int64(parsed) // OK + _ = uint64(parsed) // OK + _ = int(parsed) // OK + _ = uint(parsed) // OK + } + { + parsed, err := strconv.ParseInt("3456", 10, 16) + if err != nil { + panic(err) + } + _ = int8(parsed) // NOT OK + _ = uint8(parsed) // NOT OK + _ = int16(parsed) // OK + _ = uint16(parsed) // OK + _ = int32(parsed) // OK + _ = uint32(parsed) // OK + _ = int64(parsed) // OK + _ = uint64(parsed) // OK + _ = int(parsed) // OK + _ = uint(parsed) // OK + } + { + parsed, err := strconv.ParseInt("3456", 10, 32) + if err != nil { + panic(err) + } + _ = int8(parsed) // NOT OK + _ = uint8(parsed) // NOT OK + _ = int16(parsed) // NOT OK + _ = uint16(parsed) // NOT OK + _ = int32(parsed) // OK + _ = uint32(parsed) // OK + _ = int64(parsed) // OK + _ = uint64(parsed) // OK + _ = int(parsed) // OK + _ = uint(parsed) // OK + } + { + parsed, err := strconv.ParseInt("3456", 10, 64) + if err != nil { + panic(err) + } + _ = int8(parsed) // NOT OK + _ = uint8(parsed) // NOT OK + _ = int16(parsed) // NOT OK + _ = uint16(parsed) // NOT OK + _ = int32(parsed) // NOT OK + _ = uint32(parsed) // NOT OK + _ = int64(parsed) // OK + _ = uint64(parsed) // OK + _ = int(parsed) // NOT OK + _ = uint(parsed) // NOT OK + } + { + parsed, err := strconv.ParseInt("3456", 10, 0) + if err != nil { + panic(err) + } + _ = int8(parsed) // NOT OK + _ = uint8(parsed) // NOT OK + _ = int16(parsed) // NOT OK + _ = uint16(parsed) // NOT OK + _ = int32(parsed) // NOT OK + _ = uint32(parsed) // NOT OK + _ = int64(parsed) // OK + _ = uint64(parsed) // OK + _ = int(parsed) // OK + _ = uint(parsed) // OK + } +} + +func testParseUint() { + { + parsed, err := strconv.ParseUint("3456", 10, 8) + if err != nil { + panic(err) + } + _ = int8(parsed) // OK + _ = uint8(parsed) // OK + _ = int16(parsed) // OK + _ = uint16(parsed) // OK + _ = int32(parsed) // OK + _ = uint32(parsed) // OK + _ = int64(parsed) // OK + _ = uint64(parsed) // OK + _ = int(parsed) // OK + _ = uint(parsed) // OK + } + { + parsed, err := strconv.ParseUint("3456", 10, 16) + if err != nil { + panic(err) + } + _ = int8(parsed) // NOT OK + _ = uint8(parsed) // NOT OK + _ = int16(parsed) // OK + _ = uint16(parsed) // OK + _ = int32(parsed) // OK + _ = uint32(parsed) // OK + _ = int64(parsed) // OK + _ = uint64(parsed) // OK + _ = int(parsed) // OK + _ = uint(parsed) // OK + } + { + parsed, err := strconv.ParseUint("3456", 10, 32) + if err != nil { + panic(err) + } + _ = int8(parsed) // NOT OK + _ = uint8(parsed) // NOT OK + _ = int16(parsed) // NOT OK + _ = uint16(parsed) // NOT OK + _ = int32(parsed) // OK + _ = uint32(parsed) // OK + _ = int64(parsed) // OK + _ = uint64(parsed) // OK + _ = int(parsed) // OK + _ = uint(parsed) // OK + } + { + parsed, err := strconv.ParseUint("3456", 10, 64) + if err != nil { + panic(err) + } + _ = int8(parsed) // NOT OK + _ = uint8(parsed) // NOT OK + _ = int16(parsed) // NOT OK + _ = uint16(parsed) // NOT OK + _ = int32(parsed) // NOT OK + _ = uint32(parsed) // NOT OK + _ = int64(parsed) // OK + _ = uint64(parsed) // OK + _ = int(parsed) // NOT OK + _ = uint(parsed) // NOT OK + } + { + parsed, err := strconv.ParseUint("3456", 10, 0) + if err != nil { + panic(err) + } + _ = int8(parsed) // NOT OK + _ = uint8(parsed) // NOT OK + _ = int16(parsed) // NOT OK + _ = uint16(parsed) // NOT OK + _ = int32(parsed) // NOT OK + _ = uint32(parsed) // NOT OK + _ = int64(parsed) // OK + _ = uint64(parsed) // OK + _ = int(parsed) // OK + _ = uint(parsed) // OK + } +} + +func testAtoi() { + parsed, err := strconv.Atoi("3456") + if err != nil { + panic(err) + } + _ = int8(parsed) // NOT OK + _ = uint8(parsed) // NOT OK + _ = int16(parsed) // NOT OK + _ = uint16(parsed) // NOT OK + _ = int32(parsed) // NOT OK + _ = uint32(parsed) // NOT OK + _ = int64(parsed) // OK + _ = uint64(parsed) // OK + _ = int(parsed) // OK + _ = uint(parsed) // OK +} + +type customInt int16 + +// these should be caught: +func typeAliases(input string) { + { + parsed, err := strconv.ParseInt(input, 10, 32) + if err != nil { + panic(err) + } + // NOTE: byte is uint8 + _ = byte(parsed) // NOT OK + _ = customInt(parsed) // NOT OK + } +} + +func testBoundsChecking(input string) { + { + parsed, err := strconv.Atoi(input) + if err != nil { + panic(err) + } + if parsed <= math.MaxInt8 && parsed >= math.MinInt8 { + _ = int8(parsed) // OK + } + if parsed < math.MaxInt8 { + _ = int8(parsed) // OK (because we only check for upper bounds) + if parsed >= 0 { + _ = int16(parsed) // OK + } + } + if parsed >= math.MinInt8 { + _ = int8(parsed) // NOT OK + if parsed <= 0 { + _ = int16(parsed) // OK + } + } + } + { + parsed, err := strconv.ParseUint(input, 10, 32) + if err != nil { + panic(err) + } + if parsed <= math.MaxInt8 { + _ = uint8(parsed) // OK + } + if parsed < 5 { + _ = uint16(parsed) // OK + } + if err == nil && 1 == 1 && parsed < math.MaxInt8 { + _ = int8(parsed) // OK + } + if parsed > 42 { + _ = uint16(parsed) // NOT OK + } + if parsed > 5 { + return + } + _ = uint8(parsed) // OK + } +} + +func testRightShifted(input string) { + { + parsed, err := strconv.ParseInt(input, 10, 32) + if err != nil { + panic(err) + } + _ = byte(parsed) // OK + _ = byte(parsed >> 8) + _ = byte(parsed >> 16) + _ = byte(parsed >> 24) + } + { + parsed, err := strconv.ParseInt(input, 10, 16) + if err != nil { + panic(err) + } + _ = byte(parsed) // OK + _ = byte(parsed & 0xff00 >> 8) + } + { + parsed, err := strconv.ParseInt(input, 10, 32) + if err != nil { + panic(err) + } + _ = byte(parsed) // OK + _ = byte(parsed >> 8 & 0xff) + } + { + parsed, err := strconv.ParseInt(input, 10, 16) + if err != nil { + panic(err) + } + _ = byte(parsed) // NOT OK + _ = byte(parsed << 8) + } +} + +func testPathWithMoreThanOneSink(input string) { + { + parsed, err := strconv.ParseInt(input, 10, 32) + if err != nil { + panic(err) + } + v1 := int16(parsed) // NOT OK + _ = int16(v1) // OK + } + { + parsed, err := strconv.ParseInt(input, 10, 32) + if err != nil { + panic(err) + } + v := int16(parsed) // NOT OK + _ = int8(v) // OK + } + { + parsed, err := strconv.ParseInt(input, 10, 32) + if err != nil { + panic(err) + } + v1 := int32(parsed) // OK + v2 := int16(v1) // NOT OK + _ = int8(v2) // OK + } + { + parsed, err := strconv.ParseInt(input, 10, 16) + if err != nil { + panic(err) + } + v1 := int64(parsed) // OK + v2 := int32(v1) // OK + v3 := int16(v2) // OK + _ = int8(v3) // NOT OK + } +} + +func testUsingStrConvIntSize(input string) { + parsed, err := strconv.ParseInt(input, 10, strconv.IntSize) + if err != nil { + panic(err) + } + _ = int8(parsed) // NOT OK + _ = uint8(parsed) // NOT OK + _ = int16(parsed) // NOT OK + _ = uint16(parsed) // NOT OK + _ = int32(parsed) // NOT OK + _ = uint32(parsed) // NOT OK + _ = int64(parsed) // OK + _ = uint64(parsed) // OK + _ = int(parsed) // OK + _ = uint(parsed) // OK +} diff --git a/ql/test/query-tests/Security/CWE-681/IncorrectIntegerConversion.qlref b/ql/test/query-tests/Security/CWE-681/IncorrectIntegerConversion.qlref new file mode 100644 index 00000000000..47d8c34c0ee --- /dev/null +++ b/ql/test/query-tests/Security/CWE-681/IncorrectIntegerConversion.qlref @@ -0,0 +1 @@ +Security/CWE-681/IncorrectIntegerConversion.ql diff --git a/ql/test/query-tests/Security/CWE-681/Test32BitArchitectureBuildConstraintInFileName_386.go b/ql/test/query-tests/Security/CWE-681/Test32BitArchitectureBuildConstraintInFileName_386.go new file mode 100644 index 00000000000..ac1200dc4d5 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-681/Test32BitArchitectureBuildConstraintInFileName_386.go @@ -0,0 +1,34 @@ +// Note that the filename acts as an implicit build constraint + +package main + +import ( + "strconv" +) + +func testIntSource386() { + { + parsed, err := strconv.ParseInt("3456", 10, 0) + if err != nil { + panic(err) + } + _ = int32(parsed) // OK + _ = uint32(parsed) // OK + } + { + parsed, err := strconv.ParseUint("3456", 10, 0) + if err != nil { + panic(err) + } + _ = int32(parsed) // OK + _ = uint32(parsed) // OK + } + { + parsed, err := strconv.Atoi("3456") + if err != nil { + panic(err) + } + _ = int32(parsed) // OK + _ = uint32(parsed) // OK + } +} diff --git a/ql/test/query-tests/Security/CWE-681/Test32BitArchitectureBuildConstraints.go b/ql/test/query-tests/Security/CWE-681/Test32BitArchitectureBuildConstraints.go new file mode 100644 index 00000000000..11e317d46cd --- /dev/null +++ b/ql/test/query-tests/Security/CWE-681/Test32BitArchitectureBuildConstraints.go @@ -0,0 +1,36 @@ +// +build 386 amd64p32 arm armbe mips mipsle mips64p32 mips64p32le ppc s390 sparc +// +build gc +// +build go1.4 + +package main + +import ( + "strconv" +) + +func testIntSource32() { + { + parsed, err := strconv.ParseInt("3456", 10, 0) + if err != nil { + panic(err) + } + _ = int32(parsed) // OK + _ = uint32(parsed) // OK + } + { + parsed, err := strconv.ParseUint("3456", 10, 0) + if err != nil { + panic(err) + } + _ = int32(parsed) // OK + _ = uint32(parsed) // OK + } + { + parsed, err := strconv.Atoi("3456") + if err != nil { + panic(err) + } + _ = int32(parsed) // OK + _ = uint32(parsed) // OK + } +} diff --git a/ql/test/query-tests/Security/CWE-681/Test64BitArchitectureBuildConstraintInFileName_amd64.go b/ql/test/query-tests/Security/CWE-681/Test64BitArchitectureBuildConstraintInFileName_amd64.go new file mode 100644 index 00000000000..95c2cf92860 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-681/Test64BitArchitectureBuildConstraintInFileName_amd64.go @@ -0,0 +1,26 @@ +// Note that the filename acts as an implicit build constraint + +package main + +import ( + "strconv" +) + +func testIntSinkAmd64() { + { + parsed, err := strconv.ParseInt("3456", 10, 64) + if err != nil { + panic(err) + } + _ = int(parsed) // OK + _ = uint(parsed) // OK + } + { + parsed, err := strconv.ParseUint("3456", 10, 64) + if err != nil { + panic(err) + } + _ = int(parsed) // OK + _ = uint(parsed) // OK + } +} diff --git a/ql/test/query-tests/Security/CWE-681/Test64BitArchitectureBuildConstraints.go b/ql/test/query-tests/Security/CWE-681/Test64BitArchitectureBuildConstraints.go new file mode 100644 index 00000000000..82bd2965cee --- /dev/null +++ b/ql/test/query-tests/Security/CWE-681/Test64BitArchitectureBuildConstraints.go @@ -0,0 +1,28 @@ +// +build amd64 arm64 arm64be ppc64 ppc64le mips64 mips64le s390x sparc64 +// +build gc +// +build go1.4 + +package main + +import ( + "strconv" +) + +func testIntSink64() { + { + parsed, err := strconv.ParseInt("3456", 10, 64) + if err != nil { + panic(err) + } + _ = int(parsed) // OK + _ = uint(parsed) // OK + } + { + parsed, err := strconv.ParseUint("3456", 10, 64) + if err != nil { + panic(err) + } + _ = int(parsed) // OK + _ = uint(parsed) // OK + } +} diff --git a/ql/test/query-tests/Security/CWE-681/TestNoArchitectureBuildConstraints.go b/ql/test/query-tests/Security/CWE-681/TestNoArchitectureBuildConstraints.go new file mode 100644 index 00000000000..98cb6abdd61 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-681/TestNoArchitectureBuildConstraints.go @@ -0,0 +1,27 @@ +// +build gc +// +build go1.4 + +package main + +import ( + "strconv" +) + +func testIntSizeIsArchicturallyDependent1() { + { + parsed, err := strconv.ParseInt("3456", 10, 0) + if err != nil { + panic(err) + } + _ = int32(parsed) // NOT OK + _ = uint32(parsed) // NOT OK + } + { + parsed, err := strconv.ParseInt("3456", 10, 64) + if err != nil { + panic(err) + } + _ = int(parsed) // NOT OK + _ = uint(parsed) // NOT OK + } +}