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