Merge pull request #19535 from geoffw0/operations2

Rust: Add ComparisonOperation library.
This commit is contained in:
Geoffrey White
2025-05-22 13:41:53 +01:00
committed by GitHub
6 changed files with 145 additions and 39 deletions

View File

@@ -0,0 +1,101 @@
/**
* Provides classes for comparison operations.
*/
private import codeql.rust.elements.BinaryExpr
private import codeql.rust.elements.Operation
/**
* A comparison operation, such as `==`, `<`, or `>=`.
*/
abstract private class ComparisonOperationImpl extends Operation { }
final class ComparisonOperation = ComparisonOperationImpl;
/**
* An equality comparison operation, `==` or `!=`.
*/
abstract private class EqualityOperationImpl extends BinaryExpr, ComparisonOperationImpl { }
final class EqualityOperation = EqualityOperationImpl;
/**
* The equal comparison operation, `==`.
*/
final class EqualsOperation extends EqualityOperationImpl {
EqualsOperation() { this.getOperatorName() = "==" }
}
/**
* The not equal comparison operation, `!=`.
*/
final class NotEqualsOperation extends EqualityOperationImpl {
NotEqualsOperation() { this.getOperatorName() = "!=" }
}
/**
* A relational comparison operation, that is, one of `<=`, `<`, `>`, or `>=`.
*/
abstract private class RelationalOperationImpl extends BinaryExpr, ComparisonOperationImpl {
/**
* Gets the operand on the "greater" (or "greater-or-equal") side
* of this relational expression, that is, the side that is larger
* if the overall expression evaluates to `true`; for example on
* `x <= 20` this is the `20`, and on `y > 0` it is `y`.
*/
abstract Expr getGreaterOperand();
/**
* Gets the operand on the "lesser" (or "lesser-or-equal") side
* of this relational expression, that is, the side that is smaller
* if the overall expression evaluates to `true`; for example on
* `x <= 20` this is `x`, and on `y > 0` it is the `0`.
*/
abstract Expr getLesserOperand();
}
final class RelationalOperation = RelationalOperationImpl;
/**
* The less than comparison operation, `<`.
*/
final class LessThanOperation extends RelationalOperationImpl {
LessThanOperation() { this.getOperatorName() = "<" }
override Expr getGreaterOperand() { result = this.getRhs() }
override Expr getLesserOperand() { result = this.getLhs() }
}
/**
* The greater than comparison operation, `>`.
*/
final class GreaterThanOperation extends RelationalOperationImpl {
GreaterThanOperation() { this.getOperatorName() = ">" }
override Expr getGreaterOperand() { result = this.getLhs() }
override Expr getLesserOperand() { result = this.getRhs() }
}
/**
* The less than or equal comparison operation, `<=`.
*/
final class LessOrEqualsOperation extends RelationalOperationImpl {
LessOrEqualsOperation() { this.getOperatorName() = "<=" }
override Expr getGreaterOperand() { result = this.getRhs() }
override Expr getLesserOperand() { result = this.getLhs() }
}
/**
* The greater than or equal comparison operation, `>=`.
*/
final class GreaterOrEqualsOperation extends RelationalOperationImpl {
GreaterOrEqualsOperation() { this.getOperatorName() = ">=" }
override Expr getGreaterOperand() { result = this.getLhs() }
override Expr getLesserOperand() { result = this.getRhs() }
}

View File

@@ -1,3 +1,7 @@
/**
* Provides classes for logical operations.
*/
private import codeql.rust.elements.Expr
private import codeql.rust.elements.BinaryExpr
private import codeql.rust.elements.PrefixExpr

View File

