diff --git a/shared/ssa/codeql/ssa/Ssa.qll b/shared/ssa/codeql/ssa/Ssa.qll index b8fe058bc0f5..a0c295c5d27d 100644 --- a/shared/ssa/codeql/ssa/Ssa.qll +++ b/shared/ssa/codeql/ssa/Ssa.qll @@ -1419,6 +1419,22 @@ module Make< */ default predicate allowFlowIntoUncertainDef(UncertainWriteDefinition def) { none() } + /** + * Holds if the post-update node corresponding to the given `read` occurs at `bb,i`, meaning + * it will propagate to the next use (strictly) after that point in the CFG. + * + * The default is to use the CFG node associated with the read itself, meaning the post-update + * always flows to the next use. The default can however lead to spurious flow in cases like: + * ``` + * x.f = foo(x) + * ``` + * where the post-update node for `x` on the left-hand side flows into the `x` on the right-hand side. + * + * NOTE: When implementing this predicate, you must ensure that `variableRead` is defined to contain + * a synthetic read of this variable at `bb,i`. + */ + default predicate postUpdateCfgNode(Expr read, BasicBlock bb, int i) { read.hasCfgNode(bb, i) } + /** An abstract value that a `Guard` may evaluate to. */ class GuardValue { /** Gets a textual representation of this value. */ @@ -1892,6 +1908,13 @@ module Make< override string toString() { result = "[input] " + def_.toString() } } + private predicate postUpdateNodeAt( + ExprPostUpdateNode node, BasicBlock bb, int i, SourceVariable v + ) { + node.getPreUpdateNode().(ReadNode).readsAt(_, _, v) and + DfInput::postUpdateCfgNode(node.getExpr(), bb, i) + } + /** * Holds if `nodeFrom` corresponds to the reference to `v` at index `i` in * `bb`. The boolean `isUseStep` indicates whether `nodeFrom` is an actual @@ -1907,7 +1930,10 @@ module Make< isUseStep = false ) or - [nodeFrom, nodeFrom.(ExprPostUpdateNode).getPreUpdateNode()].(ReadNode).readsAt(bb, i, v) and + nodeFrom.(ReadNode).readsAt(bb, i, v) and + isUseStep = true + or + postUpdateNodeAt(nodeFrom, bb, i, v) and isUseStep = true } diff --git a/unified/extractor/ast_types.yml b/unified/extractor/ast_types.yml index f1ee78f1c621..b293820d9cd8 100644 --- a/unified/extractor/ast_types.yml +++ b/unified/extractor/ast_types.yml @@ -23,8 +23,6 @@ supertypes: - type_cast_expr - type_test_expr - if_expr - - assign_expr - - compound_assign_expr - pattern_guard_expr - empty_expr - block @@ -159,17 +157,6 @@ named: unresolved_operator_sequence: element*: expr_or_operator - # Plain assignment - assign_expr: - target: expr - value: expr - - # Compound assignment - compound_assign_expr: - target: expr - operator: infix_operator - value: expr - # A function or method call, such as `f(x)` or `obj.m(x)`. # # Method calls are represented as a call whose `function` is a `member_access_expr`. diff --git a/unified/extractor/src/languages/swift/swift.rs b/unified/extractor/src/languages/swift/swift.rs index e355cbb96dce..8242e37a8a3f 100644 --- a/unified/extractor/src/languages/swift/swift.rs +++ b/unified/extractor/src/languages/swift/swift.rs @@ -129,13 +129,6 @@ fn member_chain( result } -/// Compound-assignment operator spellings (`+=`, `<<=`, ...). Used to tell a -/// compound assignment from an ordinary binary application, both of which -/// arrive as a `binaryOperator`-based `infixOperatorExpr`. -const COMPOUND_ASSIGN_OPS: &[&str] = &[ - "+=", "-=", "*=", "/=", "%=", "<<=", ">>=", "&=", "|=", "^=", "&+=", "&-=", "&*=", -]; - fn translation_rules() -> Vec> { vec![ // ---- Top-level ---- @@ -243,29 +236,21 @@ fn translation_rules() -> Vec> { // operator leaf. Used by `infixOperatorExpr` (folded) and `sequenceExpr` // (unresolved). rule!((binaryOperatorExpr operator: @op) => (infix_operator #{op})), - // Compound assignment (`x += y`) vs. an ordinary binary application - // (`a + b`): both are `binaryOperator`-based `infixOperatorExpr`s, - // distinguishable only by the operator's spelling. The query engine - // can't match on token text, so a small Rust block reads the spelling - // and routes to `compound_assign_expr` or `binary_expr`. The operator - // is captured raw (`@@op`) to read its spelling. + // A `binaryOperator`-based `infixOperatorExpr` represents both ordinary + // binary applications (`a + b`) and compound assignments (`x += y`). + // Both have the same target AST shape; the QL library distinguishes + // assignments by the operator spelling. rule!( (infixOperatorExpr leftOperand: @l operator: (binaryOperatorExpr) @@op rightOperand: @r) => - expr { - if COMPOUND_ASSIGN_OPS.contains(&ctx.source_text(op).as_str()) { - tree!((compound_assign_expr target: {l} operator: (infix_operator #{op}) value: {r})) - } else { - tree!((binary_expr left: {l} operator: (infix_operator #{op}) right: {r})) - } - } + (binary_expr left: {l} operator: (infix_operator #{op}) right: {r}) ), - // Plain assignment (`x = y`). In a folded chain the `=` is an - // `assignmentExpr` node (distinct from other operators), matched by kind. + // Plain assignment (`x = y`). In a folded chain the `=` is represented + // by an `assignmentExpr` node rather than a `binaryOperatorExpr`. rule!( - (infixOperatorExpr leftOperand: @l operator: (assignmentExpr) rightOperand: @r) + (infixOperatorExpr leftOperand: @l operator: (assignmentExpr) @op rightOperand: @r) => - (assign_expr target: {l} value: {r}) + (binary_expr left: {l} operator: (infix_operator #{op}) right: {r}) ), // In an unresolved `sequenceExpr` (below) the operator positions are not // only `binaryOperatorExpr`s: a plain assignment (`=`), an `as`/`is` cast diff --git a/unified/extractor/tests/corpus/swift/control-flow/if-case-let-with-shadowing-in-condition-value.output b/unified/extractor/tests/corpus/swift/control-flow/if-case-let-with-shadowing-in-condition-value.output index 699609a26309..1b44ec1e7707 100644 --- a/unified/extractor/tests/corpus/swift/control-flow/if-case-let-with-shadowing-in-condition-value.output +++ b/unified/extractor/tests/corpus/swift/control-flow/if-case-let-with-shadowing-in-condition-value.output @@ -151,7 +151,7 @@ top_level then: block stmt: - compound_assign_expr - target: identifier "y" + binary_expr + left: identifier "y" operator: infix_operator "+=" - value: int_literal "1" + right: int_literal "1" diff --git a/unified/extractor/tests/corpus/swift/expressions/array-type-constructor.output b/unified/extractor/tests/corpus/swift/expressions/array-type-constructor.output index be59a73183d9..6f33fc0321a4 100644 --- a/unified/extractor/tests/corpus/swift/expressions/array-type-constructor.output +++ b/unified/extractor/tests/corpus/swift/expressions/array-type-constructor.output @@ -167,6 +167,7 @@ top_level body: block stmt: - assign_expr - target: identifier "count" - value: int_literal "0" + binary_expr + left: identifier "count" + operator: infix_operator "=" + right: int_literal "0" diff --git a/unified/extractor/tests/corpus/swift/functions/function-with-inout-parameter.output b/unified/extractor/tests/corpus/swift/functions/function-with-inout-parameter.output index 198bb22bb29f..83e3c7a53c2d 100644 --- a/unified/extractor/tests/corpus/swift/functions/function-with-inout-parameter.output +++ b/unified/extractor/tests/corpus/swift/functions/function-with-inout-parameter.output @@ -71,7 +71,7 @@ top_level body: block stmt: - compound_assign_expr - target: identifier "x" + binary_expr + left: identifier "x" operator: infix_operator "+=" - value: int_literal "1" + right: int_literal "1" diff --git a/unified/extractor/tests/corpus/swift/loops/repeat-while-loop.output b/unified/extractor/tests/corpus/swift/loops/repeat-while-loop.output index 025cdb19f63f..6287bbaa9bfc 100644 --- a/unified/extractor/tests/corpus/swift/loops/repeat-while-loop.output +++ b/unified/extractor/tests/corpus/swift/loops/repeat-while-loop.output @@ -51,10 +51,10 @@ top_level body: block stmt: - compound_assign_expr - target: identifier "x" + binary_expr + left: identifier "x" operator: infix_operator "-=" - value: int_literal "1" + right: int_literal "1" condition: binary_expr left: identifier "x" diff --git a/unified/extractor/tests/corpus/swift/loops/while-loop.output b/unified/extractor/tests/corpus/swift/loops/while-loop.output index 54b3c20d61ab..f4f64cfca6bc 100644 --- a/unified/extractor/tests/corpus/swift/loops/while-loop.output +++ b/unified/extractor/tests/corpus/swift/loops/while-loop.output @@ -57,7 +57,7 @@ top_level body: block stmt: - compound_assign_expr - target: identifier "x" + binary_expr + left: identifier "x" operator: infix_operator "-=" - value: int_literal "1" + right: int_literal "1" diff --git a/unified/extractor/tests/corpus/swift/types/class-with-initializer.output b/unified/extractor/tests/corpus/swift/types/class-with-initializer.output index 8027fd0fca8c..cd9e3c1eb9ad 100644 --- a/unified/extractor/tests/corpus/swift/types/class-with-initializer.output +++ b/unified/extractor/tests/corpus/swift/types/class-with-initializer.output @@ -106,9 +106,10 @@ top_level body: block stmt: - assign_expr - target: + binary_expr + left: member_access_expr base: identifier "self" member_name_node: identifier "x" - value: identifier "x" + operator: infix_operator "=" + right: identifier "x" diff --git a/unified/extractor/tests/corpus/swift/types/class-with-method.output b/unified/extractor/tests/corpus/swift/types/class-with-method.output index f0b8cbf68dfb..2cc184038255 100644 --- a/unified/extractor/tests/corpus/swift/types/class-with-method.output +++ b/unified/extractor/tests/corpus/swift/types/class-with-method.output @@ -90,7 +90,7 @@ top_level body: block stmt: - compound_assign_expr - target: identifier "n" + binary_expr + left: identifier "n" operator: infix_operator "+=" - value: int_literal "1" + right: int_literal "1" diff --git a/unified/extractor/tests/corpus/swift/types/property-with-getter-and-setter.output b/unified/extractor/tests/corpus/swift/types/property-with-getter-and-setter.output index 0641e6e30931..a37b28985e6b 100644 --- a/unified/extractor/tests/corpus/swift/types/property-with-getter-and-setter.output +++ b/unified/extractor/tests/corpus/swift/types/property-with-getter-and-setter.output @@ -136,6 +136,7 @@ top_level body: block stmt: - assign_expr - target: identifier "_v" - value: identifier "newValue" + binary_expr + left: identifier "_v" + operator: infix_operator "=" + right: identifier "newValue" diff --git a/unified/extractor/tests/corpus/swift/variables/assignment.output b/unified/extractor/tests/corpus/swift/variables/assignment.output index a81c74dd6c29..384b09066e37 100644 --- a/unified/extractor/tests/corpus/swift/variables/assignment.output +++ b/unified/extractor/tests/corpus/swift/variables/assignment.output @@ -24,6 +24,7 @@ top_level body: block stmt: - assign_expr - target: identifier "x" - value: int_literal "1" + binary_expr + left: identifier "x" + operator: infix_operator "=" + right: int_literal "1" diff --git a/unified/extractor/tests/corpus/swift/variables/compound-assignment.output b/unified/extractor/tests/corpus/swift/variables/compound-assignment.output index 0189512f9abd..e5e1fc04f93d 100644 --- a/unified/extractor/tests/corpus/swift/variables/compound-assignment.output +++ b/unified/extractor/tests/corpus/swift/variables/compound-assignment.output @@ -24,7 +24,7 @@ top_level body: block stmt: - compound_assign_expr - target: identifier "x" + binary_expr + left: identifier "x" operator: infix_operator "+=" - value: int_literal "1" + right: int_literal "1" diff --git a/unified/ql/lib/codeql/unified/internal/Ast.qll b/unified/ql/lib/codeql/unified/internal/Ast.qll index a04b93291707..ea296e4d3dd7 100644 --- a/unified/ql/lib/codeql/unified/internal/Ast.qll +++ b/unified/ql/lib/codeql/unified/internal/Ast.qll @@ -183,23 +183,6 @@ module Unified { final override F::AstNode getAFieldOrChild() { unified_array_literal_element(this, _, result) } } - /** A class representing `assign_expr` nodes. */ - class AssignExpr extends @unified_assign_expr, F::Expr { - /** Gets the name of the primary QL class for this element. */ - final override string getAPrimaryQlClass() { result = "AssignExpr" } - - /** Gets the node corresponding to the field `target`. */ - final F::Expr getTarget() { unified_assign_expr_def(this, result, _) } - - /** Gets the node corresponding to the field `value`. */ - final F::Expr getValue() { unified_assign_expr_def(this, _, result) } - - /** Gets a field or child node of this node. */ - final override F::AstNode getAFieldOrChild() { - unified_assign_expr_def(this, result, _) or unified_assign_expr_def(this, _, result) - } - } - /** A class representing `associated_type_declaration` nodes. */ class AssociatedTypeDeclaration extends @unified_associated_type_declaration, F::Member { /** Gets the name of the primary QL class for this element. */ @@ -468,28 +451,6 @@ module Unified { } } - /** A class representing `compound_assign_expr` nodes. */ - class CompoundAssignExpr extends @unified_compound_assign_expr, F::Expr { - /** Gets the name of the primary QL class for this element. */ - final override string getAPrimaryQlClass() { result = "CompoundAssignExpr" } - - /** Gets the node corresponding to the field `operator`. */ - final F::InfixOperator getOperator() { unified_compound_assign_expr_def(this, result, _, _) } - - /** Gets the node corresponding to the field `target`. */ - final F::Expr getTarget() { unified_compound_assign_expr_def(this, _, result, _) } - - /** Gets the node corresponding to the field `value`. */ - final F::Expr getValue() { unified_compound_assign_expr_def(this, _, _, result) } - - /** Gets a field or child node of this node. */ - final override F::AstNode getAFieldOrChild() { - unified_compound_assign_expr_def(this, result, _, _) or - unified_compound_assign_expr_def(this, _, result, _) or - unified_compound_assign_expr_def(this, _, _, result) - } - } - /** A class representing `conditional_pattern` nodes. */ class ConditionalPattern extends @unified_conditional_pattern, F::Expr { /** Gets the name of the primary QL class for this element. */ @@ -1576,10 +1537,6 @@ module Unified { or result = node.(ArrayLiteral).getElement(i) and name = "getElement" or - result = node.(AssignExpr).getTarget() and i = -1 and name = "getTarget" - or - result = node.(AssignExpr).getValue() and i = -1 and name = "getValue" - or result = node.(AssociatedTypeDeclaration).getBound() and i = -1 and name = "getBound" or result = node.(AssociatedTypeDeclaration).getModifier(i) and name = "getModifier" @@ -1634,12 +1591,6 @@ module Unified { or result = node.(ClassLikeDeclaration).getTypeParameter(i) and name = "getTypeParameter" or - result = node.(CompoundAssignExpr).getOperator() and i = -1 and name = "getOperator" - or - result = node.(CompoundAssignExpr).getTarget() and i = -1 and name = "getTarget" - or - result = node.(CompoundAssignExpr).getValue() and i = -1 and name = "getValue" - or result = node.(ConditionalPattern).getCondition() and i = -1 and name = "getCondition" or result = node.(ConditionalPattern).getModifier(i) and name = "getModifier" @@ -1879,8 +1830,6 @@ module UnifiedFinal { final class ArrayLiteral = F::ArrayLiteral; - final class AssignExpr = F::AssignExpr; - final class AssociatedTypeDeclaration = F::AssociatedTypeDeclaration; final class BaseType = F::BaseType; @@ -1907,8 +1856,6 @@ module UnifiedFinal { final class ClassLikeDeclaration = F::ClassLikeDeclaration; - final class CompoundAssignExpr = F::CompoundAssignExpr; - final class ConditionalPattern = F::ConditionalPattern; final class ConstructorDeclaration = F::ConstructorDeclaration; diff --git a/unified/ql/lib/codeql/unified/internal/AstExtra.qll b/unified/ql/lib/codeql/unified/internal/AstExtra.qll index 64ab0262ea56..486fb16ad3e5 100644 --- a/unified/ql/lib/codeql/unified/internal/AstExtra.qll +++ b/unified/ql/lib/codeql/unified/internal/AstExtra.qll @@ -6,6 +6,38 @@ private import unified private import codeql.unified.internal.NameBindingPlugin module Public { + /** An assignment, possibly a compound assignment. */ + abstract class AssignmentImpl extends BinaryExpr { + /** Gets the target of this assignment. */ + abstract Expr getTarget(); + + /** Gets the value assigned by this assignment. */ + abstract Expr getValue(); + } + + final class Assignment = AssignmentImpl; + + /** A plain assignment expression. */ + final class AssignExpr extends BinaryExpr, AssignmentImpl { + AssignExpr() { this.getOperator().getValue() = "=" } + + override Expr getTarget() { result = this.getLeft() } + + override Expr getValue() { result = this.getRight() } + } + + /** A compound assignment expression. */ + final class CompoundAssignExpr extends BinaryExpr, AssignmentImpl { + CompoundAssignExpr() { + this.getOperator().getValue() = + ["+=", "-=", "*=", "/=", "%=", "<<=", ">>=", "&=", "|=", "^=", "&+=", "&-=", "&*="] + } + + override Expr getTarget() { result = this.getLeft() } + + override Expr getValue() { result = this.getRight() } + } + /** A short-circuiting logical AND expression. */ class LogicalAndExpr extends BinaryExpr { LogicalAndExpr() { this.getOperator().getValue() = "&&" } diff --git a/unified/ql/lib/codeql/unified/internal/ControlFlowGraph.qll b/unified/ql/lib/codeql/unified/internal/ControlFlowGraph.qll index 019722484d1a..157c6794ff51 100644 --- a/unified/ql/lib/codeql/unified/internal/ControlFlowGraph.qll +++ b/unified/ql/lib/codeql/unified/internal/ControlFlowGraph.qll @@ -196,20 +196,23 @@ private module Ast implements AstSig { class LogicalNotExpr = U::LogicalNotExpr; - // TODO - class Assignment extends BinaryExpr { - Assignment() { none() } - } + class Assignment extends BinaryExpr, U::Assignment { } - class AssignExpr extends Assignment { } + class AssignExpr extends Assignment, U::AssignExpr { } - class CompoundAssignment extends Assignment { } + class CompoundAssignment extends Assignment, U::CompoundAssignExpr { } - class AssignLogicalAndExpr extends CompoundAssignment { } + class AssignLogicalAndExpr extends CompoundAssignment { + AssignLogicalAndExpr() { this.getOperator().getValue() = "&&=" } + } - class AssignLogicalOrExpr extends CompoundAssignment { } + class AssignLogicalOrExpr extends CompoundAssignment { + AssignLogicalOrExpr() { this.getOperator().getValue() = "||=" } + } - class AssignNullCoalescingExpr extends CompoundAssignment { } + class AssignNullCoalescingExpr extends CompoundAssignment { + AssignNullCoalescingExpr() { this.getOperator().getValue() = "??=" } + } class BooleanLiteral extends U::BooleanLiteral { boolean getValue() { result.toString() = super.getValue() } diff --git a/unified/ql/lib/codeql/unified/internal/dataflow/DataFlowGraph.qll b/unified/ql/lib/codeql/unified/internal/dataflow/DataFlowGraph.qll index 1edff6eea04b..2bd96b2b3ef1 100644 --- a/unified/ql/lib/codeql/unified/internal/dataflow/DataFlowGraph.qll +++ b/unified/ql/lib/codeql/unified/internal/dataflow/DataFlowGraph.qll @@ -16,6 +16,14 @@ predicate step(Node node1, Step step, Node node2) { node2.isIncomingValue(assign.getTarget()) ) or + // For compound assignments, the result of the expression represents the result of the operator. + // Make it flow to the target of the assignment. + exists(CompoundAssignExpr assign | + node1.isResultValue(assign) and + step.value() and + node2.isIncomingValue(assign.getTarget()) + ) + or exists(LocalVariableAccess access | node1.isLocalVariableRead(access, access.getLocalVariable()) and step.value() and diff --git a/unified/ql/lib/codeql/unified/internal/dataflow/DataFlowNode.qll b/unified/ql/lib/codeql/unified/internal/dataflow/DataFlowNode.qll index bc4bec52b948..09cf4b9f4606 100644 --- a/unified/ql/lib/codeql/unified/internal/dataflow/DataFlowNode.qll +++ b/unified/ql/lib/codeql/unified/internal/dataflow/DataFlowNode.qll @@ -2,9 +2,16 @@ private import unified private import AllDataFlow private import codeql.unified.internal.ExprPositions -private predicate hasPostUpdate(Expr expr) { +private predicate hasIncomingValueAtCfgNode(Expr expr, ControlFlowNode cfgNode) { + exists(AstNode declOrAssignment | + hasIncomingValue(expr, declOrAssignment) and + cfgNode.injects(declOrAssignment) + ) +} + +private predicate hasPostUpdate(Expr expr, ControlFlowNode cfgNode) { exists(MemberAccessExpr member | - (hasIncomingValue(member, _) or hasPostUpdate(member)) and + (hasIncomingValueAtCfgNode(member, cfgNode) or hasPostUpdate(member, cfgNode)) and expr = member.getBase() ) } @@ -16,11 +23,11 @@ predicate performsVariableAccess( Expr expr, LocalVariable var, VariableRefKind kind, ControlFlowNode cfgNode ) { exists(LocalVariableAccess access | var = access.getLocalVariable() and expr = access | - hasResultValue(access) and kind.isRead() and cfgNode.isAfter(expr) + hasResultValue(access) and kind.isRead() and cfgNode.asExpr() = expr or - hasIncomingValue(access, _) and kind.isWrite() and cfgNode.asExpr() = expr // TODO: use more precise CFG node + hasIncomingValueAtCfgNode(access, cfgNode) and kind.isWrite() or - hasPostUpdate(access) and kind.isPostUpdate() and cfgNode.asExpr() = expr // TODO: use more precise CFG node + hasPostUpdate(access, cfgNode) and kind.isPostUpdate() ) or exists(UnqualifiedMemberAccess access | @@ -28,16 +35,15 @@ predicate performsVariableAccess( | kind.isRead() and cfgNode.isBefore(access) or - (hasIncomingValue(access, _) or hasPostUpdate(access)) and - kind.isPostUpdate() and - cfgNode.asExpr() = access // TODO: use more precise CFG node + (hasIncomingValueAtCfgNode(access, cfgNode) or hasPostUpdate(access, cfgNode)) and + kind.isPostUpdate() ) } newtype TDataFlowNode = TValueNode(Expr expr) { hasResultValue(expr) or hasIncomingValue(expr, _) } or TStrictlyIncomingValue(Expr expr) { hasResultValue(expr) and hasIncomingValue(expr, _) } or - TExprPostUpdateNode(Expr expr) { hasPostUpdate(expr) } or + TExprPostUpdateNode(Expr expr) { hasPostUpdate(expr, _) } or TLocalVariableRefNode(Expr expr, LocalVariable var, VariableRefKind kind) { performsVariableAccess(expr, var, kind, _) } or diff --git a/unified/ql/lib/codeql/unified/internal/dataflow/DataFlowPluginSwift.qll b/unified/ql/lib/codeql/unified/internal/dataflow/DataFlowPluginSwift.qll index 6cf9b5d487b8..ec03bf1536d3 100644 --- a/unified/ql/lib/codeql/unified/internal/dataflow/DataFlowPluginSwift.qll +++ b/unified/ql/lib/codeql/unified/internal/dataflow/DataFlowPluginSwift.qll @@ -9,7 +9,7 @@ private class SwiftDataFlowPlugin extends DataFlowPlugin { // Note: For now we assume all code is Swift, but in the future we must restrict these rules to Swift-files override predicate step(Node node1, Step step, Node node2) { exists(BinaryExpr expr | - expr.getOperator().getValue() = "+" and + expr.getOperator().getValue() = ["+", "+="] and node1.isResultValue([expr.getLeft(), expr.getRight()]) and step.taint() and node2.isResultValue(expr) diff --git a/unified/ql/lib/codeql/unified/internal/dataflow/LocalSsa.qll b/unified/ql/lib/codeql/unified/internal/dataflow/LocalSsa.qll index 6b4fe6c376c1..96c90fbb47ed 100644 --- a/unified/ql/lib/codeql/unified/internal/dataflow/LocalSsa.qll +++ b/unified/ql/lib/codeql/unified/internal/dataflow/LocalSsa.qll @@ -27,6 +27,9 @@ module LocalSsaInput implements InputSig { predicate variableRead(BasicBlock bb, int i, SourceVariable v, boolean certain) { certain = true and performsVariableAccess(_, v, TRead(), bb.getNode(i)) + or + certain = true and + performsVariableAccess(_, v, TPostUpdate(), bb.getNode(i)) } } @@ -58,6 +61,13 @@ module LocalSsaDataFlowInput implements DataFlowIntegrationInputSig { } predicate guardDirectlyControlsBlock(Guard guard, BasicBlock bb, GuardValue val) { none() } + + predicate postUpdateCfgNode(Expr read, BasicBlock bb, int i) { + exists(LocalVariable var, U::Expr expr | + read = TLocalVariableRefNode(expr, var, TRead()) and + performsVariableAccess(expr, var, TPostUpdate(), bb.getNode(i)) + ) + } } module LocalSsaDataFlowOutput = DataFlowIntegration; diff --git a/unified/ql/lib/unified.dbscheme b/unified/ql/lib/unified.dbscheme index cb0facfc1d0a..c5f144e8b661 100644 --- a/unified/ql/lib/unified.dbscheme +++ b/unified/ql/lib/unified.dbscheme @@ -194,12 +194,6 @@ unified_array_literal_def( unique int id: @unified_array_literal ); -unified_assign_expr_def( - unique int id: @unified_assign_expr, - int target: @unified_expr ref, - int value: @unified_expr ref -); - unified_associated_type_declaration_bound( unique int unified_associated_type_declaration: @unified_associated_type_declaration ref, unique int bound: @unified_expr ref @@ -360,13 +354,6 @@ unified_class_like_declaration_def( unique int id: @unified_class_like_declaration ); -unified_compound_assign_expr_def( - unique int id: @unified_compound_assign_expr, - int operator: @unified_token_infix_operator ref, - int target: @unified_expr ref, - int value: @unified_expr ref -); - #keyset[unified_conditional_pattern, index] unified_conditional_pattern_modifier( int unified_conditional_pattern: @unified_conditional_pattern ref, @@ -448,7 +435,7 @@ unified_equality_type_constraint_def( int right: @unified_expr ref ); -@unified_expr = @unified_array_literal | @unified_assign_expr | @unified_binary_expr | @unified_block | @unified_break_expr | @unified_bulk_importing_pattern | @unified_call_expr | @unified_compound_assign_expr | @unified_conditional_pattern | @unified_continue_expr | @unified_expr_pattern | @unified_function_expr | @unified_generic_type_expr | @unified_if_expr | @unified_key_value_pair | @unified_map_literal | @unified_member_access_expr | @unified_named_pattern | @unified_or_pattern | @unified_pattern_guard_expr | @unified_return_expr | @unified_string_interpolation_expr | @unified_switch_expr | @unified_throw_expr | @unified_token_boolean_literal | @unified_token_builtin_expr | @unified_token_empty_expr | @unified_token_float_literal | @unified_token_identifier | @unified_token_inferred_type_expr | @unified_token_int_literal | @unified_token_regex_literal | @unified_token_string_literal | @unified_token_super_expr | @unified_token_unsupported_node | @unified_try_expr | @unified_tuple_expr | @unified_type_cast_expr | @unified_type_test_expr | @unified_unary_expr | @unified_unresolved_operator_sequence +@unified_expr = @unified_array_literal | @unified_binary_expr | @unified_block | @unified_break_expr | @unified_bulk_importing_pattern | @unified_call_expr | @unified_conditional_pattern | @unified_continue_expr | @unified_expr_pattern | @unified_function_expr | @unified_generic_type_expr | @unified_if_expr | @unified_key_value_pair | @unified_map_literal | @unified_member_access_expr | @unified_named_pattern | @unified_or_pattern | @unified_pattern_guard_expr | @unified_return_expr | @unified_string_interpolation_expr | @unified_switch_expr | @unified_throw_expr | @unified_token_boolean_literal | @unified_token_builtin_expr | @unified_token_empty_expr | @unified_token_float_literal | @unified_token_identifier | @unified_token_inferred_type_expr | @unified_token_int_literal | @unified_token_regex_literal | @unified_token_string_literal | @unified_token_super_expr | @unified_token_unsupported_node | @unified_try_expr | @unified_tuple_expr | @unified_type_cast_expr | @unified_type_test_expr | @unified_unary_expr | @unified_unresolved_operator_sequence @unified_expr_or_operator = @unified_expr | @unified_token_infix_operator @@ -1012,7 +999,7 @@ unified_trivia_tokeninfo( string value: string ref ); -@unified_ast_node = @unified_accessor_declaration | @unified_argument | @unified_array_literal | @unified_assign_expr | @unified_associated_type_declaration | @unified_base_type | @unified_binary_expr | @unified_block | @unified_bound_type_constraint | @unified_break_expr | @unified_bulk_importing_pattern | @unified_call_expr | @unified_catch_clause | @unified_class_like_declaration | @unified_compound_assign_expr | @unified_conditional_pattern | @unified_constructor_declaration | @unified_continue_expr | @unified_destructor_declaration | @unified_do_while_stmt | @unified_equality_type_constraint | @unified_expr_pattern | @unified_for_each_stmt | @unified_function_declaration | @unified_function_expr | @unified_generic_type_expr | @unified_guard_if_stmt | @unified_if_expr | @unified_import_declaration | @unified_initializer_declaration | @unified_key_value_pair | @unified_labeled_stmt | @unified_map_literal | @unified_member_access_expr | @unified_named_pattern | @unified_operator_syntax_declaration | @unified_or_pattern | @unified_parameter | @unified_pattern_guard_expr | @unified_return_expr | @unified_string_interpolation_expr | @unified_switch_case | @unified_switch_expr | @unified_throw_expr | @unified_token | @unified_top_level | @unified_trivia_token | @unified_try_expr | @unified_tuple_expr | @unified_type_alias_declaration | @unified_type_cast_expr | @unified_type_parameter | @unified_type_test_expr | @unified_unary_expr | @unified_unresolved_operator_sequence | @unified_variable_declaration | @unified_while_stmt +@unified_ast_node = @unified_accessor_declaration | @unified_argument | @unified_array_literal | @unified_associated_type_declaration | @unified_base_type | @unified_binary_expr | @unified_block | @unified_bound_type_constraint | @unified_break_expr | @unified_bulk_importing_pattern | @unified_call_expr | @unified_catch_clause | @unified_class_like_declaration | @unified_conditional_pattern | @unified_constructor_declaration | @unified_continue_expr | @unified_destructor_declaration | @unified_do_while_stmt | @unified_equality_type_constraint | @unified_expr_pattern | @unified_for_each_stmt | @unified_function_declaration | @unified_function_expr | @unified_generic_type_expr | @unified_guard_if_stmt | @unified_if_expr | @unified_import_declaration | @unified_initializer_declaration | @unified_key_value_pair | @unified_labeled_stmt | @unified_map_literal | @unified_member_access_expr | @unified_named_pattern | @unified_operator_syntax_declaration | @unified_or_pattern | @unified_parameter | @unified_pattern_guard_expr | @unified_return_expr | @unified_string_interpolation_expr | @unified_switch_case | @unified_switch_expr | @unified_throw_expr | @unified_token | @unified_top_level | @unified_trivia_token | @unified_try_expr | @unified_tuple_expr | @unified_type_alias_declaration | @unified_type_cast_expr | @unified_type_parameter | @unified_type_test_expr | @unified_unary_expr | @unified_unresolved_operator_sequence | @unified_variable_declaration | @unified_while_stmt unified_ast_node_location( unique int node: @unified_ast_node ref, diff --git a/unified/ql/test/library-tests/controlflow/basicblock-slices.expected b/unified/ql/test/library-tests/controlflow/basicblock-slices.expected index c9d14ccd1af7..50824aa38bc2 100644 --- a/unified/ql/test/library-tests/controlflow/basicblock-slices.expected +++ b/unified/ql/test/library-tests/controlflow/basicblock-slices.expected @@ -72,10 +72,10 @@ | 84 | cfg.swift:84:3:84:15 | VariableDeclaration | 'VariableDeclaration -V temp -> 10' | | 86 | cfg.swift:86:3:88:3 | FunctionDeclaration | 'FunctionDeclaration' | | 86 | cfg.swift:86:12:86:12 | a | 'a -^ Block' | -| 87 | cfg.swift:87:5:87:5 | a | 'a -> a -> + -> 1 -^ BinaryExpr -^ AssignExpr' | +| 87 | cfg.swift:87:5:87:5 | a | 'a -> = -> a -> + -> 1 -^ BinaryExpr -^ BinaryExpr' | | 90 | cfg.swift:90:3:92:3 | FunctionDeclaration | 'FunctionDeclaration' | | 90 | cfg.swift:90:20:90:20 | a | 'a -^ Block' | -| 91 | cfg.swift:91:5:91:5 | a | 'a -> nil -^ AssignExpr' | +| 91 | cfg.swift:91:5:91:5 | a | 'a -> = -> nil -^ BinaryExpr' | | 94 | cfg.swift:94:3:94:5 | add | 'add -> Argument -V -^ CallExpr' | | 95 | cfg.swift:95:3:95:30 | VariableDeclaration | 'VariableDeclaration -V tempOptional -> Optional -V Int -^ GenericTypeExpr -> 10' | | 96 | cfg.swift:96:3:96:13 | addOptional | 'addOptional -> Argument -V -^ CallExpr' | @@ -84,7 +84,7 @@ | 101 | cfg.swift:101:3:101:16 | VariableDeclaration | 'VariableDeclaration -V myInt -> Int' | | 102 | cfg.swift:102:3:104:3 | ConstructorDeclaration | 'ConstructorDeclaration' | | 102 | cfg.swift:102:8:102:8 | n | 'n -^ Block' | -| 103 | cfg.swift:103:5:103:9 | myInt | 'myInt -> n -^ AssignExpr' | +| 103 | cfg.swift:103:5:103:9 | myInt | 'myInt -> = -> n -^ BinaryExpr' | | 106 | cfg.swift:106:3:108:3 | Block | 'Block' | | 106 | cfg.swift:106:3:108:3 | FunctionDeclaration | 'FunctionDeclaration' | | 107 | cfg.swift:107:12:107:16 | myInt | 'myInt -^ ReturnExpr' | @@ -155,10 +155,10 @@ | 207 | cfg.swift:207:9:207:9 | x | 'x -^ Block' | | 208 | cfg.swift:208:3:213:3 | IfExpr | 'IfExpr -V x -> < -> 0 -^ BinaryExpr' | | 208 | cfg.swift:208:12:213:3 | Block | 'Block' | -| 209 | cfg.swift:209:5:209:5 | x | 'x -> x -? - -^ UnaryExpr -^ AssignExpr' | +| 209 | cfg.swift:209:5:209:5 | x | 'x -> = -> x -? - -^ UnaryExpr -^ BinaryExpr' | | 210 | cfg.swift:210:5:212:5 | IfExpr | 'IfExpr -V x -> > -> 10 -^ BinaryExpr' | | 210 | cfg.swift:210:15:212:5 | Block | 'Block' | -| 211 | cfg.swift:211:7:211:7 | x | 'x -> x -> - -> 1 -^ BinaryExpr -^ AssignExpr' | +| 211 | cfg.swift:211:7:211:7 | x | 'x -> = -> x -> - -> 1 -^ BinaryExpr -^ BinaryExpr' | | 214 | cfg.swift:214:10:214:10 | x | 'x -^ ReturnExpr' | | 217 | cfg.swift:217:1:223:1 | FunctionDeclaration | 'FunctionDeclaration' | | 217 | cfg.swift:217:10:217:11 | b1 | 'b1 -> b2 -> b3 -^ Block' | @@ -217,30 +217,30 @@ | 279 | cfg.swift:279:1:310:1 | Block | 'Block' | | 279 | cfg.swift:279:1:310:1 | FunctionDeclaration | 'FunctionDeclaration' | | 280 | cfg.swift:280:3:280:44 | VariableDeclaration | 'VariableDeclaration -V a -> 0 -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> 10 -^ ArrayLiteral' | -| 281 | cfg.swift:281:3:281:3 | a | 'a -> Argument -V 0 -^ CallExpr -> 0 -^ AssignExpr' | -| 282 | cfg.swift:282:3:282:3 | a | 'a -> Argument -V 1 -^ CallExpr -> += -> 1 -^ CompoundAssignExpr' | -| 283 | cfg.swift:283:3:283:3 | a | 'a -> Argument -V 2 -^ CallExpr -> -= -> 1 -^ CompoundAssignExpr' | -| 284 | cfg.swift:284:3:284:3 | a | 'a -> Argument -V 3 -^ CallExpr -> *= -> 1 -^ CompoundAssignExpr' | -| 285 | cfg.swift:285:3:285:3 | a | 'a -> Argument -V 4 -^ CallExpr -> /= -> 1 -^ CompoundAssignExpr' | -| 286 | cfg.swift:286:3:286:3 | a | 'a -> Argument -V 5 -^ CallExpr -> %= -> 1 -^ CompoundAssignExpr' | -| 287 | cfg.swift:287:3:287:3 | a | 'a -> Argument -V 6 -^ CallExpr -> &= -> 1 -^ CompoundAssignExpr' | -| 288 | cfg.swift:288:3:288:3 | a | 'a -> Argument -V 7 -^ CallExpr -> \|= -> 1 -^ CompoundAssignExpr' | -| 289 | cfg.swift:289:3:289:3 | a | 'a -> Argument -V 8 -^ CallExpr -> ^= -> 1 -^ CompoundAssignExpr' | -| 290 | cfg.swift:290:3:290:3 | a | 'a -> Argument -V 9 -^ CallExpr -> <<= -> 1 -^ CompoundAssignExpr' | -| 291 | cfg.swift:291:3:291:3 | a | 'a -> Argument -V 10 -^ CallExpr -> >>= -> 1 -^ CompoundAssignExpr' | +| 281 | cfg.swift:281:3:281:3 | a | 'a -> Argument -V 0 -^ CallExpr -> = -> 0 -^ BinaryExpr' | +| 282 | cfg.swift:282:3:282:3 | a | 'a -> Argument -V 1 -^ CallExpr -> += -> 1 -^ BinaryExpr' | +| 283 | cfg.swift:283:3:283:3 | a | 'a -> Argument -V 2 -^ CallExpr -> -= -> 1 -^ BinaryExpr' | +| 284 | cfg.swift:284:3:284:3 | a | 'a -> Argument -V 3 -^ CallExpr -> *= -> 1 -^ BinaryExpr' | +| 285 | cfg.swift:285:3:285:3 | a | 'a -> Argument -V 4 -^ CallExpr -> /= -> 1 -^ BinaryExpr' | +| 286 | cfg.swift:286:3:286:3 | a | 'a -> Argument -V 5 -^ CallExpr -> %= -> 1 -^ BinaryExpr' | +| 287 | cfg.swift:287:3:287:3 | a | 'a -> Argument -V 6 -^ CallExpr -> &= -> 1 -^ BinaryExpr' | +| 288 | cfg.swift:288:3:288:3 | a | 'a -> Argument -V 7 -^ CallExpr -> \|= -> 1 -^ BinaryExpr' | +| 289 | cfg.swift:289:3:289:3 | a | 'a -> Argument -V 8 -^ CallExpr -> ^= -> 1 -^ BinaryExpr' | +| 290 | cfg.swift:290:3:290:3 | a | 'a -> Argument -V 9 -^ CallExpr -> <<= -> 1 -^ BinaryExpr' | +| 291 | cfg.swift:291:3:291:3 | a | 'a -> Argument -V 10 -^ CallExpr -> >>= -> 1 -^ BinaryExpr' | | 293 | cfg.swift:293:3:293:49 | VariableDeclaration | 'VariableDeclaration -V tupleWithA -> Argument -V a -> Argument -V 0 -^ CallExpr -> Argument -V a -> Argument -V 1 -^ CallExpr -> Argument -V a -> Argument -V 2 -^ CallExpr -> Argument -V a -> Argument -V 3 -^ CallExpr -> Argument -V a -> Argument -V 4 -^ CallExpr -^ TupleExpr' | | 295 | cfg.swift:295:3:295:48 | VariableDeclaration | 'VariableDeclaration -V b -> 0 -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> 10 -> 11 -^ ArrayLiteral' | -| 296 | cfg.swift:296:3:296:3 | b | 'b -> Argument -V 0 -^ CallExpr -> a -> Argument -V 10 -^ CallExpr -^ AssignExpr' | -| 297 | cfg.swift:297:3:297:3 | b | 'b -> Argument -V 1 -^ CallExpr -> b -> Argument -V 0 -^ CallExpr -> + -> 1 -^ BinaryExpr -^ AssignExpr' | -| 298 | cfg.swift:298:3:298:3 | b | 'b -> Argument -V 2 -^ CallExpr -> b -> Argument -V 1 -^ CallExpr -> - -> 1 -^ BinaryExpr -^ AssignExpr' | -| 299 | cfg.swift:299:3:299:3 | b | 'b -> Argument -V 3 -^ CallExpr -> b -> Argument -V 2 -^ CallExpr -> * -> 1 -^ BinaryExpr -^ AssignExpr' | -| 300 | cfg.swift:300:3:300:3 | b | 'b -> Argument -V 4 -^ CallExpr -> b -> Argument -V 3 -^ CallExpr -> / -> 1 -^ BinaryExpr -^ AssignExpr' | -| 301 | cfg.swift:301:3:301:3 | b | 'b -> Argument -V 5 -^ CallExpr -> b -> Argument -V 4 -^ CallExpr -> % -> 1 -^ BinaryExpr -^ AssignExpr' | -| 302 | cfg.swift:302:3:302:3 | b | 'b -> Argument -V 6 -^ CallExpr -> b -> Argument -V 5 -^ CallExpr -> & -> 1 -^ BinaryExpr -^ AssignExpr' | -| 303 | cfg.swift:303:3:303:3 | b | 'b -> Argument -V 7 -^ CallExpr -> b -> Argument -V 6 -^ CallExpr -> \| -> 1 -^ BinaryExpr -^ AssignExpr' | -| 304 | cfg.swift:304:3:304:3 | b | 'b -> Argument -V 8 -^ CallExpr -> b -> Argument -V 7 -^ CallExpr -> ^ -> 1 -^ BinaryExpr -^ AssignExpr' | -| 305 | cfg.swift:305:3:305:3 | b | 'b -> Argument -V 9 -^ CallExpr -> b -> Argument -V 8 -^ CallExpr -> << -> 1 -^ BinaryExpr -^ AssignExpr' | -| 306 | cfg.swift:306:3:306:3 | b | 'b -> Argument -V 10 -^ CallExpr -> b -> Argument -V 9 -^ CallExpr -> >> -> 1 -^ BinaryExpr -^ AssignExpr' | +| 296 | cfg.swift:296:3:296:3 | b | 'b -> Argument -V 0 -^ CallExpr -> = -> a -> Argument -V 10 -^ CallExpr -^ BinaryExpr' | +| 297 | cfg.swift:297:3:297:3 | b | 'b -> Argument -V 1 -^ CallExpr -> = -> b -> Argument -V 0 -^ CallExpr -> + -> 1 -^ BinaryExpr -^ BinaryExpr' | +| 298 | cfg.swift:298:3:298:3 | b | 'b -> Argument -V 2 -^ CallExpr -> = -> b -> Argument -V 1 -^ CallExpr -> - -> 1 -^ BinaryExpr -^ BinaryExpr' | +| 299 | cfg.swift:299:3:299:3 | b | 'b -> Argument -V 3 -^ CallExpr -> = -> b -> Argument -V 2 -^ CallExpr -> * -> 1 -^ BinaryExpr -^ BinaryExpr' | +| 300 | cfg.swift:300:3:300:3 | b | 'b -> Argument -V 4 -^ CallExpr -> = -> b -> Argument -V 3 -^ CallExpr -> / -> 1 -^ BinaryExpr -^ BinaryExpr' | +| 301 | cfg.swift:301:3:301:3 | b | 'b -> Argument -V 5 -^ CallExpr -> = -> b -> Argument -V 4 -^ CallExpr -> % -> 1 -^ BinaryExpr -^ BinaryExpr' | +| 302 | cfg.swift:302:3:302:3 | b | 'b -> Argument -V 6 -^ CallExpr -> = -> b -> Argument -V 5 -^ CallExpr -> & -> 1 -^ BinaryExpr -^ BinaryExpr' | +| 303 | cfg.swift:303:3:303:3 | b | 'b -> Argument -V 7 -^ CallExpr -> = -> b -> Argument -V 6 -^ CallExpr -> \| -> 1 -^ BinaryExpr -^ BinaryExpr' | +| 304 | cfg.swift:304:3:304:3 | b | 'b -> Argument -V 8 -^ CallExpr -> = -> b -> Argument -V 7 -^ CallExpr -> ^ -> 1 -^ BinaryExpr -^ BinaryExpr' | +| 305 | cfg.swift:305:3:305:3 | b | 'b -> Argument -V 9 -^ CallExpr -> = -> b -> Argument -V 8 -^ CallExpr -> << -> 1 -^ BinaryExpr -^ BinaryExpr' | +| 306 | cfg.swift:306:3:306:3 | b | 'b -> Argument -V 10 -^ CallExpr -> = -> b -> Argument -V 9 -^ CallExpr -> >> -> 1 -^ BinaryExpr -^ BinaryExpr' | | 308 | cfg.swift:308:3:308:39 | VariableDeclaration | 'VariableDeclaration -V Argument -V a1 -> Argument -V a2 -> Argument -V a3 -> Argument -V a4 -> Argument -V a5 -^ TupleExpr -> tupleWithA' | | 309 | cfg.swift:309:11:309:20 | Argument | 'Argument -V a1 -> + -> b -> Argument -V 0 -^ CallExpr -^ BinaryExpr -> Argument -V a2 -> + -> b -> Argument -V 1 -^ CallExpr -^ BinaryExpr -> Argument -V a3 -> + -> b -> Argument -V 2 -^ CallExpr -^ BinaryExpr -> Argument -V a4 -> + -> b -> Argument -V 3 -^ CallExpr -^ BinaryExpr -> Argument -V a5 -> + -> b -> Argument -V 4 -^ CallExpr -^ BinaryExpr -^ TupleExpr -^ ReturnExpr' | | 312 | cfg.swift:312:1:317:1 | FunctionDeclaration | 'FunctionDeclaration' | @@ -249,14 +249,14 @@ | 313 | cfg.swift:313:9:313:9 | x | 'x -> >= -> 0 -^ BinaryExpr' | | 313 | cfg.swift:313:16:316:3 | Block | 'Block' | | 314 | cfg.swift:314:5:314:9 | print | 'print -> Argument -V x -^ CallExpr' | -| 315 | cfg.swift:315:5:315:5 | x | 'x -> -= -> 1 -^ CompoundAssignExpr' | +| 315 | cfg.swift:315:5:315:5 | x | 'x -> -= -> 1 -^ BinaryExpr' | | 319 | cfg.swift:319:1:332:1 | FunctionDeclaration | 'FunctionDeclaration' | | 319 | cfg.swift:319:12:319:12 | x | 'x -^ Block' | | 320 | cfg.swift:320:3:330:3 | WhileStmt | 'WhileStmt' | | 320 | cfg.swift:320:9:320:9 | x | 'x -> >= -> 0 -^ BinaryExpr' | | 320 | cfg.swift:320:16:330:3 | Block | 'Block' | | 321 | cfg.swift:321:5:321:9 | print | 'print -> Argument -V x -^ CallExpr' | -| 322 | cfg.swift:322:5:322:5 | x | 'x -> -= -> 1 -^ CompoundAssignExpr' | +| 322 | cfg.swift:322:5:322:5 | x | 'x -> -= -> 1 -^ BinaryExpr' | | 323 | cfg.swift:323:5:328:5 | IfExpr | 'IfExpr -V x -> > -> 100 -^ BinaryExpr' | | 323 | cfg.swift:323:16:325:5 | Block | 'Block' | | 324 | cfg.swift:324:7:324:11 | BreakExpr | 'BreakExpr' | @@ -274,7 +274,7 @@ | 336 | cfg.swift:336:18:336:18 | x | 'x -> >= -> 0 -^ BinaryExpr' | | 336 | cfg.swift:336:25:346:5 | Block | 'Block' | | 337 | cfg.swift:337:7:337:11 | print | 'print -> Argument -V x -^ CallExpr' | -| 338 | cfg.swift:338:7:338:7 | x | 'x -> -= -> 1 -^ CompoundAssignExpr' | +| 338 | cfg.swift:338:7:338:7 | x | 'x -> -= -> 1 -^ BinaryExpr' | | 339 | cfg.swift:339:7:344:7 | IfExpr | 'IfExpr -V x -> > -> 100 -^ BinaryExpr' | | 339 | cfg.swift:339:18:341:7 | Block | 'Block' | | 340 | cfg.swift:340:9:340:19 | BreakExpr | 'BreakExpr' | @@ -288,7 +288,7 @@ | 352 | cfg.swift:352:3:355:16 | DoWhileStmt | 'DoWhileStmt' | | 352 | cfg.swift:352:10:355:3 | Block | 'Block' | | 353 | cfg.swift:353:5:353:9 | print | 'print -> Argument -V x -^ CallExpr' | -| 354 | cfg.swift:354:5:354:5 | x | 'x -> -= -> 1 -^ CompoundAssignExpr' | +| 354 | cfg.swift:354:5:354:5 | x | 'x -> -= -> 1 -^ BinaryExpr' | | 355 | cfg.swift:355:11:355:11 | x | 'x -> >= -> 0 -^ BinaryExpr' | | 358 | cfg.swift:358:1:363:1 | Block | 'Block' | | 358 | cfg.swift:358:1:363:1 | FunctionDeclaration | 'FunctionDeclaration' | @@ -296,12 +296,12 @@ | 360 | cfg.swift:360:3:362:3 | WhileStmt | 'WhileStmt' | | 360 | cfg.swift:360:9:360:9 | x | 'x -> < -> 10 -^ BinaryExpr' | | 360 | cfg.swift:360:17:362:3 | Block | 'Block' | -| 361 | cfg.swift:361:5:361:5 | x | 'x -> += -> 1 -^ CompoundAssignExpr' | +| 361 | cfg.swift:361:5:361:5 | x | 'x -> += -> 1 -^ BinaryExpr' | | 365 | cfg.swift:365:1:374:1 | ClassLikeDeclaration | 'ClassLikeDeclaration -V OptionalC' | | 366 | cfg.swift:366:3:366:11 | VariableDeclaration | 'VariableDeclaration -V c -> Optional -V C -^ GenericTypeExpr' | | 367 | cfg.swift:367:3:369:3 | ConstructorDeclaration | 'ConstructorDeclaration' | | 367 | cfg.swift:367:8:367:10 | arg | 'arg -^ Block' | -| 368 | cfg.swift:368:5:368:5 | c | 'c -> arg -^ AssignExpr' | +| 368 | cfg.swift:368:5:368:5 | c | 'c -> = -> arg -^ BinaryExpr' | | 371 | cfg.swift:371:3:373:3 | Block | 'Block' | | 371 | cfg.swift:371:3:373:3 | FunctionDeclaration | 'FunctionDeclaration' | | 372 | cfg.swift:372:12:372:12 | c | 'c -^ ReturnExpr' | @@ -333,10 +333,10 @@ | 407 | cfg.swift:407:3:407:16 | VariableDeclaration | 'VariableDeclaration -V field -> Int' | | 408 | cfg.swift:408:3:410:3 | Block | 'Block' | | 408 | cfg.swift:408:3:410:3 | ConstructorDeclaration | 'ConstructorDeclaration' | -| 409 | cfg.swift:409:5:409:9 | field | 'field -> 10 -^ AssignExpr' | +| 409 | cfg.swift:409:5:409:9 | field | 'field -> = -> 10 -^ BinaryExpr' | | 412 | cfg.swift:412:3:414:3 | Block | 'Block' | | 412 | cfg.swift:412:3:414:3 | DestructorDeclaration | 'DestructorDeclaration' | -| 413 | cfg.swift:413:5:413:9 | field | 'field -> 0 -^ AssignExpr' | +| 413 | cfg.swift:413:5:413:9 | field | 'field -> = -> 0 -^ BinaryExpr' | | 417 | cfg.swift:417:1:419:1 | FunctionDeclaration | 'FunctionDeclaration' | | 417 | cfg.swift:417:24:417:24 | x | 'x -> y -^ Block' | | 418 | cfg.swift:418:10:418:25 | MapLiteral | 'MapLiteral -^ ReturnExpr' | @@ -346,12 +346,12 @@ | 423 | cfg.swift:423:5:423:14 | VariableDeclaration | 'VariableDeclaration -V x -> Int' | | 424 | cfg.swift:424:5:426:5 | Block | 'Block' | | 424 | cfg.swift:424:5:426:5 | ConstructorDeclaration | 'ConstructorDeclaration' | -| 425 | cfg.swift:425:7:425:7 | x | 'x -> 10 -^ AssignExpr' | +| 425 | cfg.swift:425:7:425:7 | x | 'x -> = -> 10 -^ BinaryExpr' | | 429 | cfg.swift:429:3:434:3 | ClassLikeDeclaration | 'ClassLikeDeclaration -V MyLocalStruct' | | 430 | cfg.swift:430:5:430:14 | VariableDeclaration | 'VariableDeclaration -V x -> Int' | | 431 | cfg.swift:431:5:433:5 | Block | 'Block' | | 431 | cfg.swift:431:5:433:5 | ConstructorDeclaration | 'ConstructorDeclaration' | -| 432 | cfg.swift:432:7:432:7 | x | 'x -> 10 -^ AssignExpr' | +| 432 | cfg.swift:432:7:432:7 | x | 'x -> = -> 10 -^ BinaryExpr' | | 436 | cfg.swift:436:3:439:3 | ClassLikeDeclaration | 'ClassLikeDeclaration -V MyLocalEnum' | | 437 | cfg.swift:437:10:437:10 | VariableDeclaration | 'VariableDeclaration -V A' | | 438 | cfg.swift:438:10:438:10 | VariableDeclaration | 'VariableDeclaration -V B' | @@ -386,19 +386,19 @@ | 498 | cfg.swift:498:3:498:11 | VariableDeclaration | 'VariableDeclaration -V x -> 0' | | 500 | cfg.swift:500:3:502:3 | IfExpr | 'IfExpr -V ' | | 500 | cfg.swift:500:30:502:3 | Block | 'Block' | -| 501 | cfg.swift:501:5:501:5 | x | 'x -> += -> 1 -^ CompoundAssignExpr' | +| 501 | cfg.swift:501:5:501:5 | x | 'x -> += -> 1 -^ BinaryExpr' | | 504 | cfg.swift:504:3:506:3 | IfExpr | 'IfExpr -V ' | | 504 | cfg.swift:504:33:506:3 | Block | 'Block' | -| 505 | cfg.swift:505:5:505:5 | x | 'x -> += -> 1 -^ CompoundAssignExpr' | +| 505 | cfg.swift:505:5:505:5 | x | 'x -> += -> 1 -^ BinaryExpr' | | 508 | cfg.swift:508:3:510:3 | IfExpr | 'IfExpr -V ' | | 508 | cfg.swift:508:49:510:3 | Block | 'Block' | -| 509 | cfg.swift:509:5:509:5 | x | 'x -> += -> 1 -^ CompoundAssignExpr' | +| 509 | cfg.swift:509:5:509:5 | x | 'x -> += -> 1 -^ BinaryExpr' | | 512 | cfg.swift:512:3:514:3 | GuardIfStmt | 'GuardIfStmt -V -> Block' | -| 513 | cfg.swift:513:5:513:5 | x | 'x -> += -> 1 -^ CompoundAssignExpr' | +| 513 | cfg.swift:513:5:513:5 | x | 'x -> += -> 1 -^ BinaryExpr' | | 516 | cfg.swift:516:3:519:3 | IfExpr | 'IfExpr -V BinaryExpr -V ' | | 517 | cfg.swift:517:7:517:27 | | '' | | 517 | cfg.swift:517:29:519:3 | Block | 'Block' | -| 518 | cfg.swift:518:5:518:5 | x | 'x -> += -> 1 -^ CompoundAssignExpr' | +| 518 | cfg.swift:518:5:518:5 | x | 'x -> += -> 1 -^ BinaryExpr' | | 521 | cfg.swift:521:10:521:10 | x | 'x -^ ReturnExpr' | | 524 | cfg.swift:524:1:538:1 | Block | 'Block' | | 524 | cfg.swift:524:1:538:1 | FunctionDeclaration | 'FunctionDeclaration' | @@ -467,4 +467,4 @@ | 600 | cfg.swift:600:36:600:40 | value | 'value -^ Block' | | 601 | cfg.swift:601:5:601:13 | VariableDeclaration | 'VariableDeclaration -V x -> N' | | 602 | cfg.swift:602:5:602:9 | print | 'print -> Argument -V x -^ CallExpr' | -| 603 | cfg.swift:603:5:603:5 | _ | '_ -> value -^ AssignExpr' | +| 603 | cfg.swift:603:5:603:5 | _ | '_ -> = -> value -^ BinaryExpr' | diff --git a/unified/ql/test/library-tests/controlflow/cfg.expected b/unified/ql/test/library-tests/controlflow/cfg.expected index cf0b25228239..d5b76b70bd47 100644 --- a/unified/ql/test/library-tests/controlflow/cfg.expected +++ b/unified/ql/test/library-tests/controlflow/cfg.expected @@ -40,7 +40,7 @@ bbStep | cfg.swift:208:6:208:10 | BinaryExpr | 'BinaryExpr : true -> Block(+0)' | | cfg.swift:210:8:210:13 | BinaryExpr | 'BinaryExpr : false -> x(+4)' | | cfg.swift:210:8:210:13 | BinaryExpr | 'BinaryExpr : true -> Block(+0)' | -| cfg.swift:211:7:211:15 | AssignExpr | 'AssignExpr : successor -> x(+3)' | +| cfg.swift:211:7:211:15 | BinaryExpr | 'BinaryExpr : successor -> x(+3)' | | cfg.swift:218:11:218:12 | b1 | 'b1 : false -> b3(+2)' | | cfg.swift:218:11:218:12 | b1 | 'b1 : true -> b2(+1)' | | cfg.swift:219:13:219:14 | b2 | 'b2 : false,false -> "!b2 \|\| !b3"(+3)' | @@ -63,7 +63,7 @@ bbStep | cfg.swift:251:13:251:14 | b2 | 'b2 : true,true -> Block(+0)' | | cfg.swift:313:3:313:3 | WhileStmt | 'WhileStmt : successor -> x(+0)' | | cfg.swift:313:9:313:14 | BinaryExpr | 'BinaryExpr : true -> Block(+0)' | -| cfg.swift:315:5:315:10 | CompoundAssignExpr | 'CompoundAssignExpr : successor -> x(-2)' | +| cfg.swift:315:5:315:10 | BinaryExpr | 'BinaryExpr : successor -> x(-2)' | | cfg.swift:320:3:320:3 | WhileStmt | 'WhileStmt : successor -> x(+0)' | | cfg.swift:320:9:320:14 | BinaryExpr | 'BinaryExpr : false -> print(+11)' | | cfg.swift:320:9:320:14 | BinaryExpr | 'BinaryExpr : true -> Block(+0)' | @@ -90,22 +90,22 @@ bbStep | cfg.swift:355:11:355:16 | BinaryExpr | 'BinaryExpr : true -> Block(-3)' | | cfg.swift:360:3:360:3 | WhileStmt | 'WhileStmt : successor -> x(+0)' | | cfg.swift:360:9:360:14 | BinaryExpr | 'BinaryExpr : true -> Block(+0)' | -| cfg.swift:361:5:361:10 | CompoundAssignExpr | 'CompoundAssignExpr : successor -> x(-1)' | +| cfg.swift:361:5:361:10 | BinaryExpr | 'BinaryExpr : successor -> x(-1)' | | cfg.swift:398:9:398:24 | CallExpr | 'CallExpr : successor -> try(+0)' | | cfg.swift:500:6:500:28 | | ' : false -> IfExpr(+4)' | | cfg.swift:500:6:500:28 | | ' : true -> Block(+0)' | -| cfg.swift:501:5:501:10 | CompoundAssignExpr | 'CompoundAssignExpr : successor -> IfExpr(+3)' | +| cfg.swift:501:5:501:10 | BinaryExpr | 'BinaryExpr : successor -> IfExpr(+3)' | | cfg.swift:504:6:504:31 | | ' : false -> IfExpr(+4)' | | cfg.swift:504:6:504:31 | | ' : true -> Block(+0)' | -| cfg.swift:505:5:505:10 | CompoundAssignExpr | 'CompoundAssignExpr : successor -> IfExpr(+3)' | +| cfg.swift:505:5:505:10 | BinaryExpr | 'BinaryExpr : successor -> IfExpr(+3)' | | cfg.swift:508:6:508:47 | | ' : false -> GuardIfStmt(+4)' | | cfg.swift:508:6:508:47 | | ' : true -> Block(+0)' | -| cfg.swift:509:5:509:10 | CompoundAssignExpr | 'CompoundAssignExpr : successor -> GuardIfStmt(+3)' | +| cfg.swift:509:5:509:10 | BinaryExpr | 'BinaryExpr : successor -> GuardIfStmt(+3)' | | cfg.swift:516:6:516:28 | | ' : false,false -> x(+5)' | | cfg.swift:516:6:516:28 | | ' : true -> (+1)' | | cfg.swift:517:7:517:27 | | ' : false,false -> x(+4)' | | cfg.swift:517:7:517:27 | | ' : true -> Block(+0)' | -| cfg.swift:518:5:518:10 | CompoundAssignExpr | 'CompoundAssignExpr : successor -> x(+3)' | +| cfg.swift:518:5:518:10 | BinaryExpr | 'BinaryExpr : successor -> x(+3)' | | cfg.swift:528:26:528:32 | BinaryExpr | 'BinaryExpr : empty -> continuation(+3)' | | cfg.swift:528:26:528:32 | BinaryExpr | 'BinaryExpr : non-empty -> i(+0)' | | cfg.swift:529:21:529:41 | CallExpr | 'CallExpr : successor -> continuation(+2)' | @@ -158,7 +158,7 @@ noCfg nonSimple | cfg.swift:10:1:10:1 | ClassLikeDeclaration | 'ClassLikeDeclaration -V MyError -^ BaseType -V Error' | | cfg.swift:35:5:35:5 | CatchClause | 'CatchClause -V MyError -^ MemberAccessExpr -> isZero -> Argument -V x -^ CallExpr -? MyError -^ MemberAccessExpr -^ ConditionalPattern -^ OrPattern' | -| cfg.swift:209:5:209:5 | x | 'x -> x -? - -^ UnaryExpr -^ AssignExpr' | +| cfg.swift:209:5:209:5 | x | 'x -> = -> x -? - -^ UnaryExpr -^ BinaryExpr' | | cfg.swift:390:1:390:1 | ClassLikeDeclaration | 'ClassLikeDeclaration -V Derived -^ BaseType -V C' | | cfg.swift:527:13:527:16 | Task | 'Task -^ MemberAccessExpr -^ Argument -V FunctionExpr -^ CallExpr' | | cfg.swift:569:1:569:1 | ClassLikeDeclaration | 'ClassLikeDeclaration -V MyProcotolImpl -^ BaseType -V MyProtocol' | diff --git a/unified/ql/test/library-tests/controlflow/cfg.swift b/unified/ql/test/library-tests/controlflow/cfg.swift index e8bb40e33f8e..c7c96c1f1716 100644 --- a/unified/ql/test/library-tests/controlflow/cfg.swift +++ b/unified/ql/test/library-tests/controlflow/cfg.swift @@ -206,9 +206,9 @@ func m2(b : Bool) -> Int { func m3(x : inout Int) -> Int { if x < 0 { // $ bbStep='BinaryExpr : true -> Block(+0)' bbStep='BinaryExpr : false -> x(+6)' - x = -x // $ nonSimple='x -> x -? - -^ UnaryExpr -^ AssignExpr' + x = -x // $ nonSimple='x -> = -> x -? - -^ UnaryExpr -^ BinaryExpr' if x > 10 { // $ bbStep='BinaryExpr : true -> Block(+0)' bbStep='BinaryExpr : false -> x(+4)' - x = x - 1 // $ bbStep='AssignExpr : successor -> x(+3)' + x = x - 1 // $ bbStep='BinaryExpr : successor -> x(+3)' } } return x @@ -312,7 +312,7 @@ func testSubscriptExpr() -> (Int, Int, Int, Int, Int) { // $ noCfg func loop1(x : inout Int) { while x >= 0 { // $ bbStep='WhileStmt : successor -> x(+0)' bbStep='BinaryExpr : true -> Block(+0)' print(x) - x -= 1 // $ bbStep='CompoundAssignExpr : successor -> x(-2)' + x -= 1 // $ bbStep='BinaryExpr : successor -> x(-2)' } } @@ -358,7 +358,7 @@ func testRepeat(x : inout Int) { func loop_with_identity_expr() { // $ noCfg var x = 0 while(x < 10) { // $ bbStep='WhileStmt : successor -> x(+0)' bbStep='BinaryExpr : true -> Block(+0)' - x += 1 // $ bbStep='CompoundAssignExpr : successor -> x(-1)' + x += 1 // $ bbStep='BinaryExpr : successor -> x(-1)' } } @@ -498,15 +498,15 @@ func testAvailable() -> Int { // $ noCfg var x = 0; if #available(macOS 10, *) { // $ bbStep=' : false -> IfExpr(+4)' bbStep=' : true -> Block(+0)' - x += 1 // $ bbStep='CompoundAssignExpr : successor -> IfExpr(+3)' + x += 1 // $ bbStep='BinaryExpr : successor -> IfExpr(+3)' } if #available(macOS 10.13, *) { // $ bbStep=' : false -> IfExpr(+4)' bbStep=' : true -> Block(+0)' - x += 1 // $ bbStep='CompoundAssignExpr : successor -> IfExpr(+3)' + x += 1 // $ bbStep='BinaryExpr : successor -> IfExpr(+3)' } if #unavailable(iOS 10, watchOS 10, macOS 10) { // $ bbStep=' : false -> GuardIfStmt(+4)' bbStep=' : true -> Block(+0)' - x += 1 // $ bbStep='CompoundAssignExpr : successor -> GuardIfStmt(+3)' + x += 1 // $ bbStep='BinaryExpr : successor -> GuardIfStmt(+3)' } guard #available(macOS 12, *) else { @@ -515,7 +515,7 @@ func testAvailable() -> Int { // $ noCfg if #available(macOS 12, *), // $ bbStep=' : true -> (+1)' bbStep=' : false,false -> x(+5)' #available(iOS 12, *) { // $ bbStep=' : false,false -> x(+4)' bbStep=' : true -> Block(+0)' - x += 1 // $ bbStep='CompoundAssignExpr : successor -> x(+3)' + x += 1 // $ bbStep='BinaryExpr : successor -> x(+3)' } return x diff --git a/unified/ql/test/library-tests/dataflow/implicit-self.swift b/unified/ql/test/library-tests/dataflow/implicit-self.swift index 8e13479d51fe..32f8e88266f4 100644 --- a/unified/ql/test/library-tests/dataflow/implicit-self.swift +++ b/unified/ql/test/library-tests/dataflow/implicit-self.swift @@ -53,4 +53,32 @@ class C { self.box.x = source("t8.1"); sink(box.x); // $ hasValueFlow=t8.1 } + + func t9() { + x = "safe"; + x += sink(x) + source("t9.1"); + sink(x); // $ hasTaintFlow=t9.1 + sink(self.x); // $ hasTaintFlow=t9.1 + } + + func t10() { + x = "safe"; + self.x += sink(x) + source("t10.1"); + sink(x); // $ hasTaintFlow=t10.1 + sink(self.x); // $ hasTaintFlow=t10.1 + } + + func t11() { + self.x = "safe"; + x += sink(x) + source("t11.1"); + sink(x); // $ hasTaintFlow=t11.1 + sink(self.x); // $ hasTaintFlow=t11.1 + } + + func t12() { + self.x = "safe"; + self.x += sink(x) + source("t12.1"); + sink(x); // $ hasTaintFlow=t12.1 + sink(self.x); // $ hasTaintFlow=t12.1 + } } diff --git a/unified/ql/test/library-tests/dataflow/test.expected b/unified/ql/test/library-tests/dataflow/test.expected index f6df03922f1f..41ced3845de2 100644 --- a/unified/ql/test/library-tests/dataflow/test.expected +++ b/unified/ql/test/library-tests/dataflow/test.expected @@ -32,6 +32,24 @@ edges | implicit-self.swift:53:9:53:18 | MemberAccessExpr | implicit-self.swift:53:9:53:16 | [post] MemberAccessExpr [x] | provenance | | | implicit-self.swift:53:22:53:35 | CallExpr | implicit-self.swift:53:9:53:18 | MemberAccessExpr | provenance | | | implicit-self.swift:54:14:54:16 | box [x] | implicit-self.swift:54:14:54:18 | MemberAccessExpr | provenance | | +| implicit-self.swift:59:9:59:9 | [incoming] x | implicit-self.swift:60:14:60:14 | x | provenance | | +| implicit-self.swift:59:9:59:9 | [incoming] x | implicit-self.swift:61:14:61:17 | self [x] | provenance | | +| implicit-self.swift:59:24:59:37 | CallExpr | implicit-self.swift:59:9:59:9 | [incoming] x | provenance | | +| implicit-self.swift:61:14:61:17 | self [x] | implicit-self.swift:61:14:61:19 | MemberAccessExpr | provenance | | +| implicit-self.swift:66:9:66:12 | [post] self [x] | implicit-self.swift:67:14:67:14 | x | provenance | | +| implicit-self.swift:66:9:66:12 | [post] self [x] | implicit-self.swift:68:14:68:17 | self [x] | provenance | | +| implicit-self.swift:66:9:66:14 | [incoming] MemberAccessExpr | implicit-self.swift:66:9:66:12 | [post] self [x] | provenance | | +| implicit-self.swift:66:29:66:43 | CallExpr | implicit-self.swift:66:9:66:14 | [incoming] MemberAccessExpr | provenance | | +| implicit-self.swift:68:14:68:17 | self [x] | implicit-self.swift:68:14:68:19 | MemberAccessExpr | provenance | | +| implicit-self.swift:73:9:73:9 | [incoming] x | implicit-self.swift:74:14:74:14 | x | provenance | | +| implicit-self.swift:73:9:73:9 | [incoming] x | implicit-self.swift:75:14:75:17 | self [x] | provenance | | +| implicit-self.swift:73:24:73:38 | CallExpr | implicit-self.swift:73:9:73:9 | [incoming] x | provenance | | +| implicit-self.swift:75:14:75:17 | self [x] | implicit-self.swift:75:14:75:19 | MemberAccessExpr | provenance | | +| implicit-self.swift:80:9:80:12 | [post] self [x] | implicit-self.swift:81:14:81:14 | x | provenance | | +| implicit-self.swift:80:9:80:12 | [post] self [x] | implicit-self.swift:82:14:82:17 | self [x] | provenance | | +| implicit-self.swift:80:9:80:14 | [incoming] MemberAccessExpr | implicit-self.swift:80:9:80:12 | [post] self [x] | provenance | | +| implicit-self.swift:80:29:80:43 | CallExpr | implicit-self.swift:80:9:80:14 | [incoming] MemberAccessExpr | provenance | | +| implicit-self.swift:82:14:82:17 | self [x] | implicit-self.swift:82:14:82:19 | MemberAccessExpr | provenance | | | test.swift:6:10:6:23 | CallExpr | test.swift:6:10:6:32 | BinaryExpr | provenance | | | test.swift:7:19:7:32 | CallExpr | test.swift:7:10:7:32 | BinaryExpr | provenance | | | test.swift:9:13:9:26 | CallExpr | test.swift:9:10:9:33 | StringInterpolationExpr | provenance | | @@ -95,9 +113,33 @@ edges | test.swift:120:12:120:12 | b | test.swift:126:10:126:10 | b | provenance | | | test.swift:120:17:120:21 | tuple [0] | test.swift:120:9:120:13 | TupleExpr [0] | provenance | | | test.swift:120:17:120:21 | tuple [1] | test.swift:120:9:120:13 | TupleExpr [1] | provenance | | -| test.swift:131:5:131:5 | a | test.swift:131:14:131:14 | a | provenance | | | test.swift:131:5:131:5 | a | test.swift:132:10:132:10 | a | provenance | | | test.swift:131:19:131:33 | CallExpr | test.swift:131:5:131:5 | a | provenance | | +| test.swift:137:5:137:5 | [incoming] a | test.swift:138:10:138:10 | a | provenance | | +| test.swift:137:10:137:24 | CallExpr | test.swift:137:5:137:5 | [incoming] a | provenance | | +| test.swift:143:5:143:5 | [incoming] a | test.swift:144:10:144:10 | a | provenance | | +| test.swift:143:20:143:34 | CallExpr | test.swift:143:5:143:5 | [incoming] a | provenance | | +| test.swift:149:5:149:5 | [post] a [0] | test.swift:150:10:150:10 | a [0] | provenance | | +| test.swift:149:5:149:7 | MemberAccessExpr | test.swift:149:5:149:5 | [post] a [0] | provenance | | +| test.swift:149:23:149:37 | CallExpr | test.swift:149:5:149:7 | MemberAccessExpr | provenance | | +| test.swift:150:10:150:10 | a [0] | test.swift:150:10:150:12 | MemberAccessExpr | provenance | | +| test.swift:156:5:156:12 | TupleExpr [0] | test.swift:156:6:156:8 | MemberAccessExpr | provenance | | +| test.swift:156:6:156:6 | [post] a [0] | test.swift:157:10:157:10 | a [0] | provenance | | +| test.swift:156:6:156:8 | MemberAccessExpr | test.swift:156:6:156:6 | [post] a [0] | provenance | | +| test.swift:156:16:156:61 | TupleExpr [0] | test.swift:156:5:156:12 | TupleExpr [0] | provenance | | +| test.swift:156:17:156:43 | BinaryExpr | test.swift:156:16:156:61 | TupleExpr [0] | provenance | | +| test.swift:156:29:156:43 | CallExpr | test.swift:156:17:156:43 | BinaryExpr | provenance | | +| test.swift:157:10:157:10 | a [0] | test.swift:157:10:157:12 | MemberAccessExpr | provenance | | +| test.swift:164:5:164:10 | TupleExpr [0] | test.swift:164:6:164:6 | a | provenance | | +| test.swift:164:5:164:10 | TupleExpr [1] | test.swift:164:9:164:9 | b | provenance | | +| test.swift:164:6:164:6 | a | test.swift:165:10:165:10 | a | provenance | | +| test.swift:164:9:164:9 | b | test.swift:166:10:166:10 | b | provenance | | +| test.swift:164:14:164:67 | TupleExpr [0] | test.swift:164:5:164:10 | TupleExpr [0] | provenance | | +| test.swift:164:14:164:67 | TupleExpr [1] | test.swift:164:5:164:10 | TupleExpr [1] | provenance | | +| test.swift:164:15:164:39 | BinaryExpr | test.swift:164:14:164:67 | TupleExpr [0] | provenance | | +| test.swift:164:25:164:39 | CallExpr | test.swift:164:15:164:39 | BinaryExpr | provenance | | +| test.swift:164:42:164:66 | BinaryExpr | test.swift:164:14:164:67 | TupleExpr [1] | provenance | | +| test.swift:164:52:164:66 | CallExpr | test.swift:164:42:164:66 | BinaryExpr | provenance | | nodes | implicit-self.swift:11:9:11:12 | [post] self [x] | semmle.label | [post] self [x] | | implicit-self.swift:11:9:11:14 | MemberAccessExpr | semmle.label | MemberAccessExpr | @@ -139,6 +181,28 @@ nodes | implicit-self.swift:53:22:53:35 | CallExpr | semmle.label | CallExpr | | implicit-self.swift:54:14:54:16 | box [x] | semmle.label | box [x] | | implicit-self.swift:54:14:54:18 | MemberAccessExpr | semmle.label | MemberAccessExpr | +| implicit-self.swift:59:9:59:9 | [incoming] x | semmle.label | [incoming] x | +| implicit-self.swift:59:24:59:37 | CallExpr | semmle.label | CallExpr | +| implicit-self.swift:60:14:60:14 | x | semmle.label | x | +| implicit-self.swift:61:14:61:17 | self [x] | semmle.label | self [x] | +| implicit-self.swift:61:14:61:19 | MemberAccessExpr | semmle.label | MemberAccessExpr | +| implicit-self.swift:66:9:66:12 | [post] self [x] | semmle.label | [post] self [x] | +| implicit-self.swift:66:9:66:14 | [incoming] MemberAccessExpr | semmle.label | [incoming] MemberAccessExpr | +| implicit-self.swift:66:29:66:43 | CallExpr | semmle.label | CallExpr | +| implicit-self.swift:67:14:67:14 | x | semmle.label | x | +| implicit-self.swift:68:14:68:17 | self [x] | semmle.label | self [x] | +| implicit-self.swift:68:14:68:19 | MemberAccessExpr | semmle.label | MemberAccessExpr | +| implicit-self.swift:73:9:73:9 | [incoming] x | semmle.label | [incoming] x | +| implicit-self.swift:73:24:73:38 | CallExpr | semmle.label | CallExpr | +| implicit-self.swift:74:14:74:14 | x | semmle.label | x | +| implicit-self.swift:75:14:75:17 | self [x] | semmle.label | self [x] | +| implicit-self.swift:75:14:75:19 | MemberAccessExpr | semmle.label | MemberAccessExpr | +| implicit-self.swift:80:9:80:12 | [post] self [x] | semmle.label | [post] self [x] | +| implicit-self.swift:80:9:80:14 | [incoming] MemberAccessExpr | semmle.label | [incoming] MemberAccessExpr | +| implicit-self.swift:80:29:80:43 | CallExpr | semmle.label | CallExpr | +| implicit-self.swift:81:14:81:14 | x | semmle.label | x | +| implicit-self.swift:82:14:82:17 | self [x] | semmle.label | self [x] | +| implicit-self.swift:82:14:82:19 | MemberAccessExpr | semmle.label | MemberAccessExpr | | test.swift:2:10:2:21 | CallExpr | semmle.label | CallExpr | | test.swift:6:10:6:23 | CallExpr | semmle.label | CallExpr | | test.swift:6:10:6:32 | BinaryExpr | semmle.label | BinaryExpr | @@ -224,9 +288,39 @@ nodes | test.swift:125:10:125:10 | a | semmle.label | a | | test.swift:126:10:126:10 | b | semmle.label | b | | test.swift:131:5:131:5 | a | semmle.label | a | -| test.swift:131:14:131:14 | a | semmle.label | a | | test.swift:131:19:131:33 | CallExpr | semmle.label | CallExpr | | test.swift:132:10:132:10 | a | semmle.label | a | +| test.swift:137:5:137:5 | [incoming] a | semmle.label | [incoming] a | +| test.swift:137:10:137:24 | CallExpr | semmle.label | CallExpr | +| test.swift:138:10:138:10 | a | semmle.label | a | +| test.swift:143:5:143:5 | [incoming] a | semmle.label | [incoming] a | +| test.swift:143:20:143:34 | CallExpr | semmle.label | CallExpr | +| test.swift:144:10:144:10 | a | semmle.label | a | +| test.swift:149:5:149:5 | [post] a [0] | semmle.label | [post] a [0] | +| test.swift:149:5:149:7 | MemberAccessExpr | semmle.label | MemberAccessExpr | +| test.swift:149:23:149:37 | CallExpr | semmle.label | CallExpr | +| test.swift:150:10:150:10 | a [0] | semmle.label | a [0] | +| test.swift:150:10:150:12 | MemberAccessExpr | semmle.label | MemberAccessExpr | +| test.swift:156:5:156:12 | TupleExpr [0] | semmle.label | TupleExpr [0] | +| test.swift:156:6:156:6 | [post] a [0] | semmle.label | [post] a [0] | +| test.swift:156:6:156:8 | MemberAccessExpr | semmle.label | MemberAccessExpr | +| test.swift:156:16:156:61 | TupleExpr [0] | semmle.label | TupleExpr [0] | +| test.swift:156:17:156:43 | BinaryExpr | semmle.label | BinaryExpr | +| test.swift:156:29:156:43 | CallExpr | semmle.label | CallExpr | +| test.swift:157:10:157:10 | a [0] | semmle.label | a [0] | +| test.swift:157:10:157:12 | MemberAccessExpr | semmle.label | MemberAccessExpr | +| test.swift:164:5:164:10 | TupleExpr [0] | semmle.label | TupleExpr [0] | +| test.swift:164:5:164:10 | TupleExpr [1] | semmle.label | TupleExpr [1] | +| test.swift:164:6:164:6 | a | semmle.label | a | +| test.swift:164:9:164:9 | b | semmle.label | b | +| test.swift:164:14:164:67 | TupleExpr [0] | semmle.label | TupleExpr [0] | +| test.swift:164:14:164:67 | TupleExpr [1] | semmle.label | TupleExpr [1] | +| test.swift:164:15:164:39 | BinaryExpr | semmle.label | BinaryExpr | +| test.swift:164:25:164:39 | CallExpr | semmle.label | CallExpr | +| test.swift:164:42:164:66 | BinaryExpr | semmle.label | BinaryExpr | +| test.swift:164:52:164:66 | CallExpr | semmle.label | CallExpr | +| test.swift:165:10:165:10 | a | semmle.label | a | +| test.swift:166:10:166:10 | b | semmle.label | b | subpaths testFailures #select @@ -238,6 +332,14 @@ testFailures | implicit-self.swift:42:14:42:18 | MemberAccessExpr | implicit-self.swift:41:17:41:30 | CallExpr | implicit-self.swift:42:14:42:18 | MemberAccessExpr | $@ | implicit-self.swift:41:17:41:30 | CallExpr | CallExpr | | implicit-self.swift:48:14:48:23 | MemberAccessExpr | implicit-self.swift:47:17:47:30 | CallExpr | implicit-self.swift:48:14:48:23 | MemberAccessExpr | $@ | implicit-self.swift:47:17:47:30 | CallExpr | CallExpr | | implicit-self.swift:54:14:54:18 | MemberAccessExpr | implicit-self.swift:53:22:53:35 | CallExpr | implicit-self.swift:54:14:54:18 | MemberAccessExpr | $@ | implicit-self.swift:53:22:53:35 | CallExpr | CallExpr | +| implicit-self.swift:60:14:60:14 | x | implicit-self.swift:59:24:59:37 | CallExpr | implicit-self.swift:60:14:60:14 | x | $@ | implicit-self.swift:59:24:59:37 | CallExpr | CallExpr | +| implicit-self.swift:61:14:61:19 | MemberAccessExpr | implicit-self.swift:59:24:59:37 | CallExpr | implicit-self.swift:61:14:61:19 | MemberAccessExpr | $@ | implicit-self.swift:59:24:59:37 | CallExpr | CallExpr | +| implicit-self.swift:67:14:67:14 | x | implicit-self.swift:66:29:66:43 | CallExpr | implicit-self.swift:67:14:67:14 | x | $@ | implicit-self.swift:66:29:66:43 | CallExpr | CallExpr | +| implicit-self.swift:68:14:68:19 | MemberAccessExpr | implicit-self.swift:66:29:66:43 | CallExpr | implicit-self.swift:68:14:68:19 | MemberAccessExpr | $@ | implicit-self.swift:66:29:66:43 | CallExpr | CallExpr | +| implicit-self.swift:74:14:74:14 | x | implicit-self.swift:73:24:73:38 | CallExpr | implicit-self.swift:74:14:74:14 | x | $@ | implicit-self.swift:73:24:73:38 | CallExpr | CallExpr | +| implicit-self.swift:75:14:75:19 | MemberAccessExpr | implicit-self.swift:73:24:73:38 | CallExpr | implicit-self.swift:75:14:75:19 | MemberAccessExpr | $@ | implicit-self.swift:73:24:73:38 | CallExpr | CallExpr | +| implicit-self.swift:81:14:81:14 | x | implicit-self.swift:80:29:80:43 | CallExpr | implicit-self.swift:81:14:81:14 | x | $@ | implicit-self.swift:80:29:80:43 | CallExpr | CallExpr | +| implicit-self.swift:82:14:82:19 | MemberAccessExpr | implicit-self.swift:80:29:80:43 | CallExpr | implicit-self.swift:82:14:82:19 | MemberAccessExpr | $@ | implicit-self.swift:80:29:80:43 | CallExpr | CallExpr | | test.swift:2:10:2:21 | CallExpr | test.swift:2:10:2:21 | CallExpr | test.swift:2:10:2:21 | CallExpr | $@ | test.swift:2:10:2:21 | CallExpr | CallExpr | | test.swift:6:10:6:32 | BinaryExpr | test.swift:6:10:6:23 | CallExpr | test.swift:6:10:6:32 | BinaryExpr | $@ | test.swift:6:10:6:23 | CallExpr | CallExpr | | test.swift:7:10:7:32 | BinaryExpr | test.swift:7:19:7:32 | CallExpr | test.swift:7:10:7:32 | BinaryExpr | $@ | test.swift:7:19:7:32 | CallExpr | CallExpr | @@ -261,5 +363,10 @@ testFailures | test.swift:112:10:112:16 | MemberAccessExpr | test.swift:107:19:107:33 | CallExpr | test.swift:112:10:112:16 | MemberAccessExpr | $@ | test.swift:107:19:107:33 | CallExpr | CallExpr | | test.swift:125:10:125:10 | a | test.swift:117:18:117:33 | CallExpr | test.swift:125:10:125:10 | a | $@ | test.swift:117:18:117:33 | CallExpr | CallExpr | | test.swift:126:10:126:10 | b | test.swift:117:35:117:49 | CallExpr | test.swift:126:10:126:10 | b | $@ | test.swift:117:35:117:49 | CallExpr | CallExpr | -| test.swift:131:14:131:14 | a | test.swift:131:19:131:33 | CallExpr | test.swift:131:14:131:14 | a | $@ | test.swift:131:19:131:33 | CallExpr | CallExpr | | test.swift:132:10:132:10 | a | test.swift:131:19:131:33 | CallExpr | test.swift:132:10:132:10 | a | $@ | test.swift:131:19:131:33 | CallExpr | CallExpr | +| test.swift:138:10:138:10 | a | test.swift:137:10:137:24 | CallExpr | test.swift:138:10:138:10 | a | $@ | test.swift:137:10:137:24 | CallExpr | CallExpr | +| test.swift:144:10:144:10 | a | test.swift:143:20:143:34 | CallExpr | test.swift:144:10:144:10 | a | $@ | test.swift:143:20:143:34 | CallExpr | CallExpr | +| test.swift:150:10:150:12 | MemberAccessExpr | test.swift:149:23:149:37 | CallExpr | test.swift:150:10:150:12 | MemberAccessExpr | $@ | test.swift:149:23:149:37 | CallExpr | CallExpr | +| test.swift:157:10:157:12 | MemberAccessExpr | test.swift:156:29:156:43 | CallExpr | test.swift:157:10:157:12 | MemberAccessExpr | $@ | test.swift:156:29:156:43 | CallExpr | CallExpr | +| test.swift:165:10:165:10 | a | test.swift:164:25:164:39 | CallExpr | test.swift:165:10:165:10 | a | $@ | test.swift:164:25:164:39 | CallExpr | CallExpr | +| test.swift:166:10:166:10 | b | test.swift:164:52:164:66 | CallExpr | test.swift:166:10:166:10 | b | $@ | test.swift:164:52:164:66 | CallExpr | CallExpr | diff --git a/unified/ql/test/library-tests/dataflow/test.swift b/unified/ql/test/library-tests/dataflow/test.swift index 132afed56490..988bcfe03f52 100644 --- a/unified/ql/test/library-tests/dataflow/test.swift +++ b/unified/ql/test/library-tests/dataflow/test.swift @@ -128,18 +128,40 @@ func t13() { func t14() { var a = "safe"; - a = sink(a) + source("t14.1"); // $ SPURIOUS: hasTaintFlow=t14.1 + a = sink(a) + source("t14.1"); sink(a); // $ hasTaintFlow=t14.1 } func t15() { var a = "safe"; a += source("t15.1"); - sink(a); // $ MISSING: hasTaintFlow=t15.1 + sink(a); // $ hasTaintFlow=t15.1 } func t16() { var a = "safe"; a += sink(a) + source("t16.1"); - sink(a); // $ MISSING: hasTaintFlow=t16.1 + sink(a); // $ hasTaintFlow=t16.1 +} + +func t17() { + var a = ("safe", "safe"); + a.0 = sink(a.0) + source("t17.1"); + sink(a.0); // $ hasTaintFlow=t17.1 + sink(a.1); // no flow +} + +func t18() { + var a = ("safe", "safe"); + (a.0, _) = (sink(a.0) + source("t18.1"), source("t18.2")); + sink(a.0); // $ hasTaintFlow=t18.1 + sink(a.1); // no flow +} + +func t19() { + var a = "safe"; + var b = "safe"; + (a, b) = (sink(a) + source("t19.1"), sink(b) + source("t19.2")); + sink(a); // $ hasTaintFlow=t19.1 + sink(b); // $ hasTaintFlow=t19.2 }