diff --git a/config/identical-files.json b/config/identical-files.json index 8a5c00a49f88..818f033e4db5 100644 --- a/config/identical-files.json +++ b/config/identical-files.json @@ -11,10 +11,6 @@ "java/ql/lib/semmle/code/java/dataflow/internal/rangeanalysis/SignAnalysisCommon.qll", "csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/SignAnalysisCommon.qll" ], - "Bound Java/C#": [ - "java/ql/lib/semmle/code/java/dataflow/Bound.qll", - "csharp/ql/lib/semmle/code/csharp/dataflow/Bound.qll" - ], "ModulusAnalysis Java/C#": [ "java/ql/lib/semmle/code/java/dataflow/ModulusAnalysis.qll", "csharp/ql/lib/semmle/code/csharp/dataflow/ModulusAnalysis.qll" diff --git a/csharp/ql/lib/qlpack.yml b/csharp/ql/lib/qlpack.yml index ca43ae8b07bc..638f99026429 100644 --- a/csharp/ql/lib/qlpack.yml +++ b/csharp/ql/lib/qlpack.yml @@ -9,6 +9,7 @@ dependencies: codeql/controlflow: ${workspace} codeql/dataflow: ${workspace} codeql/mad: ${workspace} + codeql/rangeanalysis: ${workspace} codeql/ssa: ${workspace} codeql/threat-models: ${workspace} codeql/tutorial: ${workspace} diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/Bound.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/Bound.qll index 65af6fb13a81..4f03a735a694 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/Bound.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/Bound.qll @@ -4,67 +4,31 @@ overlay[local?] module; -private import internal.rangeanalysis.BoundSpecific +private import csharp as CS +private import semmle.code.csharp.dataflow.SSA::Ssa +private import semmle.code.csharp.dataflow.internal.rangeanalysis.ConstantUtils as CU +private import semmle.code.csharp.dataflow.internal.rangeanalysis.RangeUtils as RU +private import semmle.code.csharp.dataflow.internal.rangeanalysis.SsaUtils as SU +private import codeql.rangeanalysis.Bound as SharedBound -private newtype TBound = - TBoundZero() or - TBoundSsa(SsaVariable v) { v.getSourceVariable().getType() instanceof IntegralType } or - TBoundExpr(Expr e) { - interestingExprBound(e) and - not exists(SsaVariable v | e = v.getAUse()) - } +/** Provides C#-specific definitions for bounds. */ +private module BoundDefs implements SharedBound::BoundDefinitions { + class Type = CS::Type; -/** - * A bound that may be inferred for an expression plus/minus an integer delta. - */ -abstract class Bound extends TBound { - /** Gets a textual representation of this bound. */ - abstract string toString(); + class SsaVariable = SU::SsaVariable; - /** Gets an expression that equals this bound plus `delta`. */ - abstract Expr getExpr(int delta); + class SsaSourceVariable = SourceVariable; - /** Gets an expression that equals this bound. */ - Expr getExpr() { result = this.getExpr(0) } + class Expr = CS::ControlFlowNodes::ExprNode; - /** Gets the location of this bound. */ - abstract Location getLocation(); -} + class IntegralType = CS::IntegralType; -/** - * The bound that corresponds to the integer 0. This is used to represent all - * integer bounds as bounds are always accompanied by an added integer delta. - */ -class ZeroBound extends Bound, TBoundZero { - override string toString() { result = "0" } + class ConstantIntegerExpr = CU::ConstantIntegerExpr; - override Expr getExpr(int delta) { result.(ConstantIntegerExpr).getIntValue() = delta } - - override Location getLocation() { result.hasLocationInfo("", 0, 0, 0, 0) } + /** Holds if `e` is a bound expression and it is not an SSA variable read. */ + predicate interestingExprBound(Expr e) { CU::systemArrayLengthAccess(e.getExpr()) } } -/** - * A bound corresponding to the value of an SSA variable. - */ -class SsaBound extends Bound, TBoundSsa { - /** Gets the SSA variable that equals this bound. */ - SsaVariable getSsa() { this = TBoundSsa(result) } - - override string toString() { result = this.getSsa().toString() } +module BoundImpl = SharedBound::Bound; - override Expr getExpr(int delta) { result = this.getSsa().getAUse() and delta = 0 } - - override Location getLocation() { result = this.getSsa().getLocation() } -} - -/** - * A bound that corresponds to the value of a specific expression that might be - * interesting, but isn't otherwise represented by the value of an SSA variable. - */ -class ExprBound extends Bound, TBoundExpr { - override string toString() { result = this.getExpr().toString() } - - override Expr getExpr(int delta) { this = TBoundExpr(result) and delta = 0 } - - override Location getLocation() { result = this.getExpr().getLocation() } -} +import BoundImpl diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/BoundSpecific.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/BoundSpecific.qll deleted file mode 100644 index 037422684306..000000000000 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/BoundSpecific.qll +++ /dev/null @@ -1,22 +0,0 @@ -/** - * Provides C#-specific definitions for bounds. - */ - -private import csharp as CS -private import semmle.code.csharp.dataflow.SSA::Ssa as Ssa -private import semmle.code.csharp.dataflow.internal.rangeanalysis.ConstantUtils as CU -private import semmle.code.csharp.dataflow.internal.rangeanalysis.RangeUtils as RU -private import semmle.code.csharp.dataflow.internal.rangeanalysis.SsaUtils as SU - -class SsaVariable = SU::SsaVariable; - -class Expr = CS::ControlFlowNodes::ExprNode; - -class Location = CS::Location; - -class IntegralType = CS::IntegralType; - -class ConstantIntegerExpr = CU::ConstantIntegerExpr; - -/** Holds if `e` is a bound expression and it is not an SSA variable read. */ -predicate interestingExprBound(Expr e) { CU::systemArrayLengthAccess(e.getExpr()) } diff --git a/java/ql/lib/semmle/code/java/dataflow/Bound.qll b/java/ql/lib/semmle/code/java/dataflow/Bound.qll index 65af6fb13a81..4780b9caccac 100644 --- a/java/ql/lib/semmle/code/java/dataflow/Bound.qll +++ b/java/ql/lib/semmle/code/java/dataflow/Bound.qll @@ -4,67 +4,33 @@ overlay[local?] module; -private import internal.rangeanalysis.BoundSpecific - -private newtype TBound = - TBoundZero() or - TBoundSsa(SsaVariable v) { v.getSourceVariable().getType() instanceof IntegralType } or - TBoundExpr(Expr e) { - interestingExprBound(e) and - not exists(SsaVariable v | e = v.getAUse()) +private import java as J +private import semmle.code.java.dataflow.SSA +private import semmle.code.java.dataflow.RangeUtils as RU +private import codeql.rangeanalysis.Bound as SharedBound + +private module BoundDefs implements SharedBound::BoundDefinitions { + class SsaVariable extends Ssa::SsaDefinition { + /** Gets a use of this variable. */ + Expr getAUse() { result = super.getARead() } } -/** - * A bound that may be inferred for an expression plus/minus an integer delta. - */ -abstract class Bound extends TBound { - /** Gets a textual representation of this bound. */ - abstract string toString(); - - /** Gets an expression that equals this bound plus `delta`. */ - abstract Expr getExpr(int delta); - - /** Gets an expression that equals this bound. */ - Expr getExpr() { result = this.getExpr(0) } + class SsaSourceVariable = Ssa::SourceVariable; - /** Gets the location of this bound. */ - abstract Location getLocation(); -} + class Type = J::Type; -/** - * The bound that corresponds to the integer 0. This is used to represent all - * integer bounds as bounds are always accompanied by an added integer delta. - */ -class ZeroBound extends Bound, TBoundZero { - override string toString() { result = "0" } + class Expr = J::Expr; - override Expr getExpr(int delta) { result.(ConstantIntegerExpr).getIntValue() = delta } + class IntegralType = J::IntegralType; - override Location getLocation() { result.hasLocationInfo("", 0, 0, 0, 0) } -} + class ConstantIntegerExpr = RU::ConstantIntegerExpr; -/** - * A bound corresponding to the value of an SSA variable. - */ -class SsaBound extends Bound, TBoundSsa { - /** Gets the SSA variable that equals this bound. */ - SsaVariable getSsa() { this = TBoundSsa(result) } - - override string toString() { result = this.getSsa().toString() } - - override Expr getExpr(int delta) { result = this.getSsa().getAUse() and delta = 0 } - - override Location getLocation() { result = this.getSsa().getLocation() } + /** Holds if `e` is a bound expression and it is not an SSA variable read. */ + predicate interestingExprBound(Expr e) { + e.(J::FieldRead).getField() instanceof J::ArrayLengthField + } } -/** - * A bound that corresponds to the value of a specific expression that might be - * interesting, but isn't otherwise represented by the value of an SSA variable. - */ -class ExprBound extends Bound, TBoundExpr { - override string toString() { result = this.getExpr().toString() } +module BoundImpl = SharedBound::Bound; - override Expr getExpr(int delta) { this = TBoundExpr(result) and delta = 0 } - - override Location getLocation() { result = this.getExpr().getLocation() } -} +import BoundImpl diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/rangeanalysis/BoundSpecific.qll b/java/ql/lib/semmle/code/java/dataflow/internal/rangeanalysis/BoundSpecific.qll deleted file mode 100644 index cd85883f7bc4..000000000000 --- a/java/ql/lib/semmle/code/java/dataflow/internal/rangeanalysis/BoundSpecific.qll +++ /dev/null @@ -1,27 +0,0 @@ -/** - * Provides Java-specific definitions for bounds. - */ -overlay[local?] -module; - -private import java as J -private import semmle.code.java.dataflow.SSA as Ssa -private import semmle.code.java.dataflow.RangeUtils as RU - -class SsaVariable extends Ssa::SsaDefinition { - /** Gets a use of this variable. */ - Expr getAUse() { result = super.getARead() } -} - -class Expr = J::Expr; - -class Location = J::Location; - -class IntegralType = J::IntegralType; - -class ConstantIntegerExpr = RU::ConstantIntegerExpr; - -/** Holds if `e` is a bound expression and it is not an SSA variable read. */ -predicate interestingExprBound(Expr e) { - e.(J::FieldRead).getField() instanceof J::ArrayLengthField -} diff --git a/shared/rangeanalysis/codeql/rangeanalysis/Bound.qll b/shared/rangeanalysis/codeql/rangeanalysis/Bound.qll new file mode 100644 index 000000000000..5bb1723fd0aa --- /dev/null +++ b/shared/rangeanalysis/codeql/rangeanalysis/Bound.qll @@ -0,0 +1,111 @@ +/** + * Provides classes for representing abstract bounds for use in, for example, range analysis. + */ +overlay[local?] +module; + +private import codeql.util.Location + +signature module BoundDefinitions { + class Type; + + class IntegralType extends Type; + + class ConstantIntegerExpr extends Expr { + int getIntValue(); + } + + class SsaSourceVariable { + Type getType(); + } + + class SsaVariable { + SsaSourceVariable getSourceVariable(); + + string toString(); + + Location getLocation(); + + Expr getAUse(); + } + + class Expr { + string toString(); + + Location getLocation(); + } + + predicate interestingExprBound(Expr e); +} + +/** + * Provides classes for representing abstract bounds for use in, for example, range analysis. + * This is a generic implementation of bounds that relies on language specific modules to provide language-specific definitions of expressions, SSA variables, etc. + */ +overlay[local?] +module Bound Defs> { + private import Defs + + private newtype TBound = + TBoundZero() or + TBoundSsa(SsaVariable v) { v.getSourceVariable().getType() instanceof IntegralType } or + TBoundExpr(Expr e) { + interestingExprBound(e) and + not exists(SsaVariable v | e = v.getAUse()) + } + + /** + * A bound that may be inferred for an expression plus/minus an integer delta. + */ + abstract class Bound extends TBound { + /** Gets a textual representation of this bound. */ + abstract string toString(); + + /** Gets an expression that equals this bound plus `delta`. */ + abstract Expr getExpr(int delta); + + /** Gets an expression that equals this bound. */ + Expr getExpr() { result = this.getExpr(0) } + + /** Gets the location of this bound. */ + abstract Location getLocation(); + } + + /** + * The bound that corresponds to the integer 0. This is used to represent all + * integer bounds as bounds are always accompanied by an added integer delta. + */ + class ZeroBound extends Bound, TBoundZero { + override string toString() { result = "0" } + + override Expr getExpr(int delta) { result.(ConstantIntegerExpr).getIntValue() = delta } + + override Location getLocation() { result.hasLocationInfo("", 0, 0, 0, 0) } + } + + /** + * A bound corresponding to the value of an SSA variable. + */ + class SsaBound extends Bound, TBoundSsa { + /** Gets the SSA variable that equals this bound. */ + SsaVariable getSsa() { this = TBoundSsa(result) } + + override string toString() { result = this.getSsa().toString() } + + override Expr getExpr(int delta) { result = this.getSsa().getAUse() and delta = 0 } + + override Location getLocation() { result = this.getSsa().getLocation() } + } + + /** + * A bound that corresponds to the value of a specific expression that might be + * interesting, but isn't otherwise represented by the value of an SSA variable. + */ + class ExprBound extends Bound, TBoundExpr { + override string toString() { result = this.getExpr().toString() } + + override Expr getExpr(int delta) { this = TBoundExpr(result) and delta = 0 } + + override Location getLocation() { result = this.getExpr().getLocation() } + } +}