Merge branch 'main' into felickz/razor-page-handler-sources

This commit is contained in:
Chad Bentz
2026-06-15 11:35:54 -04:00
committed by GitHub
45 changed files with 6679 additions and 357 deletions

View File

@@ -59,9 +59,5 @@ MODULE.bazel @github/codeql-ci-reviewers
/.github/workflows/rust.yml @github/codeql-rust
/.github/workflows/swift.yml @github/codeql-swift
# Misc
/misc/scripts/accept-expected-changes-from-ci.py @RasmusWL
/misc/scripts/generate-code-scanning-query-list.py @RasmusWL
# .devcontainer
/.devcontainer/ @github/codeql-ci-reviewers

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,2 @@
description: Restructure and rename types related to operations.
compatibility: full

View File

@@ -0,0 +1,4 @@
---
category: breaking
---
* Renamed types related to *operation* expressions. The QL classes `BinaryArithmeticOperation`, `BinaryBitwiseOperation`, and `BinaryLogicalOperation` now include compound assignments; for example, `BinaryArithmeticOperation` now includes `a += b`.

View File

@@ -50,15 +50,15 @@ private predicate maybeUsedInElfHashFunction(Variable v, Operation xor, Operatio
|
add instanceof AddOperation and
e1.getAChild*() = add.getAnOperand() and
e1 instanceof BinaryBitwiseOperation and
e2 = e1.(BinaryBitwiseOperation).getLeftOperand() and
e1 instanceof BinaryBitwiseExpr and
e2 = e1.(BinaryBitwiseExpr).getLeftOperand() and
v = addAssign.getTargetVariable() and
addAssign.getAChild*() = add and
(xor instanceof BitwiseXorExpr or xor instanceof AssignXorExpr) and
addAssign.getControlFlowNode().getASuccessor*() = xor.getControlFlowNode() and
xorAssign.getAChild*() = xor and
v = xorAssign.getTargetVariable() and
(notOp instanceof UnaryBitwiseOperation or notOp instanceof AssignBitwiseOperation) and
(notOp instanceof UnaryBitwiseOperation or notOp instanceof AssignBitwiseExpr) and
xor.getControlFlowNode().getASuccessor*() = notOp.getControlFlowNode() and
notAssign.getAChild*() = notOp and
v = notAssign.getTargetVariable() and

View File

@@ -290,7 +290,7 @@ module AssignableInternal {
newtype TAssignableDefinition =
TAssignmentDefinition(Assignment a) {
not a.getLeftOperand() instanceof TupleExpr and
not a instanceof AssignCallOperation and
not a instanceof AssignCallExpr and
not a instanceof AssignCoalesceExpr
} or
TTupleAssignmentDefinition(AssignExpr ae, Expr leaf) { tupleAssignmentDefinition(ae, leaf) } or
@@ -324,7 +324,7 @@ module AssignableInternal {
TAddressOfDefinition(AddressOfExpr aoe) or
TPatternDefinition(TopLevelPatternDecl tlpd) or
TAssignOperationDefinition(AssignOperation ao) {
ao instanceof AssignCallOperation and not ao instanceof CompoundAssignmentOperatorCall
ao instanceof AssignCallExpr and not ao instanceof CompoundAssignmentOperatorCall
or
ao instanceof AssignCoalesceExpr
}

View File

@@ -912,18 +912,17 @@ module Internal {
)
or
// In C#, `null + 1` has type `int?` with value `null`
exists(BinaryOperation bo, Expr o |
bo instanceof BinaryArithmeticOperation or
bo instanceof AssignArithmeticOperation
|
result = bo and
bo.getAnOperand() = e and
bo.getAnOperand() = o and
// The other operand must be provably non-null in order
// for `only if` to hold
nonNullValueImplied(o) and
e != o
)
result =
any(BinaryArithmeticOperation bao |
exists(Expr o |
bao.getAnOperand() = e and
bao.getAnOperand() = o and
// The other operand must be provably non-null in order
// for `only if` to hold
nonNullValueImplied(o) and
e != o
)
)
}
/**
@@ -934,10 +933,10 @@ module Internal {
any(QualifiableExpr qe |
qe.isConditional() and
result = qe.getQualifier()
) or
)
or
// In C#, `null + 1` has type `int?` with value `null`
e = any(BinaryArithmeticOperation bao | result = bao.getAnOperand()) or
e = any(AssignArithmeticOperation aao | result = aao.getAnOperand())
e = any(BinaryArithmeticOperation bao | result = bao.getAnOperand())
}
deprecated predicate isGuard(Expr e, GuardValue val) {

View File

@@ -172,6 +172,10 @@ module Ast implements AstSig<Location> {
class DoStmt = CS::DoStmt;
class UntilStmt extends LoopStmt {
UntilStmt() { none() }
}
final private class FinalForStmt = CS::ForStmt;
class ForStmt extends FinalForStmt {

View File

@@ -124,9 +124,7 @@ private module Internal {
TDispatchDynamicOperatorCall(DynamicOperatorCall doc) or
TDispatchDynamicMemberAccess(DynamicMemberAccess dma) or
TDispatchDynamicElementAccess(DynamicElementAccess dea) or
TDispatchDynamicEventAccess(
AssignArithmeticOperation aao, DynamicMemberAccess dma, string name
) {
TDispatchDynamicEventAccess(AssignArithmeticExpr aao, DynamicMemberAccess dma, string name) {
isPotentialEventCall(aao, dma, name)
} or
TDispatchDynamicObjectCreation(DynamicObjectCreation doc) or
@@ -230,7 +228,7 @@ private module Internal {
* accessor.
*/
private predicate isPotentialEventCall(
AssignArithmeticOperation aao, DynamicMemberAccess dma, string name
AssignArithmeticExpr aao, DynamicMemberAccess dma, string name
) {
aao instanceof DynamicOperatorCall and
dma = aao.getLeftOperand() and
@@ -1397,9 +1395,7 @@ private module Internal {
private class DispatchDynamicEventAccess extends DispatchReflectionOrDynamicCall,
TDispatchDynamicEventAccess
{
override AssignArithmeticOperation getCall() {
this = TDispatchDynamicEventAccess(result, _, _)
}
override AssignArithmeticExpr getCall() { this = TDispatchDynamicEventAccess(result, _, _) }
override string getName() { this = TDispatchDynamicEventAccess(_, _, result) }

View File

@@ -11,19 +11,27 @@ import Expr
* (`UnaryArithmeticOperation`) or a binary arithmetic operation
* (`BinaryArithmeticOperation`).
*/
class ArithmeticOperation extends Operation, @arith_op_expr {
class ArithmeticOperation extends Operation, @arith_operation {
override string getOperator() { none() }
}
/**
* A unary arithmetic operation. Either a unary minus operation
* (`UnaryMinusExpr`), a unary plus operation (`UnaryPlusExpr`),
* or a mutator operation (`MutatorOperation`).
* A binary arithmetic operation. Either a binary arithmetic expression (`BinaryArithmeticExpr`) or
* an arithmetic assignment expression (`AssignArithmeticExpr`).
*/
class UnaryArithmeticOperation extends ArithmeticOperation, UnaryOperation, @un_arith_op_expr { }
class BinaryArithmeticOperation extends ArithmeticOperation, BinaryOperation, @bin_arith_operation {
override string getOperator() { none() }
}
/**
* A unary minus operation, for example `-x`.
* A unary arithmetic operation. Either a unary minus expression
* (`UnaryMinusExpr`), a unary plus expression (`UnaryPlusExpr`),
* or a mutator operation (`MutatorOperation`).
*/
class UnaryArithmeticOperation extends ArithmeticOperation, UnaryOperation, @un_arith_operation { }
/**
* A unary minus expression, for example `-x`.
*/
class UnaryMinusExpr extends UnaryArithmeticOperation, @minus_expr {
override string getOperator() { result = "-" }
@@ -32,7 +40,7 @@ class UnaryMinusExpr extends UnaryArithmeticOperation, @minus_expr {
}
/**
* A unary plus operation, for example `+x`.
* A unary plus expression, for example `+x`.
*/
class UnaryPlusExpr extends UnaryArithmeticOperation, @plus_expr {
override string getOperator() { result = "+" }
@@ -44,40 +52,40 @@ class UnaryPlusExpr extends UnaryArithmeticOperation, @plus_expr {
* A mutator operation. Either an increment operation (`IncrementOperation`)
* or a decrement operation (`DecrementOperation`).
*/
class MutatorOperation extends UnaryArithmeticOperation, @mut_op_expr { }
class MutatorOperation extends UnaryArithmeticOperation, @mut_operation { }
/**
* An increment operation. Either a postfix increment operation
* (`PostIncrExpr`) or a prefix increment operation (`PreIncrExpr`).
* An increment operation. Either a postfix increment expression
* (`PostIncrExpr`) or a prefix increment expression (`PreIncrExpr`).
*/
class IncrementOperation extends MutatorOperation, @incr_op_expr {
class IncrementOperation extends MutatorOperation, @incr_operation {
override string getOperator() { result = "++" }
}
/**
* A decrement operation. Either a postfix decrement operation
* (`PostDecrExpr`) or a prefix decrement operation (`PreDecrExpr`).
* A decrement operation. Either a postfix decrement expression
* (`PostDecrExpr`) or a prefix decrement expression (`PreDecrExpr`).
*/
class DecrementOperation extends MutatorOperation, @decr_op_expr {
class DecrementOperation extends MutatorOperation, @decr_operation {
override string getOperator() { result = "--" }
}
/**
* A prefix increment operation, for example `++x`.
* A prefix increment expression, for example `++x`.
*/
class PreIncrExpr extends IncrementOperation, @pre_incr_expr {
override string getAPrimaryQlClass() { result = "PreIncrExpr" }
}
/**
* A prefix decrement operation, for example `--x`.
* A prefix decrement expression, for example `--x`.
*/
class PreDecrExpr extends DecrementOperation, @pre_decr_expr {
override string getAPrimaryQlClass() { result = "PreDecrExpr" }
}
/**
* A postfix increment operation, for example `x++`.
* A postfix increment expression, for example `x++`.
*/
class PostIncrExpr extends IncrementOperation, @post_incr_expr {
override string toString() { result = "..." + this.getOperator() }
@@ -86,7 +94,7 @@ class PostIncrExpr extends IncrementOperation, @post_incr_expr {
}
/**
* A postfix decrement operation, for example `x--`.
* A postfix decrement expression, for example `x--`.
*/
class PostDecrExpr extends DecrementOperation, @post_decr_expr {
override string toString() { result = "..." + this.getOperator() }
@@ -95,55 +103,84 @@ class PostDecrExpr extends DecrementOperation, @post_decr_expr {
}
/**
* A binary arithmetic operation. Either an addition operation
* (`AddExpr`), a subtraction operation (`SubExpr`), a multiplication
* operation (`MulExpr`), a division operation (`DivExpr`), or a
* remainder operation (`RemExpr`).
* An addition operation, either `x + y` or `x += y`.
*/
class BinaryArithmeticOperation extends ArithmeticOperation, BinaryOperation, @bin_arith_op_expr {
override string getOperator() { none() }
class AddOperation extends BinaryArithmeticOperation, @add_operation { }
/**
* A subtraction operation, either `x - y` or `x -= y`.
*/
class SubOperation extends BinaryArithmeticOperation, @sub_operation { }
/**
* A multiplication operation, either `x * y` or `x *= y`.
*/
class MulOperation extends BinaryArithmeticOperation, @mul_operation { }
/**
* A division operation, either `x / y` or `x /= y`.
*/
class DivOperation extends BinaryArithmeticOperation, @div_operation {
/** Gets the numerator of this division operation. */
Expr getNumerator() { result = this.getLeftOperand() }
/** Gets the denominator of this division operation. */
Expr getDenominator() { result = this.getRightOperand() }
}
/**
* An addition operation, for example `x + y`.
* A remainder operation, either `x % y` or `x %= y`.
*/
class AddExpr extends BinaryArithmeticOperation, AddOperation, @add_expr {
class RemOperation extends BinaryArithmeticOperation, @rem_operation { }
/**
* A binary arithmetic expression. Either an addition expression
* (`AddExpr`), a subtraction expression (`SubExpr`), a multiplication
* expression (`MulExpr`), a division expression (`DivExpr`), or a
* remainder expression (`RemExpr`).
*/
class BinaryArithmeticExpr extends BinaryArithmeticOperation, @bin_arith_expr { }
/**
* An addition expression, for example `x + y`.
*/
class AddExpr extends BinaryArithmeticExpr, AddOperation, @add_expr {
override string getOperator() { result = "+" }
override string getAPrimaryQlClass() { result = "AddExpr" }
}
/**
* A subtraction operation, for example `x - y`.
* A subtraction expression, for example `x - y`.
*/
class SubExpr extends BinaryArithmeticOperation, SubOperation, @sub_expr {
class SubExpr extends BinaryArithmeticExpr, SubOperation, @sub_expr {
override string getOperator() { result = "-" }
override string getAPrimaryQlClass() { result = "SubExpr" }
}
/**
* A multiplication operation, for example `x * y`.
* A multiplication expression, for example `x * y`.
*/
class MulExpr extends BinaryArithmeticOperation, MulOperation, @mul_expr {
class MulExpr extends BinaryArithmeticExpr, MulOperation, @mul_expr {
override string getOperator() { result = "*" }
override string getAPrimaryQlClass() { result = "MulExpr" }
}
/**
* A division operation, for example `x / y`.
* A division expression, for example `x / y`.
*/
class DivExpr extends BinaryArithmeticOperation, DivOperation, @div_expr {
class DivExpr extends BinaryArithmeticExpr, DivOperation, @div_expr {
override string getOperator() { result = "/" }
override string getAPrimaryQlClass() { result = "DivExpr" }
}
/**
* A remainder operation, for example `x % y`.
* A remainder expression, for example `x % y`.
*/
class RemExpr extends BinaryArithmeticOperation, RemOperation, @rem_expr {
class RemExpr extends BinaryArithmeticExpr, RemOperation, @rem_expr {
override string getOperator() { result = "%" }
override string getAPrimaryQlClass() { result = "RemExpr" }

View File

@@ -72,9 +72,9 @@ class AssignExpr extends Assignment, @simple_assign_expr {
}
/**
* An assignment operation. Either an arithmetic assignment operation
* (`AssignArithmeticOperation`), a bitwise assignment operation
* (`AssignBitwiseOperation`), an event assignment (`AddOrRemoveEventExpr`), or
* An assignment operation. Either an arithmetic assignment expression
* (`AssignArithmeticExpr`), a bitwise assignment expression
* (`AssignBitwiseExpr`), an event assignment (`AddOrRemoveEventExpr`), or
* a null-coalescing assignment (`AssignCoalesceExpr`).
*/
class AssignOperation extends Assignment, @assign_op_expr {
@@ -94,134 +94,147 @@ class AssignOperation extends Assignment, @assign_op_expr {
}
/**
* A compound assignment operation that invokes an operator.
* A compound assignment expression that invokes an operator.
*
* (1) `x += y` invokes the compound assignment operator `+=` (if it exists).
* (2) `x += y` invokes the operator `+` and assigns `x + y` to `x`.
*
* Either an arithmetic assignment operation (`AssignArithmeticOperation`) or a bitwise
* assignment operation (`AssignBitwiseOperation`).
* Either an arithmetic assignment expression (`AssignArithmeticExpr`) or a bitwise
* assignment expression (`AssignBitwiseExpr`).
*/
class AssignCallOperation extends AssignOperation, OperatorCall, QualifiableExpr,
@assign_op_call_expr
{
class AssignCallExpr extends AssignOperation, OperatorCall, QualifiableExpr, @assign_op_call_expr {
override string toString() { result = AssignOperation.super.toString() }
}
/**
* An arithmetic assignment operation. Either an addition assignment operation
* (`AssignAddExpr`), a subtraction assignment operation (`AssignSubExpr`), a
* multiplication assignment operation (`AssignMulExpr`), a division assignment
* operation (`AssignDivExpr`), or a remainder assignment operation
* (`AssignRemExpr`).
* DEPRECATED: Use `AssignCallExpr` instead.
*/
class AssignArithmeticOperation extends AssignCallOperation, @assign_arith_expr { }
deprecated class AssignCallOperation = AssignCallExpr;
/**
* An addition assignment operation, for example `x += y`.
* An arithmetic assignment expression. Either an addition assignment expression
* (`AssignAddExpr`), a subtraction assignment expression (`AssignSubExpr`), a
* multiplication assignment expression (`AssignMulExpr`), a division assignment
* expression (`AssignDivExpr`), or a remainder assignment expression
* (`AssignRemExpr`).
*/
class AssignAddExpr extends AssignArithmeticOperation, AddOperation, @assign_add_expr {
class AssignArithmeticExpr extends AssignCallExpr, @assign_arith_expr { }
/**
* DEPRECATED: Use `AssignArithmeticExpr` instead.
*/
deprecated class AssignArithmeticOperation = AssignArithmeticExpr;
/**
* An addition assignment expression, for example `x += y`.
*/
class AssignAddExpr extends AssignArithmeticExpr, AddOperation, @assign_add_expr {
override string getOperator() { result = "+=" }
override string getAPrimaryQlClass() { result = "AssignAddExpr" }
}
/**
* A subtraction assignment operation, for example `x -= y`.
* A subtraction assignment expression, for example `x -= y`.
*/
class AssignSubExpr extends AssignArithmeticOperation, SubOperation, @assign_sub_expr {
class AssignSubExpr extends AssignArithmeticExpr, SubOperation, @assign_sub_expr {
override string getOperator() { result = "-=" }
override string getAPrimaryQlClass() { result = "AssignSubExpr" }
}
/**
* An multiplication assignment operation, for example `x *= y`.
* A multiplication assignment expression, for example `x *= y`.
*/
class AssignMulExpr extends AssignArithmeticOperation, MulOperation, @assign_mul_expr {
class AssignMulExpr extends AssignArithmeticExpr, MulOperation, @assign_mul_expr {
override string getOperator() { result = "*=" }
override string getAPrimaryQlClass() { result = "AssignMulExpr" }
}
/**
* An division assignment operation, for example `x /= y`.
* A division assignment expression, for example `x /= y`.
*/
class AssignDivExpr extends AssignArithmeticOperation, DivOperation, @assign_div_expr {
class AssignDivExpr extends AssignArithmeticExpr, DivOperation, @assign_div_expr {
override string getOperator() { result = "/=" }
override string getAPrimaryQlClass() { result = "AssignDivExpr" }
}
/**
* A remainder assignment operation, for example `x %= y`.
* A remainder assignment expression, for example `x %= y`.
*/
class AssignRemExpr extends AssignArithmeticOperation, RemOperation, @assign_rem_expr {
class AssignRemExpr extends AssignArithmeticExpr, RemOperation, @assign_rem_expr {
override string getOperator() { result = "%=" }
override string getAPrimaryQlClass() { result = "AssignRemExpr" }
}
/**
* A bitwise assignment operation. Either a bitwise-and assignment
* operation (`AssignAndExpr`), a bitwise-or assignment
* operation (`AssignOrExpr`), a bitwise exclusive-or assignment
* operation (`AssignXorExpr`), a left-shift assignment
* operation (`AssignLeftShiftExpr`), or a right-shift assignment
* operation (`AssignRightShiftExpr`), or an unsigned right-shift assignment
* operation (`AssignUnsignedRightShiftExpr`).
* A bitwise assignment expression. Either a bitwise-and assignment
* expression (`AssignAndExpr`), a bitwise-or assignment
* expression (`AssignOrExpr`), a bitwise exclusive-or assignment
* expression (`AssignXorExpr`), a left-shift assignment
* expression (`AssignLeftShiftExpr`), or a right-shift assignment
* expression (`AssignRightShiftExpr`), or an unsigned right-shift assignment
* expression (`AssignUnsignedRightShiftExpr`).
*/
class AssignBitwiseOperation extends AssignCallOperation, @assign_bitwise_expr { }
class AssignBitwiseExpr extends AssignCallExpr, @assign_bitwise_expr { }
/**
* A bitwise-and assignment operation, for example `x &= y`.
* DEPRECATED: Use `AssignBitwiseExpr` instead.
*/
class AssignAndExpr extends AssignBitwiseOperation, BitwiseAndOperation, @assign_and_expr {
deprecated class AssignBitwiseOperation = AssignBitwiseExpr;
/**
* A bitwise-and assignment expression, for example `x &= y`.
*/
class AssignAndExpr extends AssignBitwiseExpr, BitwiseAndOperation, @assign_and_expr {
override string getOperator() { result = "&=" }
override string getAPrimaryQlClass() { result = "AssignAndExpr" }
}
/**
* A bitwise-or assignment operation, for example `x |= y`.
* A bitwise-or assignment expression, for example `x |= y`.
*/
class AssignOrExpr extends AssignBitwiseOperation, BitwiseOrOperation, @assign_or_expr {
class AssignOrExpr extends AssignBitwiseExpr, BitwiseOrOperation, @assign_or_expr {
override string getOperator() { result = "|=" }
override string getAPrimaryQlClass() { result = "AssignOrExpr" }
}
/**
* A bitwise exclusive-or assignment operation, for example `x ^= y`.
* A bitwise exclusive-or assignment expression, for example `x ^= y`.
*/
class AssignXorExpr extends AssignBitwiseOperation, BitwiseXorOperation, @assign_xor_expr {
class AssignXorExpr extends AssignBitwiseExpr, BitwiseXorOperation, @assign_xor_expr {
override string getOperator() { result = "^=" }
override string getAPrimaryQlClass() { result = "AssignXorExpr" }
}
/**
* A left-shift assignment operation, for example `x <<= y`.
* A left-shift assignment expression, for example `x <<= y`.
*/
class AssignLeftShiftExpr extends AssignBitwiseOperation, LeftShiftOperation, @assign_lshift_expr {
class AssignLeftShiftExpr extends AssignBitwiseExpr, LeftShiftOperation, @assign_lshift_expr {
override string getOperator() { result = "<<=" }
override string getAPrimaryQlClass() { result = "AssignLeftShiftExpr" }
}
/**
* A right-shift assignment operation, for example `x >>= y`.
* A right-shift assignment expression, for example `x >>= y`.
*/
class AssignRightShiftExpr extends AssignBitwiseOperation, RightShiftOperation, @assign_rshift_expr {
class AssignRightShiftExpr extends AssignBitwiseExpr, RightShiftOperation, @assign_rshift_expr {
override string getOperator() { result = ">>=" }
override string getAPrimaryQlClass() { result = "AssignRightShiftExpr" }
}
/**
* An unsigned right-shift assignment operation, for example `x >>>= y`.
* An unsigned right-shift assignment expression, for example `x >>>= y`.
*/
class AssignUnsignedRightShiftExpr extends AssignBitwiseOperation, UnsignedRightShiftOperation,
class AssignUnsignedRightShiftExpr extends AssignBitwiseExpr, UnsignedRightShiftOperation,
@assign_urshift_expr
{
override string getOperator() { result = ">>>=" }
@@ -297,10 +310,10 @@ class RemoveEventExpr extends AddOrRemoveEventExpr, @remove_event_expr {
}
/**
* A null-coalescing assignment operation, for example `x ??= y`.
* A null-coalescing assignment expression, for example `x ??= y`.
*/
class AssignCoalesceExpr extends AssignOperation, NullCoalescingOperation, @assign_coalesce_expr {
override string toString() { result = "... ??= ..." }
override string getOperator() { result = "??=" }
override string getAPrimaryQlClass() { result = "AssignCoalesceExpr" }
}

View File

@@ -10,16 +10,16 @@ import Expr
* A bitwise operation. Either a unary bitwise operation (`UnaryBitwiseOperation`)
* or a binary bitwise operation (`BinaryBitwiseOperation`).
*/
class BitwiseOperation extends Operation, @bit_expr { }
class BitwiseOperation extends Operation, @bit_operation { }
/**
* A unary bitwise operation, that is, a bitwise complement operation
* (`ComplementExpr`).
*/
class UnaryBitwiseOperation extends BitwiseOperation, UnaryOperation, @un_bit_op_expr { }
class UnaryBitwiseOperation extends BitwiseOperation, UnaryOperation, @un_bit_operation { }
/**
* A bitwise complement operation, for example `~x`.
* A bitwise complement expression, for example `~x`.
*/
class ComplementExpr extends UnaryBitwiseOperation, @bit_not_expr {
override string getOperator() { result = "~" }
@@ -28,67 +28,101 @@ class ComplementExpr extends UnaryBitwiseOperation, @bit_not_expr {
}
/**
* A binary bitwise operation. Either a bitwise-and operation
* (`BitwiseAndExpr`), a bitwise-or operation (`BitwiseOrExpr`),
* a bitwise exclusive-or operation (`BitwiseXorExpr`), a left-shift
* operation (`LeftShiftExpr`), a right-shift operation (`RightShiftExpr`),
* or an unsigned right-shift operation (`UnsignedRightShiftExpr`).
* A binary bitwise operation. Either a binary bitwise expression (`BinaryBitwiseExpr`) or
* a bitwise assignment expression (`AssignBitwiseExpr`).
*/
class BinaryBitwiseOperation extends BitwiseOperation, BinaryOperation, @bin_bit_op_expr {
class BinaryBitwiseOperation extends BitwiseOperation, BinaryOperation, @bin_bit_operation {
override string getOperator() { none() }
}
/**
* A left-shift operation, for example `x << y`.
* A bitwise-and operation, either `x & y` or `x &= y`.
*/
class LeftShiftExpr extends BinaryBitwiseOperation, LeftShiftOperation, @lshift_expr {
class BitwiseAndOperation extends BinaryBitwiseOperation, @and_operation { }
/**
* A bitwise-or operation, either `x | y` or `x |= y`.
*/
class BitwiseOrOperation extends BinaryBitwiseOperation, @or_operation { }
/**
* A bitwise exclusive-or operation, either `x ^ y` or `x ^= y`.
*/
class BitwiseXorOperation extends BinaryBitwiseOperation, @xor_operation { }
/**
* A left-shift operation, either `x << y` or `x <<= y`.
*/
class LeftShiftOperation extends BinaryBitwiseOperation, @lshift_operation { }
/**
* A right-shift operation, either `x >> y` or `x >>= y`.
*/
class RightShiftOperation extends BinaryBitwiseOperation, @rshift_operation { }
/**
* An unsigned right-shift operation, either `x >>> y` or `x >>>= y`.
*/
class UnsignedRightShiftOperation extends BinaryBitwiseOperation, @urshift_operation { }
/**
* A binary bitwise expression. Either a bitwise-and expression
* (`BitwiseAndExpr`), a bitwise-or expression (`BitwiseOrExpr`),
* a bitwise exclusive-or expression (`BitwiseXorExpr`), a left-shift
* expression (`LeftShiftExpr`), a right-shift expression (`RightShiftExpr`),
* or an unsigned right-shift expression (`UnsignedRightShiftExpr`).
*/
class BinaryBitwiseExpr extends BinaryBitwiseOperation, @bin_bit_expr { }
/**
* A left-shift expression, for example `x << y`.
*/
class LeftShiftExpr extends BinaryBitwiseExpr, LeftShiftOperation, @lshift_expr {
override string getOperator() { result = "<<" }
override string getAPrimaryQlClass() { result = "LeftShiftExpr" }
}
/**
* A right-shift operation, for example `x >> y`.
* A right-shift expression, for example `x >> y`.
*/
class RightShiftExpr extends BinaryBitwiseOperation, RightShiftOperation, @rshift_expr {
class RightShiftExpr extends BinaryBitwiseExpr, RightShiftOperation, @rshift_expr {
override string getOperator() { result = ">>" }
override string getAPrimaryQlClass() { result = "RightShiftExpr" }
}
/**
* An unsigned right-shift operation, for example `x >>> y`.
* An unsigned right-shift expression, for example `x >>> y`.
*/
class UnsignedRightShiftExpr extends BinaryBitwiseOperation, UnsignedRightShiftOperation,
@urshift_expr
{
class UnsignedRightShiftExpr extends BinaryBitwiseExpr, UnsignedRightShiftOperation, @urshift_expr {
override string getOperator() { result = ">>>" }
override string getAPrimaryQlClass() { result = "UnsignedRightShiftExpr" }
}
/**
* A bitwise-and operation, for example `x & y`.
* A bitwise-and expression, for example `x & y`.
*/
class BitwiseAndExpr extends BinaryBitwiseOperation, BitwiseAndOperation, @bit_and_expr {
class BitwiseAndExpr extends BinaryBitwiseExpr, BitwiseAndOperation, @bit_and_expr {
override string getOperator() { result = "&" }
override string getAPrimaryQlClass() { result = "BitwiseAndExpr" }
}
/**
* A bitwise-or operation, for example `x | y`.
* A bitwise-or expression, for example `x | y`.
*/
class BitwiseOrExpr extends BinaryBitwiseOperation, BitwiseOrOperation, @bit_or_expr {
class BitwiseOrExpr extends BinaryBitwiseExpr, BitwiseOrOperation, @bit_or_expr {
override string getOperator() { result = "|" }
override string getAPrimaryQlClass() { result = "BitwiseOrExpr" }
}
/**
* A bitwise exclusive-or operation, for example `x ^ y`.
* A bitwise exclusive-or expression, for example `x ^ y`.
*/
class BitwiseXorExpr extends BinaryBitwiseOperation, BitwiseXorOperation, @bit_xor_expr {
class BitwiseXorExpr extends BinaryBitwiseExpr, BitwiseXorOperation, @bit_xor_expr {
override string getOperator() { result = "^" }
override string getAPrimaryQlClass() { result = "BitwiseXorExpr" }

View File

@@ -609,7 +609,7 @@ class InstanceMutatorOperatorCall extends MutatorOperatorCall {
* }
* ```
*/
class CompoundAssignmentOperatorCall extends AssignCallOperation {
class CompoundAssignmentOperatorCall extends AssignCallExpr {
CompoundAssignmentOperatorCall() { this.getTarget() instanceof CompoundAssignmentOperator }
override Expr getArgument(int i) { result = this.getChildExpr(i + 1) and i >= 0 }

View File

@@ -14,7 +14,6 @@ import Creation
import Dynamic
import Literal
import LogicalOperation
import Operation
import semmle.code.csharp.controlflow.ControlFlowElement
import semmle.code.csharp.Location
import semmle.code.csharp.Stmt
@@ -212,7 +211,7 @@ class LocalConstantDeclExpr extends LocalVariableDeclExpr {
* (`UnaryOperation`), a binary operation (`BinaryOperation`), or a
* ternary operation (`TernaryOperation`).
*/
class Operation extends Expr, @op_expr {
class Operation extends Expr, @operation_expr {
/** Gets the name of the operator in this operation. */
string getOperator() { none() }
@@ -227,7 +226,7 @@ class Operation extends Expr, @op_expr {
* indirection operation (`PointerIndirectionExpr`), an address-of operation
* (`AddressOfExpr`), or a unary logical operation (`UnaryLogicalOperation`).
*/
class UnaryOperation extends Operation, @un_op {
class UnaryOperation extends Operation, @un_operation {
/** Gets the operand of this unary operation. */
Expr getOperand() { result = this.getChild(0) }
@@ -241,7 +240,7 @@ class UnaryOperation extends Operation, @un_op {
* a binary logical operation (`BinaryLogicalOperation`), or an
* assignment (`Assignment`).
*/
class BinaryOperation extends Operation, @bin_op {
class BinaryOperation extends Operation, @bin_operation {
/** Gets the left operand of this binary operation. */
Expr getLeftOperand() { result = this.getChild(0) }
@@ -264,7 +263,7 @@ class BinaryOperation extends Operation, @bin_op {
* A ternary operation, that is, a ternary conditional operation
* (`ConditionalExpr`).
*/
class TernaryOperation extends Operation, @ternary_op { }
class TernaryOperation extends Operation, @ternary_operation { }
/**
* A parenthesized expression, for example `(2 + 3)` in

View File

@@ -11,14 +11,14 @@ import Expr
* a binary logical operation (`BinaryLogicalOperation`), or a ternary logical
* operation (`TernaryLogicalOperation`).
*/
class LogicalOperation extends Operation, @log_expr {
class LogicalOperation extends Operation, @log_operation {
override string getOperator() { none() }
}
/**
* A unary logical operation, that is, a logical 'not' (`LogicalNotExpr`).
*/
class UnaryLogicalOperation extends LogicalOperation, UnaryOperation, @un_log_op_expr { }
class UnaryLogicalOperation extends LogicalOperation, UnaryOperation, @un_log_operation { }
/**
* A logical 'not', for example `!String.IsNullOrEmpty(s)`.
@@ -31,10 +31,10 @@ class LogicalNotExpr extends UnaryLogicalOperation, @log_not_expr {
/**
* A binary logical operation. Either a logical 'and' (`LogicalAndExpr`),
* a logical 'or' (`LogicalAndExpr`), or a null-coalescing operation
* (`NullCoalescingExpr`).
* a logical 'or' (`LogicalOrExpr`), or a null-coalescing operation
* (`NullCoalescingOperation`).
*/
class BinaryLogicalOperation extends LogicalOperation, BinaryOperation, @bin_log_op_expr {
class BinaryLogicalOperation extends LogicalOperation, BinaryOperation, @bin_log_operation {
override string getOperator() { none() }
}
@@ -57,7 +57,12 @@ class LogicalOrExpr extends BinaryLogicalOperation, @log_or_expr {
}
/**
* A null-coalescing operation, for example `s ?? ""` on line 2 in
* A null-coalescing operation, either `x ?? y` or `x ??= y`.
*/
class NullCoalescingOperation extends BinaryLogicalOperation, @null_coalescing_operation { }
/**
* A null-coalescing expression, for example `s ?? ""` on line 2 in
*
* ```csharp
* string NonNullOrEmpty(string s) {
@@ -65,9 +70,7 @@ class LogicalOrExpr extends BinaryLogicalOperation, @log_or_expr {
* }
* ```
*/
class NullCoalescingExpr extends BinaryLogicalOperation, NullCoalescingOperation,
@null_coalescing_expr
{
class NullCoalescingExpr extends NullCoalescingOperation, @null_coalescing_expr {
override string getOperator() { result = "??" }
override string getAPrimaryQlClass() { result = "NullCoalescingExpr" }
@@ -77,7 +80,7 @@ class NullCoalescingExpr extends BinaryLogicalOperation, NullCoalescingOperation
* A ternary logical operation, that is, a ternary conditional expression
* (`ConditionalExpr`).
*/
class TernaryLogicalOperation extends LogicalOperation, TernaryOperation, @ternary_log_op_expr { }
class TernaryLogicalOperation extends LogicalOperation, TernaryOperation, @ternary_log_operation { }
/**
* A conditional expression, for example `s != null ? s.Length : -1`

View File

@@ -1,71 +1,6 @@
/**
* Provides classes for operations that also have compound assignment forms.
*/
deprecated module;
import Expr
/**
* An addition operation, either `x + y` or `x += y`.
*/
class AddOperation extends BinaryOperation, @add_operation { }
/**
* A subtraction operation, either `x - y` or `x -= y`.
*/
class SubOperation extends BinaryOperation, @sub_operation { }
/**
* A multiplication operation, either `x * y` or `x *= y`.
*/
class MulOperation extends BinaryOperation, @mul_operation { }
/**
* A division operation, either `x / y` or `x /= y`.
*/
class DivOperation extends BinaryOperation, @div_operation {
/** Gets the numerator of this division operation. */
Expr getNumerator() { result = this.getLeftOperand() }
/** Gets the denominator of this division operation. */
Expr getDenominator() { result = this.getRightOperand() }
}
/**
* A remainder operation, either `x % y` or `x %= y`.
*/
class RemOperation extends BinaryOperation, @rem_operation { }
/**
* A bitwise-and operation, either `x & y` or `x &= y`.
*/
class BitwiseAndOperation extends BinaryOperation, @and_operation { }
/**
* A bitwise-or operation, either `x | y` or `x |= y`.
*/
class BitwiseOrOperation extends BinaryOperation, @or_operation { }
/**
* A bitwise exclusive-or operation, either `x ^ y` or `x ^= y`.
*/
class BitwiseXorOperation extends BinaryOperation, @xor_operation { }
/**
* A left-shift operation, either `x << y` or `x <<= y`.
*/
class LeftShiftOperation extends BinaryOperation, @lshift_operation { }
/**
* A right-shift operation, either `x >> y` or `x >>= y`.
*/
class RightShiftOperation extends BinaryOperation, @rshift_operation { }
/**
* An unsigned right-shift operation, either `x >>> y` or `x >>>= y`.
*/
class UnsignedRightShiftOperation extends BinaryOperation, @urshift_operation { }
/**
* A null-coalescing operation, either `x ?? y` or `x ??= y`.
*/
class NullCoalescingOperation extends BinaryOperation, @null_coalescing_operation { }

View File

@@ -1254,33 +1254,39 @@ case @expr.kind of
@delegate_creation_expr = @explicit_delegate_creation_expr | @implicit_delegate_creation_expr;
@bin_arith_op_expr = @mul_expr | @div_expr | @rem_expr | @add_expr | @sub_expr;
@incr_op_expr = @pre_incr_expr | @post_incr_expr;
@decr_op_expr = @pre_decr_expr | @post_decr_expr;
@mut_op_expr = @incr_op_expr | @decr_op_expr;
@un_arith_op_expr = @plus_expr | @minus_expr | @mut_op_expr;
@arith_op_expr = @bin_arith_op_expr | @un_arith_op_expr;
@bin_arith_expr = @mul_expr | @div_expr | @rem_expr | @add_expr | @sub_expr;
@bin_arith_operation = @mul_operation | @div_operation | @rem_operation | @add_operation | @sub_operation;
@ternary_log_op_expr = @conditional_expr;
@bin_log_op_expr = @log_and_expr | @log_or_expr | @null_coalescing_expr;
@un_log_op_expr = @log_not_expr;
@log_expr = @un_log_op_expr | @bin_log_op_expr | @ternary_log_op_expr;
@incr_operation = @pre_incr_expr | @post_incr_expr;
@decr_operation = @pre_decr_expr | @post_decr_expr;
@mut_operation = @incr_operation | @decr_operation;
@un_arith_operation = @plus_expr | @minus_expr | @mut_operation;
@arith_operation = @bin_arith_operation | @un_arith_operation;
@bin_bit_op_expr = @bit_and_expr | @bit_or_expr | @bit_xor_expr | @lshift_expr
| @rshift_expr | @urshift_expr;
@un_bit_op_expr = @bit_not_expr;
@bit_expr = @un_bit_op_expr | @bin_bit_op_expr;
@ternary_log_operation = @conditional_expr;
@bin_log_operation = @log_and_expr | @log_or_expr | @null_coalescing_operation;
@un_log_operation = @log_not_expr;
@log_operation = @un_log_operation | @bin_log_operation | @ternary_log_operation;
@bin_bit_expr = @bit_and_expr | @bit_or_expr | @bit_xor_expr | @lshift_expr
| @rshift_expr | @urshift_expr;
@bin_bit_operation = @and_operation | @or_operation | @xor_operation | @lshift_operation
| @rshift_operation | @urshift_operation;
@un_bit_expr = @bit_not_expr;
@un_bit_operation = @un_bit_expr;
@bit_expr = @un_bit_expr | @bin_bit_expr;
@bit_operation = @un_bit_operation | @bin_bit_operation;
@equality_op_expr = @eq_expr | @ne_expr;
@rel_op_expr = @gt_expr | @lt_expr| @ge_expr | @le_expr;
@comp_expr = @equality_op_expr | @rel_op_expr;
@op_expr = @un_op | @bin_op | @ternary_op;
@operation_expr = @un_operation | @bin_operation | @ternary_operation;
@ternary_op = @ternary_log_op_expr;
@bin_op = @assign_expr | @bin_arith_op_expr | @bin_log_op_expr | @bin_bit_op_expr | @comp_expr;
@un_op = @un_arith_op_expr | @un_log_op_expr | @un_bit_op_expr | @sizeof_expr
| @pointer_indirection_expr | @address_of_expr;
@ternary_operation = @ternary_log_operation;
@bin_operation = @assign_expr | @bin_arith_operation | @bin_log_operation | @bin_bit_operation | @comp_expr;
@un_operation = @un_arith_operation | @un_log_operation | @un_bit_operation | @sizeof_expr
| @pointer_indirection_expr | @address_of_expr;
@anonymous_function_expr = @lambda_expr | @anonymous_method_expr;

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,2 @@
description: Restructure and rename types related to operations.
compatibility: full

View File

@@ -1,6 +1,7 @@
binarybitwise
| Operators.cs:7:18:7:25 | ... >>> ... | Operators.cs:7:18:7:19 | access to local variable x1 | Operators.cs:7:25:7:25 | 2 | >>> | UnsignedRightShiftExpr |
| Operators.cs:10:18:10:25 | ... >>> ... | Operators.cs:10:18:10:19 | access to local variable y1 | Operators.cs:10:25:10:25 | 3 | >>> | UnsignedRightShiftExpr |
| Operators.cs:13:9:13:16 | ... >>>= ... | Operators.cs:13:9:13:9 | access to local variable z | Operators.cs:13:16:13:16 | 5 | >>>= | AssignUnsignedRightShiftExpr |
assignbitwise
| Operators.cs:13:9:13:16 | ... >>>= ... | Operators.cs:13:9:13:9 | access to local variable z | Operators.cs:13:16:13:16 | 5 | >>>= | AssignUnsignedRightShiftExpr |
userdefined

View File

@@ -11,7 +11,7 @@ query predicate binarybitwise(
}
query predicate assignbitwise(
AssignBitwiseOperation op, Expr left, Expr right, string name, string qlclass
AssignBitwiseExpr op, Expr left, Expr right, string name, string qlclass
) {
op.getFile().getStem() = "Operators" and
left = op.getLeftOperand() and

View File

@@ -442,4 +442,31 @@ namespace My.Qltest
static void Sink(object o) { }
}
// Test operator overloads
public class N
{
public void operator +=(N y) => throw null;
public void operator checked +=(N y) => throw null;
public void M1(N n)
{
var n0 = new N();
n += n0;
Sink(n);
}
public void M2(N n)
{
var n0 = new N();
checked
{
n += n0;
}
Sink(n);
}
static void Sink(object o) { }
}
}

View File

@@ -32,14 +32,16 @@ models
| 31 | Summary: My.Qltest; Library; false; GetValue; (); ; Argument[this].SyntheticField[X]; ReturnValue; value; dfc-generated |
| 32 | Summary: My.Qltest; Library; false; MixedFlowArgs; (System.Object,System.Object); ; Argument[1]; ReturnValue; value; manual |
| 33 | Summary: My.Qltest; Library; false; SetValue; (System.Object); ; Argument[0]; Argument[this].SyntheticField[X]; value; dfc-generated |
| 34 | Summary: My.Qltest; TestExtensions+extension(System.Object); false; Method1; (System.Object); ; Argument[0]; ReturnValue; value; manual |
| 35 | Summary: My.Qltest; TestExtensions+extension(System.Object); false; StaticMethod1; (System.Object); ; Argument[0]; ReturnValue; value; manual |
| 36 | Summary: My.Qltest; TestExtensions+extension(System.Object); false; get_Property1; (System.Object); ; Argument[0].SyntheticField[TestExtensions.Property1]; ReturnValue; value; manual |
| 37 | Summary: My.Qltest; TestExtensions+extension(System.Object); false; set_Property1; (System.Object,System.Object); ; Argument[1]; Argument[0].SyntheticField[TestExtensions.Property1]; value; manual |
| 38 | Summary: My.Qltest; TestExtensions+extension(T)<T>; false; GenericMethod1; (T); ; Argument[0]; ReturnValue; value; manual |
| 39 | Summary: My.Qltest; TestExtensions+extension(T)<T>; false; GenericStaticMethod1; (T); ; Argument[0]; ReturnValue; value; manual |
| 40 | Summary: My.Qltest; TestExtensions+extension(T)<T>; false; get_GenericProperty1; (T); ; Argument[0].SyntheticField[TestExtensions.GenericProperty1]; ReturnValue; value; manual |
| 41 | Summary: My.Qltest; TestExtensions+extension(T)<T>; false; set_GenericProperty1; (T,T); ; Argument[1]; Argument[0].SyntheticField[TestExtensions.GenericProperty1]; value; manual |
| 34 | Summary: My.Qltest; N; false; op_AdditionAssignment; (My.Qltest.N); ; Argument[0]; Argument[this]; taint; manual |
| 35 | Summary: My.Qltest; N; false; op_CheckedAdditionAssignment; (My.Qltest.N); ; Argument[0]; Argument[this]; taint; manual |
| 36 | Summary: My.Qltest; TestExtensions+extension(System.Object); false; Method1; (System.Object); ; Argument[0]; ReturnValue; value; manual |
| 37 | Summary: My.Qltest; TestExtensions+extension(System.Object); false; StaticMethod1; (System.Object); ; Argument[0]; ReturnValue; value; manual |
| 38 | Summary: My.Qltest; TestExtensions+extension(System.Object); false; get_Property1; (System.Object); ; Argument[0].SyntheticField[TestExtensions.Property1]; ReturnValue; value; manual |
| 39 | Summary: My.Qltest; TestExtensions+extension(System.Object); false; set_Property1; (System.Object,System.Object); ; Argument[1]; Argument[0].SyntheticField[TestExtensions.Property1]; value; manual |
| 40 | Summary: My.Qltest; TestExtensions+extension(T)<T>; false; GenericMethod1; (T); ; Argument[0]; ReturnValue; value; manual |
| 41 | Summary: My.Qltest; TestExtensions+extension(T)<T>; false; GenericStaticMethod1; (T); ; Argument[0]; ReturnValue; value; manual |
| 42 | Summary: My.Qltest; TestExtensions+extension(T)<T>; false; get_GenericProperty1; (T); ; Argument[0].SyntheticField[TestExtensions.GenericProperty1]; ReturnValue; value; manual |
| 43 | Summary: My.Qltest; TestExtensions+extension(T)<T>; false; set_GenericProperty1; (T,T); ; Argument[1]; Argument[0].SyntheticField[TestExtensions.GenericProperty1]; value; manual |
edges
| ExternalFlow.cs:9:20:9:23 | access to local variable arg1 : Object | ExternalFlow.cs:10:29:10:32 | access to local variable arg1 : Object | provenance | |
| ExternalFlow.cs:9:27:9:38 | object creation of type Object : Object | ExternalFlow.cs:9:20:9:23 | access to local variable arg1 : Object | provenance | |
@@ -162,69 +164,77 @@ edges
| ExternalFlow.cs:373:17:373:19 | access to local variable obj : Object | ExternalFlow.cs:377:45:377:47 | access to local variable obj : Object | provenance | |
| ExternalFlow.cs:373:23:373:34 | object creation of type Object : Object | ExternalFlow.cs:373:17:373:19 | access to local variable obj : Object | provenance | |
| ExternalFlow.cs:374:17:374:18 | access to local variable o1 : Object | ExternalFlow.cs:375:18:375:19 | access to local variable o1 | provenance | |
| ExternalFlow.cs:374:22:374:24 | access to local variable obj : Object | ExternalFlow.cs:374:22:374:34 | call to method Method1 : Object | provenance | MaD:34 |
| ExternalFlow.cs:374:22:374:24 | access to local variable obj : Object | ExternalFlow.cs:374:22:374:34 | call to method Method1 : Object | provenance | MaD:36 |
| ExternalFlow.cs:374:22:374:34 | call to method Method1 : Object | ExternalFlow.cs:374:17:374:18 | access to local variable o1 : Object | provenance | |
| ExternalFlow.cs:377:17:377:18 | access to local variable o2 : Object | ExternalFlow.cs:378:18:378:19 | access to local variable o2 | provenance | |
| ExternalFlow.cs:377:22:377:48 | call to method Method1 : Object | ExternalFlow.cs:377:17:377:18 | access to local variable o2 : Object | provenance | |
| ExternalFlow.cs:377:45:377:47 | access to local variable obj : Object | ExternalFlow.cs:377:22:377:48 | call to method Method1 : Object | provenance | MaD:34 |
| ExternalFlow.cs:377:45:377:47 | access to local variable obj : Object | ExternalFlow.cs:377:22:377:48 | call to method Method1 : Object | provenance | MaD:36 |
| ExternalFlow.cs:383:17:383:19 | access to local variable obj : Object | ExternalFlow.cs:384:43:384:45 | access to local variable obj : Object | provenance | |
| ExternalFlow.cs:383:17:383:19 | access to local variable obj : Object | ExternalFlow.cs:387:51:387:53 | access to local variable obj : Object | provenance | |
| ExternalFlow.cs:383:23:383:34 | object creation of type Object : Object | ExternalFlow.cs:383:17:383:19 | access to local variable obj : Object | provenance | |
| ExternalFlow.cs:384:17:384:18 | access to local variable o1 : Object | ExternalFlow.cs:385:18:385:19 | access to local variable o1 | provenance | |
| ExternalFlow.cs:384:22:384:46 | call to method StaticMethod1 : Object | ExternalFlow.cs:384:17:384:18 | access to local variable o1 : Object | provenance | |
| ExternalFlow.cs:384:43:384:45 | access to local variable obj : Object | ExternalFlow.cs:384:22:384:46 | call to method StaticMethod1 : Object | provenance | MaD:35 |
| ExternalFlow.cs:384:43:384:45 | access to local variable obj : Object | ExternalFlow.cs:384:22:384:46 | call to method StaticMethod1 : Object | provenance | MaD:37 |
| ExternalFlow.cs:387:17:387:18 | access to local variable o2 : Object | ExternalFlow.cs:388:18:388:19 | access to local variable o2 | provenance | |
| ExternalFlow.cs:387:22:387:54 | call to method StaticMethod1 : Object | ExternalFlow.cs:387:17:387:18 | access to local variable o2 : Object | provenance | |
| ExternalFlow.cs:387:51:387:53 | access to local variable obj : Object | ExternalFlow.cs:387:22:387:54 | call to method StaticMethod1 : Object | provenance | MaD:35 |
| ExternalFlow.cs:387:51:387:53 | access to local variable obj : Object | ExternalFlow.cs:387:22:387:54 | call to method StaticMethod1 : Object | provenance | MaD:37 |
| ExternalFlow.cs:393:17:393:19 | access to local variable obj : Object | ExternalFlow.cs:394:27:394:29 | access to local variable obj : Object | provenance | |
| ExternalFlow.cs:393:23:393:34 | object creation of type Object : Object | ExternalFlow.cs:393:17:393:19 | access to local variable obj : Object | provenance | |
| ExternalFlow.cs:394:13:394:13 | [post] access to parameter o : Object [synthetic TestExtensions.Property1] : Object | ExternalFlow.cs:395:22:395:22 | access to parameter o : Object [synthetic TestExtensions.Property1] : Object | provenance | |
| ExternalFlow.cs:394:27:394:29 | access to local variable obj : Object | ExternalFlow.cs:394:13:394:13 | [post] access to parameter o : Object [synthetic TestExtensions.Property1] : Object | provenance | MaD:37 |
| ExternalFlow.cs:394:27:394:29 | access to local variable obj : Object | ExternalFlow.cs:394:13:394:13 | [post] access to parameter o : Object [synthetic TestExtensions.Property1] : Object | provenance | MaD:39 |
| ExternalFlow.cs:395:17:395:18 | access to local variable o1 : Object | ExternalFlow.cs:396:18:396:19 | access to local variable o1 | provenance | |
| ExternalFlow.cs:395:22:395:22 | access to parameter o : Object [synthetic TestExtensions.Property1] : Object | ExternalFlow.cs:395:22:395:32 | access to property Property1 : Object | provenance | MaD:36 |
| ExternalFlow.cs:395:22:395:22 | access to parameter o : Object [synthetic TestExtensions.Property1] : Object | ExternalFlow.cs:395:22:395:32 | access to property Property1 : Object | provenance | MaD:38 |
| ExternalFlow.cs:395:22:395:32 | access to property Property1 : Object | ExternalFlow.cs:395:17:395:18 | access to local variable o1 : Object | provenance | |
| ExternalFlow.cs:401:17:401:19 | access to local variable obj : Object | ExternalFlow.cs:402:45:402:47 | access to local variable obj : Object | provenance | |
| ExternalFlow.cs:401:23:401:34 | object creation of type Object : Object | ExternalFlow.cs:401:17:401:19 | access to local variable obj : Object | provenance | |
| ExternalFlow.cs:402:42:402:42 | [post] access to parameter o : Object [synthetic TestExtensions.Property1] : Object | ExternalFlow.cs:403:51:403:51 | access to parameter o : Object [synthetic TestExtensions.Property1] : Object | provenance | |
| ExternalFlow.cs:402:45:402:47 | access to local variable obj : Object | ExternalFlow.cs:402:42:402:42 | [post] access to parameter o : Object [synthetic TestExtensions.Property1] : Object | provenance | MaD:37 |
| ExternalFlow.cs:402:45:402:47 | access to local variable obj : Object | ExternalFlow.cs:402:42:402:42 | [post] access to parameter o : Object [synthetic TestExtensions.Property1] : Object | provenance | MaD:39 |
| ExternalFlow.cs:403:17:403:18 | access to local variable o1 : Object | ExternalFlow.cs:404:18:404:19 | access to local variable o1 | provenance | |
| ExternalFlow.cs:403:22:403:52 | call to extension accessor get_Property1 : Object | ExternalFlow.cs:403:17:403:18 | access to local variable o1 : Object | provenance | |
| ExternalFlow.cs:403:51:403:51 | access to parameter o : Object [synthetic TestExtensions.Property1] : Object | ExternalFlow.cs:403:22:403:52 | call to extension accessor get_Property1 : Object | provenance | MaD:36 |
| ExternalFlow.cs:403:51:403:51 | access to parameter o : Object [synthetic TestExtensions.Property1] : Object | ExternalFlow.cs:403:22:403:52 | call to extension accessor get_Property1 : Object | provenance | MaD:38 |
| ExternalFlow.cs:409:17:409:19 | access to local variable obj : Object | ExternalFlow.cs:410:22:410:24 | access to local variable obj : Object | provenance | |
| ExternalFlow.cs:409:17:409:19 | access to local variable obj : Object | ExternalFlow.cs:413:52:413:54 | access to local variable obj : Object | provenance | |
| ExternalFlow.cs:409:23:409:34 | object creation of type Object : Object | ExternalFlow.cs:409:17:409:19 | access to local variable obj : Object | provenance | |
| ExternalFlow.cs:410:17:410:18 | access to local variable o1 : Object | ExternalFlow.cs:411:18:411:19 | access to local variable o1 | provenance | |
| ExternalFlow.cs:410:22:410:24 | access to local variable obj : Object | ExternalFlow.cs:410:22:410:41 | call to method GenericMethod1 : Object | provenance | MaD:38 |
| ExternalFlow.cs:410:22:410:24 | access to local variable obj : Object | ExternalFlow.cs:410:22:410:41 | call to method GenericMethod1 : Object | provenance | MaD:40 |
| ExternalFlow.cs:410:22:410:41 | call to method GenericMethod1 : Object | ExternalFlow.cs:410:17:410:18 | access to local variable o1 : Object | provenance | |
| ExternalFlow.cs:413:17:413:18 | access to local variable o2 : Object | ExternalFlow.cs:414:18:414:19 | access to local variable o2 | provenance | |
| ExternalFlow.cs:413:22:413:55 | call to method GenericMethod1 : Object | ExternalFlow.cs:413:17:413:18 | access to local variable o2 : Object | provenance | |
| ExternalFlow.cs:413:52:413:54 | access to local variable obj : Object | ExternalFlow.cs:413:22:413:55 | call to method GenericMethod1 : Object | provenance | MaD:38 |
| ExternalFlow.cs:413:52:413:54 | access to local variable obj : Object | ExternalFlow.cs:413:22:413:55 | call to method GenericMethod1 : Object | provenance | MaD:40 |
| ExternalFlow.cs:419:17:419:19 | access to local variable obj : Object | ExternalFlow.cs:420:50:420:52 | access to local variable obj : Object | provenance | |
| ExternalFlow.cs:419:17:419:19 | access to local variable obj : Object | ExternalFlow.cs:423:58:423:60 | access to local variable obj : Object | provenance | |
| ExternalFlow.cs:419:23:419:34 | object creation of type Object : Object | ExternalFlow.cs:419:17:419:19 | access to local variable obj : Object | provenance | |
| ExternalFlow.cs:420:17:420:18 | access to local variable o1 : Object | ExternalFlow.cs:421:18:421:19 | access to local variable o1 | provenance | |
| ExternalFlow.cs:420:22:420:53 | call to method GenericStaticMethod1 : Object | ExternalFlow.cs:420:17:420:18 | access to local variable o1 : Object | provenance | |
| ExternalFlow.cs:420:50:420:52 | access to local variable obj : Object | ExternalFlow.cs:420:22:420:53 | call to method GenericStaticMethod1 : Object | provenance | MaD:39 |
| ExternalFlow.cs:420:50:420:52 | access to local variable obj : Object | ExternalFlow.cs:420:22:420:53 | call to method GenericStaticMethod1 : Object | provenance | MaD:41 |
| ExternalFlow.cs:423:17:423:18 | access to local variable o2 : Object | ExternalFlow.cs:424:18:424:19 | access to local variable o2 | provenance | |
| ExternalFlow.cs:423:22:423:61 | call to method GenericStaticMethod1 : Object | ExternalFlow.cs:423:17:423:18 | access to local variable o2 : Object | provenance | |
| ExternalFlow.cs:423:58:423:60 | access to local variable obj : Object | ExternalFlow.cs:423:22:423:61 | call to method GenericStaticMethod1 : Object | provenance | MaD:39 |
| ExternalFlow.cs:423:58:423:60 | access to local variable obj : Object | ExternalFlow.cs:423:22:423:61 | call to method GenericStaticMethod1 : Object | provenance | MaD:41 |
| ExternalFlow.cs:429:17:429:19 | access to local variable obj : Object | ExternalFlow.cs:430:34:430:36 | access to local variable obj : Object | provenance | |
| ExternalFlow.cs:429:23:429:34 | object creation of type Object : Object | ExternalFlow.cs:429:17:429:19 | access to local variable obj : Object | provenance | |
| ExternalFlow.cs:430:13:430:13 | [post] access to parameter o : Object [property GenericProperty1] : Object | ExternalFlow.cs:431:22:431:22 | access to parameter o : Object [property GenericProperty1] : Object | provenance | |
| ExternalFlow.cs:430:13:430:13 | [post] access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | ExternalFlow.cs:431:22:431:22 | access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | provenance | |
| ExternalFlow.cs:430:34:430:36 | access to local variable obj : Object | ExternalFlow.cs:430:13:430:13 | [post] access to parameter o : Object [property GenericProperty1] : Object | provenance | |
| ExternalFlow.cs:430:34:430:36 | access to local variable obj : Object | ExternalFlow.cs:430:13:430:13 | [post] access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | provenance | MaD:41 |
| ExternalFlow.cs:430:34:430:36 | access to local variable obj : Object | ExternalFlow.cs:430:13:430:13 | [post] access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | provenance | MaD:43 |
| ExternalFlow.cs:431:17:431:18 | access to local variable o1 : Object | ExternalFlow.cs:432:18:432:19 | access to local variable o1 | provenance | |
| ExternalFlow.cs:431:22:431:22 | access to parameter o : Object [property GenericProperty1] : Object | ExternalFlow.cs:431:22:431:39 | access to property GenericProperty1 : Object | provenance | |
| ExternalFlow.cs:431:22:431:22 | access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | ExternalFlow.cs:431:22:431:39 | access to property GenericProperty1 : Object | provenance | MaD:40 |
| ExternalFlow.cs:431:22:431:22 | access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | ExternalFlow.cs:431:22:431:39 | access to property GenericProperty1 : Object | provenance | MaD:42 |
| ExternalFlow.cs:431:22:431:39 | access to property GenericProperty1 : Object | ExternalFlow.cs:431:17:431:18 | access to local variable o1 : Object | provenance | |
| ExternalFlow.cs:437:17:437:19 | access to local variable obj : Object | ExternalFlow.cs:438:52:438:54 | access to local variable obj : Object | provenance | |
| ExternalFlow.cs:437:23:437:34 | object creation of type Object : Object | ExternalFlow.cs:437:17:437:19 | access to local variable obj : Object | provenance | |
| ExternalFlow.cs:438:49:438:49 | [post] access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | ExternalFlow.cs:439:58:439:58 | access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | provenance | |
| ExternalFlow.cs:438:52:438:54 | access to local variable obj : Object | ExternalFlow.cs:438:49:438:49 | [post] access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | provenance | MaD:41 |
| ExternalFlow.cs:438:52:438:54 | access to local variable obj : Object | ExternalFlow.cs:438:49:438:49 | [post] access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | provenance | MaD:43 |
| ExternalFlow.cs:439:17:439:18 | access to local variable o1 : Object | ExternalFlow.cs:440:18:440:19 | access to local variable o1 | provenance | |
| ExternalFlow.cs:439:22:439:59 | call to extension accessor get_GenericProperty1 : Object | ExternalFlow.cs:439:17:439:18 | access to local variable o1 : Object | provenance | |
| ExternalFlow.cs:439:58:439:58 | access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | ExternalFlow.cs:439:22:439:59 | call to extension accessor get_GenericProperty1 : Object | provenance | MaD:40 |
| ExternalFlow.cs:439:58:439:58 | access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | ExternalFlow.cs:439:22:439:59 | call to extension accessor get_GenericProperty1 : Object | provenance | MaD:42 |
| ExternalFlow.cs:455:17:455:18 | access to local variable n0 : N | ExternalFlow.cs:456:18:456:19 | access to local variable n0 : N | provenance | |
| ExternalFlow.cs:455:22:455:28 | object creation of type N : N | ExternalFlow.cs:455:17:455:18 | access to local variable n0 : N | provenance | |
| ExternalFlow.cs:456:13:456:13 | [post] access to parameter n : N | ExternalFlow.cs:457:18:457:18 | access to parameter n | provenance | |
| ExternalFlow.cs:456:18:456:19 | access to local variable n0 : N | ExternalFlow.cs:456:13:456:13 | [post] access to parameter n : N | provenance | MaD:34 |
| ExternalFlow.cs:462:17:462:18 | access to local variable n0 : N | ExternalFlow.cs:465:22:465:23 | access to local variable n0 : N | provenance | |
| ExternalFlow.cs:462:22:462:28 | object creation of type N : N | ExternalFlow.cs:462:17:462:18 | access to local variable n0 : N | provenance | |
| ExternalFlow.cs:465:17:465:17 | [post] access to parameter n : N | ExternalFlow.cs:467:18:467:18 | access to parameter n | provenance | |
| ExternalFlow.cs:465:22:465:23 | access to local variable n0 : N | ExternalFlow.cs:465:17:465:17 | [post] access to parameter n : N | provenance | MaD:35 |
nodes
| ExternalFlow.cs:9:20:9:23 | access to local variable arg1 : Object | semmle.label | access to local variable arg1 : Object |
| ExternalFlow.cs:9:27:9:38 | object creation of type Object : Object | semmle.label | object creation of type Object : Object |
@@ -443,6 +453,16 @@ nodes
| ExternalFlow.cs:439:22:439:59 | call to extension accessor get_GenericProperty1 : Object | semmle.label | call to extension accessor get_GenericProperty1 : Object |
| ExternalFlow.cs:439:58:439:58 | access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | semmle.label | access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object |
| ExternalFlow.cs:440:18:440:19 | access to local variable o1 | semmle.label | access to local variable o1 |
| ExternalFlow.cs:455:17:455:18 | access to local variable n0 : N | semmle.label | access to local variable n0 : N |
| ExternalFlow.cs:455:22:455:28 | object creation of type N : N | semmle.label | object creation of type N : N |
| ExternalFlow.cs:456:13:456:13 | [post] access to parameter n : N | semmle.label | [post] access to parameter n : N |
| ExternalFlow.cs:456:18:456:19 | access to local variable n0 : N | semmle.label | access to local variable n0 : N |
| ExternalFlow.cs:457:18:457:18 | access to parameter n | semmle.label | access to parameter n |
| ExternalFlow.cs:462:17:462:18 | access to local variable n0 : N | semmle.label | access to local variable n0 : N |
| ExternalFlow.cs:462:22:462:28 | object creation of type N : N | semmle.label | object creation of type N : N |
| ExternalFlow.cs:465:17:465:17 | [post] access to parameter n : N | semmle.label | [post] access to parameter n : N |
| ExternalFlow.cs:465:22:465:23 | access to local variable n0 : N | semmle.label | access to local variable n0 : N |
| ExternalFlow.cs:467:18:467:18 | access to parameter n | semmle.label | access to parameter n |
subpaths
| ExternalFlow.cs:84:29:84:32 | access to local variable objs : null [element] : Object | ExternalFlow.cs:84:35:84:35 | o : Object | ExternalFlow.cs:84:40:84:40 | access to parameter o : Object | ExternalFlow.cs:84:25:84:41 | call to method Map<Object,Object> : T[] [element] : Object |
invalidModelRow
@@ -489,3 +509,5 @@ invalidModelRow
| ExternalFlow.cs:424:18:424:19 | access to local variable o2 | ExternalFlow.cs:419:23:419:34 | object creation of type Object : Object | ExternalFlow.cs:424:18:424:19 | access to local variable o2 | $@ | ExternalFlow.cs:419:23:419:34 | object creation of type Object : Object | object creation of type Object : Object |
| ExternalFlow.cs:432:18:432:19 | access to local variable o1 | ExternalFlow.cs:429:23:429:34 | object creation of type Object : Object | ExternalFlow.cs:432:18:432:19 | access to local variable o1 | $@ | ExternalFlow.cs:429:23:429:34 | object creation of type Object : Object | object creation of type Object : Object |
| ExternalFlow.cs:440:18:440:19 | access to local variable o1 | ExternalFlow.cs:437:23:437:34 | object creation of type Object : Object | ExternalFlow.cs:440:18:440:19 | access to local variable o1 | $@ | ExternalFlow.cs:437:23:437:34 | object creation of type Object : Object | object creation of type Object : Object |
| ExternalFlow.cs:457:18:457:18 | access to parameter n | ExternalFlow.cs:455:22:455:28 | object creation of type N : N | ExternalFlow.cs:457:18:457:18 | access to parameter n | $@ | ExternalFlow.cs:455:22:455:28 | object creation of type N : N | object creation of type N : N |
| ExternalFlow.cs:467:18:467:18 | access to parameter n | ExternalFlow.cs:462:22:462:28 | object creation of type N : N | ExternalFlow.cs:467:18:467:18 | access to parameter n | $@ | ExternalFlow.cs:462:22:462:28 | object creation of type N : N | object creation of type N : N |

View File

@@ -53,6 +53,8 @@ extensions:
- ["My.Qltest", "TestExtensions+extension(T)<T>", false, "GenericStaticMethod1", "(T)", "", "Argument[0]", "ReturnValue", "value", "manual"]
- ["My.Qltest", "TestExtensions+extension(T)<T>", false, "get_GenericProperty1", "(T)", "", "Argument[0].SyntheticField[TestExtensions.GenericProperty1]", "ReturnValue", "value", "manual"]
- ["My.Qltest", "TestExtensions+extension(T)<T>", false, "set_GenericProperty1", "(T,T)", "", "Argument[1]", "Argument[0].SyntheticField[TestExtensions.GenericProperty1]", "value", "manual"]
- ["My.Qltest", "N", false, "op_AdditionAssignment", "(My.Qltest.N)", "", "Argument[0]", "Argument[this]", "taint", "manual"]
- ["My.Qltest", "N", false, "op_CheckedAdditionAssignment", "(My.Qltest.N)", "", "Argument[0]", "Argument[this]", "taint", "manual"]
- addsTo:
pack: codeql/csharp-all

View File

@@ -84,6 +84,10 @@ private module Ast implements AstSig<Location> {
class DoStmt = J::DoStmt;
class UntilStmt extends LoopStmt {
UntilStmt() { none() }
}
final private class FinalForStmt = J::ForStmt;
class ForStmt extends FinalForStmt {

View File

@@ -331,7 +331,7 @@ public class B {
x = new Object();
}
if(y instanceof String) {
x.hashCode(); // $ Alert[java/dereferenced-value-may-be-null] // Spurious NPE - false positive
x.hashCode(); // $ SPURIOUS: Alert[java/dereferenced-value-may-be-null] // Spurious NPE - false positive
}
}
@@ -341,7 +341,7 @@ public class B {
x = new Object();
}
if(!(y instanceof String)) {
x.hashCode(); // $ Alert[java/dereferenced-value-may-be-null] // Spurious NPE - false positive
x.hashCode(); // $ SPURIOUS: Alert[java/dereferenced-value-may-be-null] // Spurious NPE - false positive
}
}
@@ -351,7 +351,7 @@ public class B {
x = new Object();
}
if(y == z) {
x.hashCode(); // $ Alert[java/dereferenced-value-may-be-null] // Spurious NPE - false positive
x.hashCode(); // $ SPURIOUS: Alert[java/dereferenced-value-may-be-null] // Spurious NPE - false positive
}
Object x2 = null;
@@ -359,7 +359,7 @@ public class B {
x2 = new Object();
}
if(y != z) {
x2.hashCode(); // $ Alert[java/dereferenced-value-may-be-null] // Spurious NPE - false positive
x2.hashCode(); // $ SPURIOUS: Alert[java/dereferenced-value-may-be-null] // Spurious NPE - false positive
}
Object x3 = null;
@@ -367,7 +367,7 @@ public class B {
x3 = new Object();
}
if(!(y == z)) {
x3.hashCode(); // $ Alert[java/dereferenced-value-may-be-null] // Spurious NPE - false positive
x3.hashCode(); // $ SPURIOUS: Alert[java/dereferenced-value-may-be-null] // Spurious NPE - false positive
}
}
@@ -462,7 +462,7 @@ public class B {
cur = a[i];
if (!prev) {
// correctly guarded by !cur from the _previous_ iteration
x.hashCode(); // $ Alert[java/dereferenced-value-may-be-null] // Spurious NPE - false positive
x.hashCode(); // $ SPURIOUS: Alert[java/dereferenced-value-may-be-null] // Spurious NPE - false positive
} else {
x = new Object();
}
@@ -484,7 +484,7 @@ public class B {
t = new Object();
}
// correctly guarded by t: null -> String -> Object
x.hashCode(); // $ Alert[java/dereferenced-value-may-be-null] // Spurious NPE - false positive
x.hashCode(); // $ SPURIOUS: Alert[java/dereferenced-value-may-be-null] // Spurious NPE - false positive
}
}
}
@@ -573,7 +573,7 @@ public class B {
} finally {
}
}
s.hashCode(); // $ Alert[java/dereferenced-value-may-be-null] // Spurious NPE - false positive
s.hashCode(); // $ SPURIOUS: Alert[java/dereferenced-value-may-be-null] // Spurious NPE - false positive
// CFG reachability does not distinguish abrupt successors
}
}

View File

@@ -6,8 +6,8 @@ public class C {
long[][] a2 = null;
boolean haveA2 = ix < len && (a2 = a1[ix]) != null;
long[] a3 = null;
final boolean haveA3 = haveA2 && (a3 = a2[ix]) != null; // $ Alert[java/dereferenced-value-may-be-null] // NPE - false positive
if (haveA3) a3[0] = 0; // $ Alert[java/dereferenced-value-may-be-null] // NPE - false positive
final boolean haveA3 = haveA2 && (a3 = a2[ix]) != null; // $ SPURIOUS: Alert[java/dereferenced-value-may-be-null] // NPE - false positive
if (haveA3) a3[0] = 0; // $ SPURIOUS: Alert[java/dereferenced-value-may-be-null] // NPE - false positive
}
public void ex2(boolean x, boolean y) {
@@ -18,7 +18,7 @@ public class C {
s2 = (s1 == null) ? null : "";
}
if (s2 != null)
s1.hashCode(); // $ Alert[java/dereferenced-value-may-be-null] // NPE - false positive
s1.hashCode(); // $ SPURIOUS: Alert[java/dereferenced-value-may-be-null] // NPE - false positive
}
public void ex3(List<String> ss) {
@@ -48,7 +48,7 @@ public class C {
slice = new ArrayList<>();
result.add(slice);
}
slice.add(str); // $ Alert[java/dereferenced-value-may-be-null] // NPE - false positive
slice.add(str); // $ SPURIOUS: Alert[java/dereferenced-value-may-be-null] // NPE - false positive
++index;
iter.remove();
}
@@ -141,7 +141,7 @@ public class C {
public void ex10(int[] a) {
int n = a == null ? 0 : a.length;
for (int i = 0; i < n; i++) {
int x = a[i]; // $ Alert[java/dereferenced-value-may-be-null] // NPE - false positive
int x = a[i]; // $ SPURIOUS: Alert[java/dereferenced-value-may-be-null] // NPE - false positive
if (x > 7)
a = new int[n];
}
@@ -216,7 +216,7 @@ public class C {
if (o1 == o2) {
return;
}
if (o1.equals(o2)) { // $ Alert[java/dereferenced-value-may-be-null] // NPE - false positive
if (o1.equals(o2)) { // $ SPURIOUS: Alert[java/dereferenced-value-may-be-null] // NPE - false positive
return;
}
}
@@ -230,7 +230,7 @@ public class C {
public static void ex16(C c) {
int[] xs = c.getFoo16() != null ? new int[5] : null;
if (c.getFoo16() != null) {
xs[0]++; // $ Alert[java/dereferenced-value-may-be-null] // NPE - false positive
xs[0]++; // $ SPURIOUS: Alert[java/dereferenced-value-may-be-null] // NPE - false positive
}
}

View File

@@ -11,25 +11,25 @@ class UseBraces
{
int x = 0, y;
int[] branches = new int[10];
// If-then statement
if(1==1)
{
f();
}
g(); // No alert
if(1==1)
if(1==1)
f();
g(); // No alert
if(1==1)
f(); // $ Alert
g(); // Alert
g();
if(1==1)
f(); g(); // $ Alert // Alert
f(); g(); // $ Alert
// If-then-else statement
@@ -41,29 +41,29 @@ class UseBraces
{
g();
}
g(); // No alert
if(1==2)
f();
else
g();
f(); // No alert
if(true)
{
f();
}
else
f(); // $ Alert
g(); // Alert
g();
if(true)
{
f();
}
else
f(); g(); // $ Alert // Alert
f(); g(); // $ Alert
// While statement
@@ -80,44 +80,44 @@ class UseBraces
while(bb )
f(); // $ Alert
g(); // Alert
g();
g(); // No alert
while(bb )
f(); g(); // $ Alert // Alert
f(); g(); // $ Alert
while(bb)
if (x != 0) x = 1;
// Do-while statement
do
f();
while(false);
g(); // No alert
// For statement
for(int i=0; i<10; ++i)
{
f();
}
g();
for(int i=0; i<10; ++i)
f();
g();
for(int i=0; i<10; ++i)
f(); // $ Alert
g(); // Alert
g();
for(int i=0; i<10; ++i)
f(); g(); // $ Alert // Alert
f(); g(); // $ Alert
// Foreach statement
for( int b : branches)
x += b;
f();
@@ -130,42 +130,42 @@ class UseBraces
for( int b : branches)
f(); // $ Alert
g(); // Alert
g();
for( int b : branches)
f(); g(); // $ Alert // Alert
f(); g(); // $ Alert
// Nested ifs
if( true )
if(false)
f();
g(); // No alert
if( true )
if(false) // $ Alert
f();
g(); // Alert
g();
if( true )
;
else
else
if (false)
f();
g(); // No alert
if( true )
;
else
else
if (false)
f();
g(); // false negative
g(); // $ MISSING: Alert // false negative
if( true )
;
else if (false)
f(); // $ Alert
g(); // Alert
g();
// Nested combinations
if (true)
while (x<10)
@@ -175,7 +175,7 @@ class UseBraces
if (true)
while (x<10) // $ Alert
f();
g(); // Alert
g();
while (x<10)
if (true)
@@ -185,7 +185,7 @@ class UseBraces
while (x<10)
if (true) // $ Alert
f();
g(); // Alert
g();
if (true)
f();

View File

@@ -62,10 +62,10 @@ public class ResponseSplitting extends HttpServlet {
response.setHeader("h", t.replace('\n', ' ').replace('\r', ' '));
// FALSE NEGATIVE: replace only some line breaks
response.setHeader("h", t.replace('\n', ' '));
response.setHeader("h", t.replace('\n', ' ')); // $ MISSING: Alert
// FALSE NEGATIVE: replace only some line breaks
response.setHeader("h", t.replaceAll("\r", ""));
response.setHeader("h", t.replaceAll("\r", "")); // $ MISSING: Alert
// GOOD: replace all linebreaks with a simple regex
response.setHeader("h", t.replaceAll("\n", "").replaceAll("\r", ""));

View File

@@ -78,7 +78,7 @@ public class ArithmeticTainted {
// FALSE NEGATIVE: stillTainted could still be very large, even
// after
// it has had arithmetic done on it
int output = stillTainted + 100;
int output = stillTainted + 100; // $ MISSING: Alert[java/tainted-arithmetic]
}
}
@@ -107,7 +107,7 @@ public class ArithmeticTainted {
}
int output = data + 1;
}
{
double x= Double.MAX_VALUE;
// OK: CWE-190 only pertains to integer arithmetic

View File

@@ -84,7 +84,7 @@ class Test {
// FALSE POSITIVE: the query check purely based on the type, it
// can't try to
// determine whether the value may in fact always be in bounds
i += j; // $ Alert[java/implicit-cast-in-compound-assignment]
i += j; // $ SPURIOUS: Alert[java/implicit-cast-in-compound-assignment]
}
// ArithmeticWithExtremeValues
@@ -224,7 +224,7 @@ class Test {
// FALSE NEGATIVE: stillLarge could still be very large, even
// after
// it has had arithmetic done on it
int output = stillLarge + 100;
int output = stillLarge + 100; // $ MISSING: Alert[java/uncontrolled-arithmetic]
}
}
@@ -263,7 +263,7 @@ class Test {
// FALSE NEGATIVE: stillLarge could still be very large, even
// after
// it has had arithmetic done on it
int output = stillLarge + 100;
int output = stillLarge + 100; // $ MISSING: Alert[java/uncontrolled-arithmetic]
}
}

View File

@@ -17,7 +17,7 @@ interface Hello extends java.rmi.Remote {
class HelloImpl implements Hello {
public static void main(String[] args) {
try {
try {
// HttpsUrls
{
String protocol = "http://"; // $ Source[java/non-https-url]
@@ -31,7 +31,7 @@ class HelloImpl implements Hello {
OutputStream os = hu.getOutputStream();
hu.disconnect();
}
{
String protocol = "http"; // $ Source[java/non-https-url]
URL u = new URL(protocol, "www.secret.example.org", "foo");
@@ -44,7 +44,7 @@ class HelloImpl implements Hello {
OutputStream os = hu.getOutputStream();
hu.disconnect();
}
{
String protocol = "http://"; // $ Source[java/non-https-url]
// the second URL overwrites the first, as it has a protocol
@@ -58,7 +58,7 @@ class HelloImpl implements Hello {
OutputStream os = hu.getOutputStream();
hu.disconnect();
}
{
String protocol = "https://";
URL u = new URL(protocol + "www.secret.example.org/");
@@ -70,7 +70,7 @@ class HelloImpl implements Hello {
OutputStream os = hu.getOutputStream();
hu.disconnect();
}
{
String protocol = "https";
URL u = new URL(protocol, "www.secret.example.org", "foo");
@@ -82,27 +82,27 @@ class HelloImpl implements Hello {
OutputStream os = hu.getOutputStream();
hu.disconnect();
}
{
String protocol = "http"; // $ Source[java/non-https-url]
String protocol = "http"; // $ SPURIOUS: Source[java/non-https-url]
URL u = new URL(protocol, "internal-url", "foo");
// FALSE POSITIVE: the query has no way of knowing whether the url will
// resolve to somewhere outside the internal network, where there
// are unlikely to be interception attempts
HttpsURLConnection hu = (HttpsURLConnection) u.openConnection(); // $ Alert[java/non-https-url]
HttpsURLConnection hu = (HttpsURLConnection) u.openConnection(); // $ SPURIOUS: Alert[java/non-https-url]
hu.setRequestMethod("PUT");
hu.connect();
OutputStream os = hu.getOutputStream();
hu.disconnect();
}
{
String input = "URL is: http://www.secret-example.org";
String url = input.substring(8);
URL u = new URL(url);
// FALSE NEGATIVE: we cannot tell that the substring results in a url
// string
HttpsURLConnection hu = (HttpsURLConnection) u.openConnection();
HttpsURLConnection hu = (HttpsURLConnection) u.openConnection(); // $ MISSING: Alert[java/non-https-url]
hu.setRequestMethod("PUT");
hu.connect();
OutputStream os = hu.getOutputStream();

View File

@@ -119,6 +119,12 @@ signature module AstSig<LocationSig Location> {
Expr getCondition();
}
/** An `until` loop statement. */
class UntilStmt extends LoopStmt {
/** Gets the boolean condition of this `until` loop. */
Expr getCondition();
}
/** A traditional C-style `for` loop. */
class ForStmt extends LoopStmt {
/** Gets the initializer of the loop at the specified (zero-based) position, if any. */
@@ -608,6 +614,7 @@ module Make0<LocationSig Location, AstSig<Location> Ast> {
any(IfStmt ifstmt).getCondition() = n or
any(WhileStmt whilestmt).getCondition() = n or
any(DoStmt dostmt).getCondition() = n or
any(UntilStmt untilstmt).getCondition() = n or
any(ForStmt forstmt).getCondition() = n or
any(ConditionalExpr condexpr).getCondition() = n or
any(CatchClause catch).getCondition() = n or
@@ -1513,7 +1520,12 @@ module Make0<LocationSig Location, AstSig<Location> Ast> {
n2.isBefore(ifstmt.getCondition())
or
n1.isAfterTrue(ifstmt.getCondition()) and
n2.isBefore(ifstmt.getThen())
(
n2.isBefore(ifstmt.getThen())
or
not exists(ifstmt.getThen()) and
n2.isAfter(ifstmt)
)
or
n1.isAfterFalse(ifstmt.getCondition()) and
(
@@ -1530,9 +1542,9 @@ module Make0<LocationSig Location, AstSig<Location> Ast> {
n2.isAfter(ifstmt)
)
or
exists(WhileStmt whilestmt |
n1.isBefore(whilestmt) and
n2.isAdditional(whilestmt, loopHeaderTag())
exists(LoopStmt loopstmt | loopstmt instanceof WhileStmt or loopstmt instanceof UntilStmt |
n1.isBefore(loopstmt) and
n2.isAdditional(loopstmt, loopHeaderTag())
)
or
exists(DoStmt dostmt |
@@ -1540,16 +1552,20 @@ module Make0<LocationSig Location, AstSig<Location> Ast> {
n2.isBefore(dostmt.getBody())
)
or
exists(LoopStmt loopstmt, AstNode cond |
loopstmt.(WhileStmt).getCondition() = cond or loopstmt.(DoStmt).getCondition() = cond
exists(LoopStmt loopstmt, AstNode cond, boolean while |
loopstmt.(WhileStmt).getCondition() = cond and while = true
or
loopstmt.(DoStmt).getCondition() = cond and while = true
or
loopstmt.(UntilStmt).getCondition() = cond and while = false
|
n1.isAdditional(loopstmt, loopHeaderTag()) and
n2.isBefore(cond)
or
n1.isAfterTrue(cond) and
n1.isAfterValue(cond, any(BooleanSuccessor b | b.getValue() = while)) and
n2.isBefore(loopstmt.getBody())
or
n1.isAfterFalse(cond) and
n1.isAfterValue(cond, any(BooleanSuccessor b | b.getValue() = while.booleanNot())) and
n2.isAfter(loopstmt)
or
n1.isAfter(loopstmt.getBody()) and

View File

@@ -333,6 +333,9 @@ pub fn extract(
.run_from_tree(&tree, source)
.unwrap_or_else(|e| panic!("Desugaring failed for {path_str}: {e}"));
traverse_yeast(&ast, &mut visitor);
// Comments and other `extra` nodes are not represented in the desugared
// AST, so recover them directly from the original parse tree.
traverse_extras(&tree, &mut visitor);
} else {
traverse(&tree, &mut visitor);
}
@@ -365,6 +368,8 @@ struct Visitor<'a> {
ast_node_parent_table_name: String,
/// Language-specific name of the tokeninfo table
tokeninfo_table_name: String,
/// Language-specific name of the trivia tokeninfo table
trivia_tokeninfo_table_name: String,
/// A lookup table from type name to node types
schema: &'a NodeTypeMap,
/// A stack for gathering information from child nodes. Whenever a node is
@@ -395,11 +400,33 @@ impl<'a> Visitor<'a> {
ast_node_location_table_name: format!("{language_prefix}_ast_node_location"),
ast_node_parent_table_name: format!("{language_prefix}_ast_node_parent"),
tokeninfo_table_name: format!("{language_prefix}_tokeninfo"),
trivia_tokeninfo_table_name: format!("{language_prefix}_trivia_tokeninfo"),
schema,
stack: Vec::new(),
}
}
/// Emits a `TriviaToken` for the given `extra` node (e.g. a comment) from
/// the original parse tree. Trivia tokens carry a location and their source
/// text, but are not attached to a parent in the (possibly desugared) AST.
fn emit_trivia_token(&mut self, node: &Node) {
let id = self.trap_writer.fresh_id();
let loc = location_for(self, self.file_label, node);
let loc_label = location_label(self.trap_writer, loc);
self.trap_writer.add_tuple(
&self.ast_node_location_table_name,
vec![trap::Arg::Label(id), trap::Arg::Label(loc_label)],
);
self.trap_writer.add_tuple(
&self.trivia_tokeninfo_table_name,
vec![
trap::Arg::Label(id),
trap::Arg::Int(node.kind_id() as usize),
sliced_source_arg(self.source, node),
],
);
}
fn record_parse_error(&mut self, loc: trap::Label, mesg: &diagnostics::DiagnosticMessage) {
self.diagnostics_writer.write(mesg);
let id = self.trap_writer.fresh_id();
@@ -835,6 +862,24 @@ fn traverse(tree: &Tree, visitor: &mut Visitor) {
}
}
/// Walks the original tree-sitter tree and emits a `TriviaToken` for every
/// `extra` node (e.g. a comment). Used to preserve comments that would
/// otherwise be lost after a desugaring pass rewrites the tree.
fn traverse_extras(tree: &Tree, visitor: &mut Visitor) {
emit_extras_in(visitor, tree.root_node());
}
fn emit_extras_in(visitor: &mut Visitor, node: Node<'_>) {
let mut cursor = node.walk();
for child in node.children(&mut cursor) {
if child.is_extra() {
visitor.emit_trivia_token(&child);
} else {
emit_extras_in(visitor, child);
}
}
}
fn traverse_yeast(tree: &yeast::Ast, visitor: &mut Visitor) {
use yeast::Cursor;
let mut cursor = tree.walk();

View File

@@ -68,7 +68,12 @@ pub fn generate(
let node_parent_table_name = format!("{}_ast_node_parent", &prefix);
let token_name = format!("{}_token", &prefix);
let tokeninfo_name = format!("{}_tokeninfo", &prefix);
let trivia_token_name = format!("{}_trivia_token", &prefix);
let trivia_tokeninfo_name = format!("{}_trivia_tokeninfo", &prefix);
let reserved_word_name = format!("{}_reserved_word", &prefix);
// When a desugaring is configured, comments and other `extra` nodes are
// preserved from the original parse tree as `TriviaToken`s.
let has_trivia_tokens = language.desugar.is_some();
let effective_node_types: String = match language
.desugar
.as_ref()
@@ -85,28 +90,35 @@ pub fn generate(
let nodes = node_types::read_node_types_str(&prefix, &effective_node_types)?;
let (dbscheme_entries, mut ast_node_members, token_kinds) = convert_nodes(&nodes);
ast_node_members.insert(&token_name);
if has_trivia_tokens {
ast_node_members.insert(&trivia_token_name);
}
writeln!(&mut dbscheme_writer, "/*- {} dbscheme -*/", language.name)?;
dbscheme::write(&mut dbscheme_writer, &dbscheme_entries)?;
let token_case = create_token_case(&token_name, token_kinds);
dbscheme::write(
&mut dbscheme_writer,
&[
dbscheme::Entry::Table(create_tokeninfo(&tokeninfo_name, &token_name)),
dbscheme::Entry::Case(token_case),
dbscheme::Entry::Union(dbscheme::Union {
name: &ast_node_name,
members: ast_node_members,
}),
dbscheme::Entry::Table(create_ast_node_location_table(
&node_location_table_name,
&ast_node_name,
)),
dbscheme::Entry::Table(create_ast_node_parent_table(
&node_parent_table_name,
&ast_node_name,
)),
],
)?;
let mut dbscheme_tail = vec![
dbscheme::Entry::Table(create_tokeninfo(&tokeninfo_name, &token_name)),
dbscheme::Entry::Case(token_case),
];
if has_trivia_tokens {
dbscheme_tail.push(dbscheme::Entry::Table(create_tokeninfo(
&trivia_tokeninfo_name,
&trivia_token_name,
)));
}
dbscheme_tail.push(dbscheme::Entry::Union(dbscheme::Union {
name: &ast_node_name,
members: ast_node_members,
}));
dbscheme_tail.push(dbscheme::Entry::Table(create_ast_node_location_table(
&node_location_table_name,
&ast_node_name,
)));
dbscheme_tail.push(dbscheme::Entry::Table(create_ast_node_parent_table(
&node_parent_table_name,
&ast_node_name,
)));
dbscheme::write(&mut dbscheme_writer, &dbscheme_tail)?;
let mut body = vec![
ql::TopLevel::Class(ql_gen::create_ast_node_class(
@@ -116,6 +128,12 @@ pub fn generate(
)),
ql::TopLevel::Class(ql_gen::create_token_class(&token_name, &tokeninfo_name)),
];
if has_trivia_tokens {
body.push(ql::TopLevel::Class(ql_gen::create_trivia_token_class(
&trivia_token_name,
&trivia_tokeninfo_name,
)));
}
// Only emit the ReservedWord class when there are actually unnamed token
// types in the schema (i.e., @{prefix}_reserved_word exists in the dbscheme).
// When converting from a YEAST YAML schema that has no unnamed tokens, this

View File

@@ -199,6 +199,70 @@ pub fn create_token_class<'a>(token_type: &'a str, tokeninfo: &'a str) -> ql::Cl
}
}
/// Creates the `TriviaToken` class. Trivia tokens (e.g. comments) are
/// `extra` nodes preserved from the original parse tree even when the tree has
/// been rewritten by a desugaring pass. They are not part of the regular
/// `Token` hierarchy because they do not appear in the (possibly desugared)
/// output schema.
pub fn create_trivia_token_class<'a>(
trivia_token_type: &'a str,
trivia_tokeninfo: &'a str,
) -> ql::Class<'a> {
let trivia_tokeninfo_arity = 3; // id, kind, value
let get_value = ql::Predicate {
qldoc: Some(String::from("Gets the source text of this trivia token.")),
name: "getValue",
overridden: false,
is_private: false,
is_final: true,
return_type: Some(ql::Type::String),
formal_parameters: vec![],
body: create_get_field_expr_for_column_storage(
"result",
trivia_tokeninfo,
1,
trivia_tokeninfo_arity,
),
overlay: None,
};
let to_string = ql::Predicate {
qldoc: Some(String::from(
"Gets a string representation of this element.",
)),
name: "toString",
overridden: true,
is_private: false,
is_final: true,
return_type: Some(ql::Type::String),
formal_parameters: vec![],
body: ql::Expression::Equals(
Box::new(ql::Expression::Var("result")),
Box::new(ql::Expression::Dot(
Box::new(ql::Expression::Var("this")),
"getValue",
vec![],
)),
),
overlay: None,
};
ql::Class {
qldoc: Some(String::from(
"A trivia token, such as a comment, preserved from the original parse tree.",
)),
name: "TriviaToken",
is_abstract: false,
supertypes: vec![ql::Type::At(trivia_token_type), ql::Type::Normal("AstNode")]
.into_iter()
.collect(),
characteristic_predicate: None,
predicates: vec![
get_value,
to_string,
create_get_a_primary_ql_class("TriviaToken", false),
],
}
}
// Creates the `ReservedWord` class.
pub fn create_reserved_word_class(db_name: &str) -> ql::Class<'_> {
let class_name = "ReservedWord";

View File

@@ -61,6 +61,18 @@ module Unified {
override string getAPrimaryQlClass() { result = "Token" }
}
/** A trivia token, such as a comment, preserved from the original parse tree. */
class TriviaToken extends @unified_trivia_token, AstNode {
/** Gets the source text of this trivia token. */
final string getValue() { unified_trivia_tokeninfo(this, _, result) }
/** Gets a string representation of this element. */
final override string toString() { result = this.getValue() }
/** Gets the name of the primary QL class for this element. */
override string getAPrimaryQlClass() { result = "TriviaToken" }
}
/** Gets the file containing the given `node`. */
private @file getNodeFile(@unified_ast_node node) {
exists(@location_default loc | unified_ast_node_location(node, loc) |

View File

@@ -0,0 +1,18 @@
/** Provides classes for working with comments. */
private import unified
/**
* A comment appearing in the source code.
*/
class Comment extends TriviaToken {
// At the moment, comments are the only type trivia token we extract
/**
* Gets the text inside this comment, not counting the delimeters.
*/
string getCommentText() {
result = this.getValue().regexpCapture("//(.*)", 1)
or
result = this.getValue().regexpCapture("(?s)/\\*(.*)\\*/", 1)
}
}

View File

@@ -334,7 +334,13 @@ case @unified_token.kind of
;
@unified_ast_node = @unified_apply_pattern | @unified_binary_expr | @unified_block_stmt | @unified_call_expr | @unified_expr_condition | @unified_expr_stmt | @unified_guard_if_stmt | @unified_if_stmt | @unified_lambda_expr | @unified_let_pattern_condition | @unified_member_access_expr | @unified_name_expr | @unified_parameter | @unified_sequence_condition | @unified_token | @unified_top_level | @unified_tuple_pattern | @unified_unary_expr | @unified_var_pattern | @unified_variable_declaration_stmt | @unified_variable_declarator
unified_trivia_tokeninfo(
unique int id: @unified_trivia_token,
int kind: int ref,
string value: string ref
);
@unified_ast_node = @unified_apply_pattern | @unified_binary_expr | @unified_block_stmt | @unified_call_expr | @unified_expr_condition | @unified_expr_stmt | @unified_guard_if_stmt | @unified_if_stmt | @unified_lambda_expr | @unified_let_pattern_condition | @unified_member_access_expr | @unified_name_expr | @unified_parameter | @unified_sequence_condition | @unified_token | @unified_top_level | @unified_trivia_token | @unified_tuple_pattern | @unified_unary_expr | @unified_var_pattern | @unified_variable_declaration_stmt | @unified_variable_declarator
unified_ast_node_location(
unique int node: @unified_ast_node ref,

View File

@@ -0,0 +1,8 @@
/**
* Provides classes for working with the AST, as well as files and locations.
*/
import codeql.Locations
import codeql.files.FileSystem
import codeql.unified.Ast::Unified
import codeql.unified.Comments

View File

@@ -0,0 +1,3 @@
| comments.swift:1:1:1:22 | // Hello this is swift | Hello this is swift |
| comments.swift:3:1:6:3 | /*\n * This is a multi-line comment\n * It should be ignored by the parser\n */ | \n * This is a multi-line comment\n * It should be ignored by the parser\n |
| comments.swift:9:5:9:36 | // This is a single-line comment | This is a single-line comment |

View File

@@ -0,0 +1,3 @@
import unified
query predicate comments(Comment c, string text) { text = c.getCommentText() }

View File

@@ -0,0 +1,11 @@
// Hello this is swift
/*
* This is a multi-line comment
* It should be ignored by the parser
*/
func hello() {
// This is a single-line comment
print("Hello, world!")
}