@@ -43,51 +43,23 @@ module UncontrolledAllocationSize {
}
}
/**
* Gets the operand on the "greater" (or "greater-or-equal") side
* of this relational expression, that is, the side that is larger
* if the overall expression evaluates to `true`; for example on
* `x <= 20` this is the `20`, and on `y > 0` it is `y`.
*/
private Expr getGreaterOperand(BinaryExpr op) {
op.getOperatorName() = ["<", "<="] and
result = op.getRhs()
or
op.getOperatorName() = [">", ">="] and
result = op.getLhs()
}
/**
* Gets the operand on the "lesser" (or "lesser-or-equal") side
* of this relational expression, that is, the side that is smaller
* if the overall expression evaluates to `true`; for example on
* `x <= 20` this is `x`, and on `y > 0` it is the `0`.
*/
private Expr getLesserOperand(BinaryExpr op) {
op.getOperatorName() = ["<", "<="] and
result = op.getLhs()
or
op.getOperatorName() = [">", ">="] and
result = op.getRhs()
}
/**
* Holds if comparison `g` having result `branch` indicates an upper bound for the sub-expression
* `node`. For example when the comparison `x < 10` is true, we have an upper bound for `x`.
*/
private predicate isUpperBoundCheck(CfgNodes::AstCfgNode g, Cfg::CfgNode node, boolean branch) {
exists(BinaryExpr cmp | g = cmp.getACfgNode() |
node = getLesserOperand(cmp).getACfgNode() and
node = cmp.(RelationalOperation).getLesserOperand().getACfgNode() and
branch = true
or
node = getGreaterOperand(cmp).getACfgNode() and
node = cmp.(RelationalOperation).getGreaterOperand().getACfgNode() and
branch = false
or
cmp.getOperatorName() = "==" and
cmp instanceof EqualsOperation and
[cmp.getLhs(), cmp.getRhs()].getACfgNode() = node and
branch = true
or
cmp.getOperatorName() = "!=" and
cmp instanceof NotEqualsOperation and
[cmp.getLhs(), cmp.getRhs()].getACfgNode() = node and
branch = false
)

View File

@@ -5,6 +5,7 @@ import codeql.Locations
import codeql.files.FileSystem
import codeql.rust.elements.Operation
import codeql.rust.elements.AssignmentOperation
import codeql.rust.elements.ComparisonOperation
import codeql.rust.elements.LiteralExprExt
import codeql.rust.elements.LogicalOperation
import codeql.rust.elements.AsyncBlockExpr

View File

@@ -13,10 +13,30 @@ string describe(Expr op) {
op instanceof LogicalOperation and result = "LogicalOperation"
or
op instanceof RefExpr and result = "RefExpr"
or
op instanceof ComparisonOperation and result = "ComparisonOperation"
or
op instanceof EqualityOperation and result = "EqualityOperation"
or
op instanceof EqualsOperation and result = "EqualsOperation"
or
op instanceof NotEqualsOperation and result = "NotEqualsOperation"
or
op instanceof RelationalOperation and result = "RelationalOperation"
or
op instanceof LessThanOperation and result = "LessThanOperation"
or
op instanceof GreaterThanOperation and result = "GreaterThanOperation"
or
op instanceof LessOrEqualsOperation and result = "LessOrEqualsOperation"
or
op instanceof GreaterOrEqualsOperation and result = "GreaterOrEqualsOperation"
}
module OperationsTest implements TestSig {
string getARelevantTag() { result = describe(_) or result = ["Op", "Operands"] }
string getARelevantTag() {
result = describe(_) or result = ["Op", "Operands", "Greater", "Lesser"]
}
predicate hasActualResult(Location location, string element, string tag, string value) {
exists(Expr op |
@@ -33,6 +53,14 @@ module OperationsTest implements TestSig {
op instanceof Operation and
tag = "Operands" and
value = count(op.(Operation).getAnOperand()).toString()
or
op instanceof RelationalOperation and
tag = "Greater" and
value = op.(RelationalOperation).getGreaterOperand().toString()
or
op instanceof RelationalOperation and
tag = "Lesser" and
value = op.(RelationalOperation).getLesserOperand().toString()
)
)
}

View File

@@ -11,12 +11,12 @@ fn test_operations(
x = y; // $ Operation Op== Operands=2 AssignmentOperation BinaryExpr
// comparison operations
x == y; // $ Operation Op=== Operands=2 BinaryExpr
x != y; // $ Operation Op=!= Operands=2 BinaryExpr
x < y; // $ Operation Op=< Operands=2 BinaryExpr
x <= y; // $ Operation Op=<= Operands=2 BinaryExpr
x > y; // $ Operation Op=> Operands=2 BinaryExpr
x >= y; // $ Operation Op=>= Operands=2 BinaryExpr
x == y; // $ Operation Op=== Operands=2 BinaryExpr ComparisonOperation EqualityOperation EqualsOperation
x != y; // $ Operation Op=!= Operands=2 BinaryExpr ComparisonOperation EqualityOperation NotEqualsOperation
x < y; // $ Operation Op=< Operands=2 BinaryExpr ComparisonOperation RelationalOperation LessThanOperation Greater=y Lesser=x
x <= y; // $ Operation Op=<= Operands=2 BinaryExpr ComparisonOperation RelationalOperation LessOrEqualsOperation Greater=y Lesser=x
x > y; // $ Operation Op=> Operands=2 BinaryExpr ComparisonOperation RelationalOperation GreaterThanOperation Greater=x Lesser=y
x >= y; // $ Operation Op=>= Operands=2 BinaryExpr ComparisonOperation RelationalOperation GreaterOrEqualsOperation Greater=x Lesser=y
// arithmetic operations
x + y; // $ Operation Op=+ Operands=2 BinaryExpr