From 901f389a7d54552786e6f66fe1af616f62378a9c Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Thu, 3 Jan 2019 14:53:16 +0100 Subject: [PATCH 01/33] C#: Add CFG tests for field/property initializers --- .../controlflow/graph/Dominance.expected | 8 ++++---- .../controlflow/graph/ElementGraph.expected | 4 ++-- .../controlflow/graph/EntryElement.expected | 11 +++++++++-- .../controlflow/graph/ExitElement.expected | 9 ++++++++- .../library-tests/controlflow/graph/Initializers.cs | 6 ++++-- .../controlflow/graph/NodeGraph.expected | 4 ++-- 6 files changed, 29 insertions(+), 13 deletions(-) diff --git a/csharp/ql/test/library-tests/controlflow/graph/Dominance.expected b/csharp/ql/test/library-tests/controlflow/graph/Dominance.expected index 71f86f41d72..09ed4977418 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/Dominance.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/Dominance.expected @@ -909,9 +909,9 @@ | post | Initializers.cs:10:40:10:40 | access to field F | Initializers.cs:10:17:10:53 | object creation of type Initializers | | post | Initializers.cs:10:40:10:44 | ... = ... | Initializers.cs:10:44:10:44 | 0 | | post | Initializers.cs:10:44:10:44 | 0 | Initializers.cs:10:40:10:40 | access to field F | -| post | Initializers.cs:10:47:10:47 | access to field G | Initializers.cs:10:40:10:44 | ... = ... | +| post | Initializers.cs:10:47:10:47 | access to property G | Initializers.cs:10:40:10:44 | ... = ... | | post | Initializers.cs:10:47:10:51 | ... = ... | Initializers.cs:10:51:10:51 | 1 | -| post | Initializers.cs:10:51:10:51 | 1 | Initializers.cs:10:47:10:47 | access to field G | +| post | Initializers.cs:10:51:10:51 | 1 | Initializers.cs:10:47:10:47 | access to property G | | post | Initializers.cs:11:9:11:64 | ... ...; | Initializers.cs:10:13:10:53 | Initializers i = ... | | post | Initializers.cs:11:13:11:14 | access to local variable iz | Initializers.cs:11:9:11:64 | ... ...; | | post | Initializers.cs:11:13:11:63 | Initializers[] iz = ... | Initializers.cs:11:37:11:63 | { ..., ... } | @@ -3152,9 +3152,9 @@ | pre | Initializers.cs:10:34:10:35 | "" | Initializers.cs:10:17:10:53 | object creation of type Initializers | | pre | Initializers.cs:10:38:10:53 | { ..., ... } | Initializers.cs:10:13:10:53 | Initializers i = ... | | pre | Initializers.cs:10:40:10:40 | access to field F | Initializers.cs:10:44:10:44 | 0 | -| pre | Initializers.cs:10:40:10:44 | ... = ... | Initializers.cs:10:47:10:47 | access to field G | +| pre | Initializers.cs:10:40:10:44 | ... = ... | Initializers.cs:10:47:10:47 | access to property G | | pre | Initializers.cs:10:44:10:44 | 0 | Initializers.cs:10:40:10:44 | ... = ... | -| pre | Initializers.cs:10:47:10:47 | access to field G | Initializers.cs:10:51:10:51 | 1 | +| pre | Initializers.cs:10:47:10:47 | access to property G | Initializers.cs:10:51:10:51 | 1 | | pre | Initializers.cs:10:47:10:51 | ... = ... | Initializers.cs:10:38:10:53 | { ..., ... } | | pre | Initializers.cs:10:51:10:51 | 1 | Initializers.cs:10:47:10:51 | ... = ... | | pre | Initializers.cs:11:9:11:64 | ... ...; | Initializers.cs:11:13:11:14 | access to local variable iz | diff --git a/csharp/ql/test/library-tests/controlflow/graph/ElementGraph.expected b/csharp/ql/test/library-tests/controlflow/graph/ElementGraph.expected index 39fc3e21505..a02cad96c81 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/ElementGraph.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/ElementGraph.expected @@ -693,9 +693,9 @@ | Initializers.cs:10:34:10:35 | "" | Initializers.cs:10:17:10:53 | object creation of type Initializers | semmle.label | successor | | Initializers.cs:10:38:10:53 | { ..., ... } | Initializers.cs:10:13:10:53 | Initializers i = ... | semmle.label | successor | | Initializers.cs:10:40:10:40 | access to field F | Initializers.cs:10:44:10:44 | 0 | semmle.label | successor | -| Initializers.cs:10:40:10:44 | ... = ... | Initializers.cs:10:47:10:47 | access to field G | semmle.label | successor | +| Initializers.cs:10:40:10:44 | ... = ... | Initializers.cs:10:47:10:47 | access to property G | semmle.label | successor | | Initializers.cs:10:44:10:44 | 0 | Initializers.cs:10:40:10:44 | ... = ... | semmle.label | successor | -| Initializers.cs:10:47:10:47 | access to field G | Initializers.cs:10:51:10:51 | 1 | semmle.label | successor | +| Initializers.cs:10:47:10:47 | access to property G | Initializers.cs:10:51:10:51 | 1 | semmle.label | successor | | Initializers.cs:10:47:10:51 | ... = ... | Initializers.cs:10:38:10:53 | { ..., ... } | semmle.label | successor | | Initializers.cs:10:51:10:51 | 1 | Initializers.cs:10:47:10:51 | ... = ... | semmle.label | successor | | Initializers.cs:11:9:11:64 | ... ...; | Initializers.cs:11:13:11:14 | access to local variable iz | semmle.label | successor | diff --git a/csharp/ql/test/library-tests/controlflow/graph/EntryElement.expected b/csharp/ql/test/library-tests/controlflow/graph/EntryElement.expected index 9604f48630b..fd9627fbe19 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/EntryElement.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/EntryElement.expected @@ -727,6 +727,12 @@ | Foreach.cs:38:33:38:33 | Int32 y | Foreach.cs:38:33:38:33 | Int32 y | | Foreach.cs:38:39:38:42 | access to parameter args | Foreach.cs:38:39:38:42 | access to parameter args | | Foreach.cs:39:11:39:11 | ; | Foreach.cs:39:11:39:11 | ; | +| Initializers.cs:3:13:3:13 | access to field H | Initializers.cs:3:13:3:13 | access to field H | +| Initializers.cs:3:13:3:17 | ... + ... | Initializers.cs:3:13:3:13 | access to field H | +| Initializers.cs:3:17:3:17 | 1 | Initializers.cs:3:17:3:17 | 1 | +| Initializers.cs:4:27:4:27 | access to field H | Initializers.cs:4:27:4:27 | access to field H | +| Initializers.cs:4:27:4:31 | ... + ... | Initializers.cs:4:27:4:27 | access to field H | +| Initializers.cs:4:31:4:31 | 2 | Initializers.cs:4:31:4:31 | 2 | | Initializers.cs:6:28:6:30 | {...} | Initializers.cs:6:28:6:30 | {...} | | Initializers.cs:9:5:12:5 | {...} | Initializers.cs:9:5:12:5 | {...} | | Initializers.cs:10:9:10:54 | ... ...; | Initializers.cs:10:9:10:54 | ... ...; | @@ -738,8 +744,8 @@ | Initializers.cs:10:40:10:40 | access to field F | Initializers.cs:10:40:10:40 | access to field F | | Initializers.cs:10:40:10:44 | ... = ... | Initializers.cs:10:40:10:40 | access to field F | | Initializers.cs:10:44:10:44 | 0 | Initializers.cs:10:44:10:44 | 0 | -| Initializers.cs:10:47:10:47 | access to field G | Initializers.cs:10:47:10:47 | access to field G | -| Initializers.cs:10:47:10:51 | ... = ... | Initializers.cs:10:47:10:47 | access to field G | +| Initializers.cs:10:47:10:47 | access to property G | Initializers.cs:10:47:10:47 | access to property G | +| Initializers.cs:10:47:10:51 | ... = ... | Initializers.cs:10:47:10:47 | access to property G | | Initializers.cs:10:51:10:51 | 1 | Initializers.cs:10:51:10:51 | 1 | | Initializers.cs:11:9:11:64 | ... ...; | Initializers.cs:11:9:11:64 | ... ...; | | Initializers.cs:11:13:11:14 | access to local variable iz | Initializers.cs:11:13:11:14 | access to local variable iz | @@ -750,6 +756,7 @@ | Initializers.cs:11:39:11:39 | access to local variable i | Initializers.cs:11:39:11:39 | access to local variable i | | Initializers.cs:11:42:11:61 | object creation of type Initializers | Initializers.cs:11:59:11:60 | "" | | Initializers.cs:11:59:11:60 | "" | Initializers.cs:11:59:11:60 | "" | +| Initializers.cs:14:20:14:20 | 1 | Initializers.cs:14:20:14:20 | 1 | | NullCoalescing.cs:3:23:3:23 | access to parameter i | NullCoalescing.cs:3:23:3:23 | access to parameter i | | NullCoalescing.cs:3:23:3:28 | ... ?? ... | NullCoalescing.cs:3:23:3:28 | ... ?? ... | | NullCoalescing.cs:3:28:3:28 | 0 | NullCoalescing.cs:3:28:3:28 | 0 | diff --git a/csharp/ql/test/library-tests/controlflow/graph/ExitElement.expected b/csharp/ql/test/library-tests/controlflow/graph/ExitElement.expected index b8dad69c8ee..38026741078 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/ExitElement.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/ExitElement.expected @@ -969,6 +969,12 @@ | Foreach.cs:38:33:38:33 | Int32 y | Foreach.cs:38:33:38:33 | Int32 y | normal | | Foreach.cs:38:39:38:42 | access to parameter args | Foreach.cs:38:39:38:42 | access to parameter args | normal | | Foreach.cs:39:11:39:11 | ; | Foreach.cs:39:11:39:11 | ; | normal | +| Initializers.cs:3:13:3:13 | access to field H | Initializers.cs:3:13:3:13 | access to field H | normal | +| Initializers.cs:3:13:3:17 | ... + ... | Initializers.cs:3:13:3:17 | ... + ... | normal | +| Initializers.cs:3:17:3:17 | 1 | Initializers.cs:3:17:3:17 | 1 | normal | +| Initializers.cs:4:27:4:27 | access to field H | Initializers.cs:4:27:4:27 | access to field H | normal | +| Initializers.cs:4:27:4:31 | ... + ... | Initializers.cs:4:27:4:31 | ... + ... | normal | +| Initializers.cs:4:31:4:31 | 2 | Initializers.cs:4:31:4:31 | 2 | normal | | Initializers.cs:6:28:6:30 | {...} | Initializers.cs:6:28:6:30 | {...} | normal | | Initializers.cs:9:5:12:5 | {...} | Initializers.cs:11:13:11:63 | Initializers[] iz = ... | normal | | Initializers.cs:10:9:10:54 | ... ...; | Initializers.cs:10:13:10:53 | Initializers i = ... | normal | @@ -980,7 +986,7 @@ | Initializers.cs:10:40:10:40 | access to field F | Initializers.cs:10:40:10:40 | access to field F | normal | | Initializers.cs:10:40:10:44 | ... = ... | Initializers.cs:10:40:10:44 | ... = ... | normal | | Initializers.cs:10:44:10:44 | 0 | Initializers.cs:10:44:10:44 | 0 | normal | -| Initializers.cs:10:47:10:47 | access to field G | Initializers.cs:10:47:10:47 | access to field G | normal | +| Initializers.cs:10:47:10:47 | access to property G | Initializers.cs:10:47:10:47 | access to property G | normal | | Initializers.cs:10:47:10:51 | ... = ... | Initializers.cs:10:47:10:51 | ... = ... | normal | | Initializers.cs:10:51:10:51 | 1 | Initializers.cs:10:51:10:51 | 1 | normal | | Initializers.cs:11:9:11:64 | ... ...; | Initializers.cs:11:13:11:63 | Initializers[] iz = ... | normal | @@ -992,6 +998,7 @@ | Initializers.cs:11:39:11:39 | access to local variable i | Initializers.cs:11:39:11:39 | access to local variable i | normal | | Initializers.cs:11:42:11:61 | object creation of type Initializers | Initializers.cs:11:42:11:61 | object creation of type Initializers | normal | | Initializers.cs:11:59:11:60 | "" | Initializers.cs:11:59:11:60 | "" | normal | +| Initializers.cs:14:20:14:20 | 1 | Initializers.cs:14:20:14:20 | 1 | normal | | NullCoalescing.cs:3:23:3:23 | access to parameter i | NullCoalescing.cs:3:23:3:23 | access to parameter i | non-null | | NullCoalescing.cs:3:23:3:23 | access to parameter i | NullCoalescing.cs:3:23:3:23 | access to parameter i | null | | NullCoalescing.cs:3:23:3:28 | ... ?? ... | NullCoalescing.cs:3:23:3:23 | access to parameter i | non-null | diff --git a/csharp/ql/test/library-tests/controlflow/graph/Initializers.cs b/csharp/ql/test/library-tests/controlflow/graph/Initializers.cs index 2c4a2f6e7ed..df1fe8422dd 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/Initializers.cs +++ b/csharp/ql/test/library-tests/controlflow/graph/Initializers.cs @@ -1,7 +1,7 @@ class Initializers { - int F; - int G; + int F = H + 1; + int G { get; set; } = H + 2; Initializers(string s) { } @@ -10,4 +10,6 @@ class Initializers var i = new Initializers("") { F = 0, G = 1 }; var iz = new Initializers[] { i, new Initializers("") }; } + + static int H = 1; } diff --git a/csharp/ql/test/library-tests/controlflow/graph/NodeGraph.expected b/csharp/ql/test/library-tests/controlflow/graph/NodeGraph.expected index f6f0a429797..bee7d6399fa 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/NodeGraph.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/NodeGraph.expected @@ -1045,9 +1045,9 @@ | Initializers.cs:10:34:10:35 | "" | Initializers.cs:10:17:10:53 | object creation of type Initializers | semmle.label | successor | | Initializers.cs:10:38:10:53 | { ..., ... } | Initializers.cs:10:13:10:53 | Initializers i = ... | semmle.label | successor | | Initializers.cs:10:40:10:40 | access to field F | Initializers.cs:10:44:10:44 | 0 | semmle.label | successor | -| Initializers.cs:10:40:10:44 | ... = ... | Initializers.cs:10:47:10:47 | access to field G | semmle.label | successor | +| Initializers.cs:10:40:10:44 | ... = ... | Initializers.cs:10:47:10:47 | access to property G | semmle.label | successor | | Initializers.cs:10:44:10:44 | 0 | Initializers.cs:10:40:10:44 | ... = ... | semmle.label | successor | -| Initializers.cs:10:47:10:47 | access to field G | Initializers.cs:10:51:10:51 | 1 | semmle.label | successor | +| Initializers.cs:10:47:10:47 | access to property G | Initializers.cs:10:51:10:51 | 1 | semmle.label | successor | | Initializers.cs:10:47:10:51 | ... = ... | Initializers.cs:10:38:10:53 | { ..., ... } | semmle.label | successor | | Initializers.cs:10:51:10:51 | 1 | Initializers.cs:10:47:10:51 | ... = ... | semmle.label | successor | | Initializers.cs:11:9:11:64 | ... ...; | Initializers.cs:11:13:11:14 | access to local variable iz | semmle.label | successor | From f323049b9da1352ccf35626b55a19aa452a1a0b9 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Thu, 3 Jan 2019 14:53:45 +0100 Subject: [PATCH 02/33] C#: CFG for expressions without enclosing callables, e.g. field initializers --- .../csharp/controlflow/ControlFlowGraph.qll | 21 ++++++++++++------- .../controlflow/graph/BasicBlock.expected | 2 ++ .../graph/BasicBlockDominance.expected | 4 ++++ .../controlflow/graph/Dominance.expected | 8 +++++++ .../controlflow/graph/ElementGraph.expected | 4 ++++ .../controlflow/graph/NodeGraph.expected | 4 ++++ 6 files changed, 36 insertions(+), 7 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowGraph.qll b/csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowGraph.qll index 64bdf961282..efb99dc6de8 100644 --- a/csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowGraph.qll +++ b/csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowGraph.qll @@ -867,6 +867,8 @@ module ControlFlow { * pre-order. */ private module Successor { + private import semmle.code.csharp.ExprOrStmtParent + /** * A control flow element where the children are evaluated following a * standard left-to-right evaluation. The actual evaluation order is @@ -2436,11 +2438,16 @@ module ControlFlow { * Gets the control flow element that is first executed when entering * callable `c`. */ - ControlFlowElement succEntry(Callable c) { - if exists(c.(Constructor).getInitializer()) then - result = first(c.(Constructor).getInitializer()) - else - result = first(c.getBody()) + ControlFlowElement succEntry(@top_level_exprorstmt_parent p) { + p = any(Callable c | + if exists(c.(Constructor).getInitializer()) then + result = first(c.(Constructor).getInitializer()) + else + result = first(c.getBody()) + ) + or + expr_parent_top_level_adjusted(any(Expr e | result = first(e)), _, p) and + not p instanceof Callable } /** @@ -3807,8 +3814,8 @@ module ControlFlow { * Holds if `succ` with splits `succSplits` is the first element that is executed * when entering callable `pred`. */ - pragma [noinline] - predicate succEntrySplits(Callable pred, ControlFlowElement succ, Splits succSplits, SuccessorType t) { + pragma[noinline] + predicate succEntrySplits(@top_level_exprorstmt_parent pred, ControlFlowElement succ, Splits succSplits, SuccessorType t) { succ = succEntry(pred) and t instanceof NormalSuccessor and succSplits = TSplitsNil() // initially no splits diff --git a/csharp/ql/test/library-tests/controlflow/graph/BasicBlock.expected b/csharp/ql/test/library-tests/controlflow/graph/BasicBlock.expected index 17d861787dc..ee01db7f6ed 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/BasicBlock.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/BasicBlock.expected @@ -243,6 +243,8 @@ | Foreach.cs:36:10:36:11 | exit M6 | Foreach.cs:36:10:36:11 | exit M6 | 1 | | Foreach.cs:38:9:39:11 | foreach (... ... in ...) ... | Foreach.cs:38:9:39:11 | foreach (... ... in ...) ... | 1 | | Foreach.cs:38:26:38:26 | String x | Foreach.cs:39:11:39:11 | ; | 4 | +| Initializers.cs:3:13:3:13 | access to field H | Initializers.cs:3:13:3:17 | ... + ... | 3 | +| Initializers.cs:4:27:4:27 | access to field H | Initializers.cs:4:27:4:31 | ... + ... | 3 | | Initializers.cs:6:5:6:16 | enter Initializers | Initializers.cs:6:5:6:16 | exit Initializers | 3 | | Initializers.cs:8:10:8:10 | enter M | Initializers.cs:8:10:8:10 | exit M | 23 | | NullCoalescing.cs:3:9:3:10 | enter M1 | NullCoalescing.cs:3:23:3:23 | access to parameter i | 3 | diff --git a/csharp/ql/test/library-tests/controlflow/graph/BasicBlockDominance.expected b/csharp/ql/test/library-tests/controlflow/graph/BasicBlockDominance.expected index bc617e1527e..da29acbeb4b 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/BasicBlockDominance.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/BasicBlockDominance.expected @@ -504,6 +504,8 @@ | post | Foreach.cs:38:9:39:11 | foreach (... ... in ...) ... | Foreach.cs:38:9:39:11 | foreach (... ... in ...) ... | | post | Foreach.cs:38:9:39:11 | foreach (... ... in ...) ... | Foreach.cs:38:26:38:26 | String x | | post | Foreach.cs:38:26:38:26 | String x | Foreach.cs:38:26:38:26 | String x | +| post | Initializers.cs:3:13:3:13 | access to field H | Initializers.cs:3:13:3:13 | access to field H | +| post | Initializers.cs:4:27:4:27 | access to field H | Initializers.cs:4:27:4:27 | access to field H | | post | Initializers.cs:6:5:6:16 | enter Initializers | Initializers.cs:6:5:6:16 | enter Initializers | | post | Initializers.cs:8:10:8:10 | enter M | Initializers.cs:8:10:8:10 | enter M | | post | NullCoalescing.cs:3:9:3:10 | enter M1 | NullCoalescing.cs:3:9:3:10 | enter M1 | @@ -1910,6 +1912,8 @@ | pre | Foreach.cs:38:9:39:11 | foreach (... ... in ...) ... | Foreach.cs:38:9:39:11 | foreach (... ... in ...) ... | | pre | Foreach.cs:38:9:39:11 | foreach (... ... in ...) ... | Foreach.cs:38:26:38:26 | String x | | pre | Foreach.cs:38:26:38:26 | String x | Foreach.cs:38:26:38:26 | String x | +| pre | Initializers.cs:3:13:3:13 | access to field H | Initializers.cs:3:13:3:13 | access to field H | +| pre | Initializers.cs:4:27:4:27 | access to field H | Initializers.cs:4:27:4:27 | access to field H | | pre | Initializers.cs:6:5:6:16 | enter Initializers | Initializers.cs:6:5:6:16 | enter Initializers | | pre | Initializers.cs:8:10:8:10 | enter M | Initializers.cs:8:10:8:10 | enter M | | pre | NullCoalescing.cs:3:9:3:10 | enter M1 | NullCoalescing.cs:3:9:3:10 | enter M1 | diff --git a/csharp/ql/test/library-tests/controlflow/graph/Dominance.expected b/csharp/ql/test/library-tests/controlflow/graph/Dominance.expected index 09ed4977418..ab282094823 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/Dominance.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/Dominance.expected @@ -896,6 +896,10 @@ | post | Foreach.cs:38:33:38:33 | Int32 y | Foreach.cs:38:26:38:26 | String x | | post | Foreach.cs:38:39:38:42 | access to parameter args | Foreach.cs:37:5:40:5 | {...} | | post | Foreach.cs:39:11:39:11 | ; | Foreach.cs:38:18:38:34 | (..., ...) | +| post | Initializers.cs:3:13:3:17 | ... + ... | Initializers.cs:3:17:3:17 | 1 | +| post | Initializers.cs:3:17:3:17 | 1 | Initializers.cs:3:13:3:13 | access to field H | +| post | Initializers.cs:4:27:4:31 | ... + ... | Initializers.cs:4:31:4:31 | 2 | +| post | Initializers.cs:4:31:4:31 | 2 | Initializers.cs:4:27:4:27 | access to field H | | post | Initializers.cs:6:5:6:16 | exit Initializers | Initializers.cs:6:28:6:30 | {...} | | post | Initializers.cs:6:28:6:30 | {...} | Initializers.cs:6:5:6:16 | enter Initializers | | post | Initializers.cs:8:10:8:10 | exit M | Initializers.cs:11:13:11:63 | Initializers[] iz = ... | @@ -3141,6 +3145,10 @@ | pre | Foreach.cs:38:26:38:26 | String x | Foreach.cs:38:33:38:33 | Int32 y | | pre | Foreach.cs:38:33:38:33 | Int32 y | Foreach.cs:38:18:38:34 | (..., ...) | | pre | Foreach.cs:38:39:38:42 | access to parameter args | Foreach.cs:38:9:39:11 | foreach (... ... in ...) ... | +| pre | Initializers.cs:3:13:3:13 | access to field H | Initializers.cs:3:17:3:17 | 1 | +| pre | Initializers.cs:3:17:3:17 | 1 | Initializers.cs:3:13:3:17 | ... + ... | +| pre | Initializers.cs:4:27:4:27 | access to field H | Initializers.cs:4:31:4:31 | 2 | +| pre | Initializers.cs:4:31:4:31 | 2 | Initializers.cs:4:27:4:31 | ... + ... | | pre | Initializers.cs:6:5:6:16 | enter Initializers | Initializers.cs:6:28:6:30 | {...} | | pre | Initializers.cs:6:28:6:30 | {...} | Initializers.cs:6:5:6:16 | exit Initializers | | pre | Initializers.cs:8:10:8:10 | enter M | Initializers.cs:9:5:12:5 | {...} | diff --git a/csharp/ql/test/library-tests/controlflow/graph/ElementGraph.expected b/csharp/ql/test/library-tests/controlflow/graph/ElementGraph.expected index a02cad96c81..2574f01b6f8 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/ElementGraph.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/ElementGraph.expected @@ -685,6 +685,10 @@ | Foreach.cs:38:33:38:33 | Int32 y | Foreach.cs:38:18:38:34 | (..., ...) | semmle.label | successor | | Foreach.cs:38:39:38:42 | access to parameter args | Foreach.cs:38:9:39:11 | foreach (... ... in ...) ... | semmle.label | successor | | Foreach.cs:39:11:39:11 | ; | Foreach.cs:38:9:39:11 | foreach (... ... in ...) ... | semmle.label | successor | +| Initializers.cs:3:13:3:13 | access to field H | Initializers.cs:3:17:3:17 | 1 | semmle.label | successor | +| Initializers.cs:3:17:3:17 | 1 | Initializers.cs:3:13:3:17 | ... + ... | semmle.label | successor | +| Initializers.cs:4:27:4:27 | access to field H | Initializers.cs:4:31:4:31 | 2 | semmle.label | successor | +| Initializers.cs:4:31:4:31 | 2 | Initializers.cs:4:27:4:31 | ... + ... | semmle.label | successor | | Initializers.cs:9:5:12:5 | {...} | Initializers.cs:10:9:10:54 | ... ...; | semmle.label | successor | | Initializers.cs:10:9:10:54 | ... ...; | Initializers.cs:10:13:10:13 | access to local variable i | semmle.label | successor | | Initializers.cs:10:13:10:13 | access to local variable i | Initializers.cs:10:34:10:35 | "" | semmle.label | successor | diff --git a/csharp/ql/test/library-tests/controlflow/graph/NodeGraph.expected b/csharp/ql/test/library-tests/controlflow/graph/NodeGraph.expected index bee7d6399fa..01d5a0df970 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/NodeGraph.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/NodeGraph.expected @@ -1034,6 +1034,10 @@ | Foreach.cs:38:33:38:33 | Int32 y | Foreach.cs:38:18:38:34 | (..., ...) | semmle.label | successor | | Foreach.cs:38:39:38:42 | access to parameter args | Foreach.cs:38:9:39:11 | foreach (... ... in ...) ... | semmle.label | successor | | Foreach.cs:39:11:39:11 | ; | Foreach.cs:38:9:39:11 | foreach (... ... in ...) ... | semmle.label | successor | +| Initializers.cs:3:13:3:13 | access to field H | Initializers.cs:3:17:3:17 | 1 | semmle.label | successor | +| Initializers.cs:3:17:3:17 | 1 | Initializers.cs:3:13:3:17 | ... + ... | semmle.label | successor | +| Initializers.cs:4:27:4:27 | access to field H | Initializers.cs:4:31:4:31 | 2 | semmle.label | successor | +| Initializers.cs:4:31:4:31 | 2 | Initializers.cs:4:27:4:31 | ... + ... | semmle.label | successor | | Initializers.cs:6:5:6:16 | enter Initializers | Initializers.cs:6:28:6:30 | {...} | semmle.label | successor | | Initializers.cs:6:28:6:30 | {...} | Initializers.cs:6:5:6:16 | exit Initializers | semmle.label | successor | | Initializers.cs:8:10:8:10 | enter M | Initializers.cs:9:5:12:5 | {...} | semmle.label | successor | From abb3f71ec8ddce41365949bd90255dce1cdc6e6c Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Fri, 21 Dec 2018 12:06:44 +0100 Subject: [PATCH 03/33] C#: Add `GuardedControlFlowNode` --- .../semmle/code/csharp/controlflow/Guards.qll | 111 +++++- .../guards/GuardedControlFlowNode.expected | 232 ++++++++++++ .../guards/GuardedControlFlowNode.ql | 5 + .../dataflow/ssa/SsaDefElement.expected | 340 ++++++++++++++++++ .../dataflow/ssa/SsaDefElement.ql | 4 + 5 files changed, 675 insertions(+), 17 deletions(-) create mode 100644 csharp/ql/test/library-tests/controlflow/guards/GuardedControlFlowNode.expected create mode 100644 csharp/ql/test/library-tests/controlflow/guards/GuardedControlFlowNode.ql create mode 100644 csharp/ql/test/library-tests/dataflow/ssa/SsaDefElement.expected create mode 100644 csharp/ql/test/library-tests/dataflow/ssa/SsaDefElement.ql diff --git a/csharp/ql/src/semmle/code/csharp/controlflow/Guards.qll b/csharp/ql/src/semmle/code/csharp/controlflow/Guards.qll index a1c112c8057..34e8889e099 100644 --- a/csharp/ql/src/semmle/code/csharp/controlflow/Guards.qll +++ b/csharp/ql/src/semmle/code/csharp/controlflow/Guards.qll @@ -417,7 +417,9 @@ class AccessOrCallExpr extends Expr { * An expression can have more than one SSA qualifier in the presence * of control flow splitting. */ - Ssa::Definition getAnSsaQualifier() { result = getAnSsaQualifier(this) } + Ssa::Definition getAnSsaQualifier(ControlFlow::Node cfn) { + result = getAnSsaQualifier(this, cfn) + } } private Declaration getDeclarationTarget(Expr e) { @@ -425,18 +427,20 @@ private Declaration getDeclarationTarget(Expr e) { result = e.(Call).getTarget() } -private Ssa::Definition getAnSsaQualifier(Expr e) { - e = getATrackedAccess(result) +private Ssa::Definition getAnSsaQualifier(Expr e, ControlFlow::Node cfn) { + e = getATrackedAccess(result, cfn) or - not e = getATrackedAccess(_) and - result = getAnSsaQualifier(e.(QualifiableExpr).getQualifier()) + not e = getATrackedAccess(_, _) and + result = getAnSsaQualifier(e.(QualifiableExpr).getQualifier(), cfn) } -private AssignableAccess getATrackedAccess(Ssa::Definition def) { +private AssignableAccess getATrackedAccess(Ssa::Definition def, ControlFlow::Node cfn) { ( - result = def.getARead() + result = def.getAReadAtNode(cfn) or - result = def.(Ssa::ExplicitDefinition).getADefinition().getTargetAccess() + result = def.(Ssa::ExplicitDefinition).getADefinition().getTargetAccess() and + result.getAControlFlowNode() = cfn and + cfn.getBasicBlock() = def.getBasicBlock() ) and not def instanceof Ssa::ImplicitUntrackedDefinition } @@ -483,7 +487,7 @@ class GuardedExpr extends AccessOrCallExpr { private AccessOrCallExpr sub0; private AbstractValue v0; - GuardedExpr() { isGuardedBy(this, g, sub0, v0) } + GuardedExpr() { isGuardedByExpr(this, g, sub0, v0) } /** * Gets an expression that guards this expression. That is, this expression is @@ -525,6 +529,58 @@ class GuardedExpr extends AccessOrCallExpr { } } +/** + * A guarded control flow node. A guarded control flow node is like a guarded + * expression (`GuardedExpr`), except control flow graph splitting is taken + * into account. That is, one control flow node belonging to an expression may + * be guarded, while another split need not be guarded: + * + * ``` + * if (b) + * if (x == null) + * return; + * x.ToString(); + * if (b) + * ... + * ``` + * + * In the example above, the node for `x.ToString()` is null-guarded in the + * split `b == true`, but not in the split `b == false`. + */ +class GuardedControlFlowNode extends ControlFlow::Nodes::ElementNode { + private Guard g; + private AccessOrCallExpr sub0; + private AbstractValue v0; + + GuardedControlFlowNode() { isGuardedByNode(this, g, sub0, v0) } + + /** + * Gets an expression that guards this control flow node. That is, this control + * flow node is only reached when the returned expression has abstract value `v`. + * + * The expression `sub` is a sub expression of the guarding expression that is + * structurally equal to the expression belonging to this control flow node. + * + * In case this control flow node or `sub` accesses an SSA variable in its + * left-most qualifier, then so must the other (accessing the same SSA + * variable). + */ + Expr getAGuard(Expr sub, AbstractValue v) { + result = g and + sub = sub0 and + v = v0 + } + + /** + * Holds if this control flow node must have abstract value `v`. That is, this + * control flow node is guarded by a structurally equal expression having + * abstract value `v`. + */ + predicate mustHaveValue(AbstractValue v) { + exists(Expr e | e = this.getAGuard(e, v)) + } +} + /** An expression guarded by a `null` check. */ class NullGuardedExpr extends GuardedExpr { NullGuardedExpr() { @@ -653,7 +709,7 @@ module Internal { * Holds if control flow node `cfn` only is reached when this guard evaluates to `v`, * because of an assertion. */ - private predicate assertionControlsNode(ControlFlow::Node cfn, AbstractValue v) { + predicate assertionControlsNode(ControlFlow::Node cfn, AbstractValue v) { exists(Assertion a, Guard g, AbstractValue v0 | asserts(a, g, v0) and impliesSteps(g, v0, this, v) @@ -1097,17 +1153,17 @@ module Internal { private cached module Cached { pragma[noinline] - private predicate isGuardedBy0(ControlFlow::Node cfn, AccessOrCallExpr guarded, Guard g, AccessOrCallExpr sub, AbstractValue v) { + private predicate isGuardedByNode0(ControlFlow::Node cfn, AccessOrCallExpr guarded, Guard g, AccessOrCallExpr sub, AbstractValue v) { cfn = guarded.getAControlFlowNode() and g.controls(cfn.getBasicBlock(), v) and exists(ConditionOnExprComparisonConfig c | c.same(sub, guarded)) } pragma[noinline] - private predicate isGuardedBy1(AccessOrCallExpr guarded, Guard g, AccessOrCallExpr sub, AbstractValue v) { + private predicate isGuardedByExpr1(AccessOrCallExpr guarded, Guard g, AccessOrCallExpr sub, AbstractValue v) { forex(ControlFlow::Node cfn | cfn = guarded.getAControlFlowNode() | - isGuardedBy0(cfn, guarded, g, sub, v) + isGuardedByNode0(cfn, guarded, g, sub, v) ) or g.assertionControlsElement(guarded, v) and @@ -1115,12 +1171,33 @@ module Internal { } cached - predicate isGuardedBy(AccessOrCallExpr guarded, Guard g, AccessOrCallExpr sub, AbstractValue v) { - isGuardedBy1(guarded, g, sub, v) and + predicate isGuardedByExpr(AccessOrCallExpr guarded, Guard g, AccessOrCallExpr sub, AbstractValue v) { + isGuardedByExpr1(guarded, g, sub, v) and sub = g.getAChildExpr*() and forall(Ssa::Definition def | - def = sub.getAnSsaQualifier() | - def = guarded.getAnSsaQualifier() + def = sub.getAnSsaQualifier(_) | + def = guarded.getAnSsaQualifier(_) + ) + } + + pragma[noinline] + private predicate isGuardedByNode1(ControlFlow::Nodes::ElementNode guarded, Guard g, AccessOrCallExpr sub, AbstractValue v) { + isGuardedByNode0(guarded, _, g, sub, v) + or + g.assertionControlsNode(guarded, v) and + exists(ConditionOnExprComparisonConfig c | c.same(sub, guarded.getElement())) + } + + cached + predicate isGuardedByNode(ControlFlow::Nodes::ElementNode guarded, Guard g, AccessOrCallExpr sub, AbstractValue v) { + isGuardedByNode1(guarded, g, sub, v) and + sub = g.getAChildExpr*() and + forall(Ssa::Definition def | + def = sub.getAnSsaQualifier(_) | + exists(ControlFlow::Node cfn | + def = guarded.getElement().(AccessOrCallExpr).getAnSsaQualifier(cfn) | + cfn.getBasicBlock() = guarded.getBasicBlock() + ) ) } diff --git a/csharp/ql/test/library-tests/controlflow/guards/GuardedControlFlowNode.expected b/csharp/ql/test/library-tests/controlflow/guards/GuardedControlFlowNode.expected new file mode 100644 index 00000000000..506555c31d5 --- /dev/null +++ b/csharp/ql/test/library-tests/controlflow/guards/GuardedControlFlowNode.expected @@ -0,0 +1,232 @@ +| Assert.cs:11:27:11:27 | access to local variable s | Assert.cs:10:22:10:22 | access to local variable s | Assert.cs:10:22:10:22 | access to local variable s | non-null | +| Assert.cs:11:27:11:27 | access to local variable s | Assert.cs:10:22:10:30 | ... != ... | Assert.cs:10:22:10:22 | access to local variable s | true | +| Assert.cs:18:27:18:27 | access to local variable s | Assert.cs:17:23:17:23 | access to local variable s | Assert.cs:17:23:17:23 | access to local variable s | null | +| Assert.cs:25:27:25:27 | access to local variable s | Assert.cs:24:26:24:26 | access to local variable s | Assert.cs:24:26:24:26 | access to local variable s | non-null | +| Assert.cs:32:27:32:27 | access to local variable s | Assert.cs:31:23:31:23 | access to local variable s | Assert.cs:31:23:31:23 | access to local variable s | null | +| Assert.cs:32:27:32:27 | access to local variable s | Assert.cs:31:23:31:31 | ... == ... | Assert.cs:31:23:31:23 | access to local variable s | true | +| Assert.cs:39:27:39:27 | access to local variable s | Assert.cs:38:23:38:23 | access to local variable s | Assert.cs:38:23:38:23 | access to local variable s | non-null | +| Assert.cs:39:27:39:27 | access to local variable s | Assert.cs:38:23:38:31 | ... != ... | Assert.cs:38:23:38:23 | access to local variable s | true | +| Assert.cs:46:27:46:27 | access to local variable s | Assert.cs:45:24:45:24 | access to local variable s | Assert.cs:45:24:45:24 | access to local variable s | null | +| Assert.cs:46:27:46:27 | access to local variable s | Assert.cs:45:24:45:32 | ... != ... | Assert.cs:45:24:45:24 | access to local variable s | false | +| Assert.cs:53:27:53:27 | access to local variable s | Assert.cs:52:24:52:24 | access to local variable s | Assert.cs:52:24:52:24 | access to local variable s | non-null | +| Assert.cs:53:27:53:27 | access to local variable s | Assert.cs:52:24:52:32 | ... == ... | Assert.cs:52:24:52:24 | access to local variable s | false | +| Assert.cs:59:36:59:36 | access to parameter b | Assert.cs:58:20:58:20 | access to parameter b | Assert.cs:58:20:58:20 | access to parameter b | false | +| Assert.cs:59:36:59:36 | access to parameter b | Assert.cs:58:20:58:32 | ... ? ... : ... | Assert.cs:58:20:58:20 | access to parameter b | non-null | +| Assert.cs:60:27:60:27 | access to local variable s | Assert.cs:59:23:59:23 | access to local variable s | Assert.cs:59:23:59:23 | access to local variable s | non-null | +| Assert.cs:60:27:60:27 | access to local variable s | Assert.cs:59:23:59:31 | ... != ... | Assert.cs:59:23:59:23 | access to local variable s | true | +| Assert.cs:60:27:60:27 | access to local variable s | Assert.cs:59:23:59:36 | ... && ... | Assert.cs:59:23:59:23 | access to local variable s | true | +| Assert.cs:66:37:66:37 | access to parameter b | Assert.cs:65:20:65:20 | access to parameter b | Assert.cs:65:20:65:20 | access to parameter b | false | +| Assert.cs:66:37:66:37 | access to parameter b | Assert.cs:65:20:65:32 | ... ? ... : ... | Assert.cs:65:20:65:20 | access to parameter b | non-null | +| Assert.cs:67:27:67:27 | access to local variable s | Assert.cs:66:24:66:24 | access to local variable s | Assert.cs:66:24:66:24 | access to local variable s | non-null | +| Assert.cs:67:27:67:27 | access to local variable s | Assert.cs:66:24:66:32 | ... == ... | Assert.cs:66:24:66:24 | access to local variable s | false | +| Assert.cs:67:27:67:27 | access to local variable s | Assert.cs:66:24:66:37 | ... \|\| ... | Assert.cs:66:24:66:24 | access to local variable s | false | +| Assert.cs:73:36:73:36 | access to parameter b | Assert.cs:72:20:72:20 | access to parameter b | Assert.cs:72:20:72:20 | access to parameter b | true | +| Assert.cs:73:36:73:36 | access to parameter b | Assert.cs:72:20:72:32 | ... ? ... : ... | Assert.cs:72:20:72:20 | access to parameter b | null | +| Assert.cs:74:27:74:27 | access to local variable s | Assert.cs:73:23:73:23 | access to local variable s | Assert.cs:73:23:73:23 | access to local variable s | null | +| Assert.cs:74:27:74:27 | access to local variable s | Assert.cs:73:23:73:31 | ... == ... | Assert.cs:73:23:73:23 | access to local variable s | true | +| Assert.cs:74:27:74:27 | access to local variable s | Assert.cs:73:23:73:36 | ... && ... | Assert.cs:73:23:73:23 | access to local variable s | true | +| Assert.cs:80:37:80:37 | access to parameter b | Assert.cs:79:20:79:20 | access to parameter b | Assert.cs:79:20:79:20 | access to parameter b | true | +| Assert.cs:80:37:80:37 | access to parameter b | Assert.cs:79:20:79:32 | ... ? ... : ... | Assert.cs:79:20:79:20 | access to parameter b | null | +| Assert.cs:81:27:81:27 | access to local variable s | Assert.cs:80:24:80:24 | access to local variable s | Assert.cs:80:24:80:24 | access to local variable s | null | +| Assert.cs:81:27:81:27 | access to local variable s | Assert.cs:80:24:80:32 | ... != ... | Assert.cs:80:24:80:24 | access to local variable s | false | +| Assert.cs:81:27:81:27 | access to local variable s | Assert.cs:80:24:80:37 | ... \|\| ... | Assert.cs:80:24:80:24 | access to local variable s | false | +| Guards.cs:12:13:12:13 | access to parameter s | Guards.cs:10:16:10:16 | access to parameter s | Guards.cs:10:16:10:16 | access to parameter s | non-null | +| Guards.cs:12:13:12:13 | access to parameter s | Guards.cs:10:16:10:24 | ... == ... | Guards.cs:10:16:10:16 | access to parameter s | false | +| Guards.cs:14:31:14:31 | access to parameter s | Guards.cs:10:16:10:16 | access to parameter s | Guards.cs:10:16:10:16 | access to parameter s | non-null | +| Guards.cs:14:31:14:31 | access to parameter s | Guards.cs:10:16:10:24 | ... == ... | Guards.cs:10:16:10:16 | access to parameter s | false | +| Guards.cs:14:31:14:31 | access to parameter s | Guards.cs:12:13:12:24 | ... > ... | Guards.cs:12:13:12:13 | access to parameter s | true | +| Guards.cs:26:31:26:31 | access to parameter s | Guards.cs:24:13:24:13 | access to parameter s | Guards.cs:24:13:24:13 | access to parameter s | non-null | +| Guards.cs:26:31:26:31 | access to parameter s | Guards.cs:24:13:24:21 | ... != ... | Guards.cs:24:13:24:13 | access to parameter s | true | +| Guards.cs:33:31:33:31 | access to parameter x | Guards.cs:32:13:32:36 | !... | Guards.cs:32:35:32:35 | access to parameter x | true | +| Guards.cs:33:31:33:31 | access to parameter x | Guards.cs:32:13:32:51 | ... & ... | Guards.cs:32:35:32:35 | access to parameter x | true | +| Guards.cs:33:31:33:31 | access to parameter x | Guards.cs:32:14:32:36 | call to method IsNullOrEmpty | Guards.cs:32:35:32:35 | access to parameter x | false | +| Guards.cs:33:31:33:31 | access to parameter x | Guards.cs:32:35:32:35 | access to parameter x | Guards.cs:32:35:32:35 | access to parameter x | non-null | +| Guards.cs:33:35:33:35 | access to parameter y | Guards.cs:32:13:32:51 | ... & ... | Guards.cs:32:42:32:42 | access to parameter y | true | +| Guards.cs:33:35:33:35 | access to parameter y | Guards.cs:32:40:32:51 | !... | Guards.cs:32:42:32:42 | access to parameter y | true | +| Guards.cs:33:35:33:35 | access to parameter y | Guards.cs:32:42:32:42 | access to parameter y | Guards.cs:32:42:32:42 | access to parameter y | non-null | +| Guards.cs:33:35:33:35 | access to parameter y | Guards.cs:32:42:32:50 | ... == ... | Guards.cs:32:42:32:42 | access to parameter y | false | +| Guards.cs:36:32:36:32 | access to parameter x | Guards.cs:35:13:35:13 | access to parameter x | Guards.cs:35:13:35:13 | access to parameter x | non-null | +| Guards.cs:36:32:36:32 | access to parameter x | Guards.cs:35:13:35:21 | ... == ... | Guards.cs:35:13:35:13 | access to parameter x | false | +| Guards.cs:36:36:36:36 | access to parameter y | Guards.cs:35:26:35:26 | access to parameter y | Guards.cs:35:26:35:26 | access to parameter y | non-null | +| Guards.cs:36:36:36:36 | access to parameter y | Guards.cs:35:26:35:34 | ... == ... | Guards.cs:35:26:35:26 | access to parameter y | false | +| Guards.cs:39:31:39:31 | access to parameter x | Guards.cs:38:15:38:15 | access to parameter x | Guards.cs:38:15:38:15 | access to parameter x | non-null | +| Guards.cs:39:31:39:31 | access to parameter x | Guards.cs:38:15:38:23 | ... == ... | Guards.cs:38:15:38:15 | access to parameter x | false | +| Guards.cs:39:35:39:35 | access to parameter y | Guards.cs:38:28:38:28 | access to parameter y | Guards.cs:38:28:38:28 | access to parameter y | non-null | +| Guards.cs:39:35:39:35 | access to parameter y | Guards.cs:38:28:38:36 | ... == ... | Guards.cs:38:28:38:28 | access to parameter y | false | +| Guards.cs:42:32:42:32 | access to parameter x | Guards.cs:41:17:41:17 | access to parameter x | Guards.cs:41:17:41:17 | access to parameter x | non-null | +| Guards.cs:42:32:42:32 | access to parameter x | Guards.cs:41:17:41:25 | ... != ... | Guards.cs:41:17:41:17 | access to parameter x | true | +| Guards.cs:42:36:42:36 | access to parameter y | Guards.cs:41:30:41:30 | access to parameter y | Guards.cs:41:30:41:30 | access to parameter y | non-null | +| Guards.cs:42:36:42:36 | access to parameter y | Guards.cs:41:30:41:38 | ... != ... | Guards.cs:41:30:41:30 | access to parameter y | true | +| Guards.cs:48:31:48:40 | access to field Field | Guards.cs:47:13:47:17 | access to field Field | Guards.cs:47:13:47:17 | access to field Field | non-null | +| Guards.cs:48:31:48:40 | access to field Field | Guards.cs:47:13:47:25 | ... != ... | Guards.cs:47:13:47:17 | access to field Field | true | +| Guards.cs:55:27:55:27 | access to parameter g | Guards.cs:53:13:53:19 | access to field Field | Guards.cs:53:13:53:13 | access to parameter g | non-null | +| Guards.cs:55:27:55:27 | access to parameter g | Guards.cs:53:13:53:27 | ... == ... | Guards.cs:53:13:53:13 | access to parameter g | false | +| Guards.cs:55:27:55:33 | access to field Field | Guards.cs:53:13:53:19 | access to field Field | Guards.cs:53:13:53:19 | access to field Field | non-null | +| Guards.cs:55:27:55:33 | access to field Field | Guards.cs:53:13:53:27 | ... == ... | Guards.cs:53:13:53:19 | access to field Field | false | +| Guards.cs:62:27:62:27 | access to parameter g | Guards.cs:60:13:60:37 | access to field Field | Guards.cs:60:13:60:13 | access to parameter g | non-null | +| Guards.cs:62:27:62:27 | access to parameter g | Guards.cs:60:13:60:45 | ... == ... | Guards.cs:60:13:60:13 | access to parameter g | false | +| Guards.cs:62:27:62:36 | access to property Property | Guards.cs:60:13:60:37 | access to field Field | Guards.cs:60:13:60:22 | access to property Property | non-null | +| Guards.cs:62:27:62:36 | access to property Property | Guards.cs:60:13:60:45 | ... == ... | Guards.cs:60:13:60:22 | access to property Property | false | +| Guards.cs:62:27:62:45 | access to property Property | Guards.cs:60:13:60:37 | access to field Field | Guards.cs:60:13:60:31 | access to property Property | non-null | +| Guards.cs:62:27:62:45 | access to property Property | Guards.cs:60:13:60:45 | ... == ... | Guards.cs:60:13:60:31 | access to property Property | false | +| Guards.cs:62:27:62:51 | access to field Field | Guards.cs:60:13:60:37 | access to field Field | Guards.cs:60:13:60:37 | access to field Field | non-null | +| Guards.cs:62:27:62:51 | access to field Field | Guards.cs:60:13:60:45 | ... == ... | Guards.cs:60:13:60:37 | access to field Field | false | +| Guards.cs:63:27:63:27 | access to parameter g | Guards.cs:60:13:60:37 | access to field Field | Guards.cs:60:13:60:13 | access to parameter g | non-null | +| Guards.cs:63:27:63:27 | access to parameter g | Guards.cs:60:13:60:45 | ... == ... | Guards.cs:60:13:60:13 | access to parameter g | false | +| Guards.cs:63:27:63:36 | access to property Property | Guards.cs:60:13:60:37 | access to field Field | Guards.cs:60:13:60:22 | access to property Property | non-null | +| Guards.cs:63:27:63:36 | access to property Property | Guards.cs:60:13:60:45 | ... == ... | Guards.cs:60:13:60:22 | access to property Property | false | +| Guards.cs:70:31:70:31 | access to parameter s | Guards.cs:68:16:68:16 | access to parameter s | Guards.cs:68:16:68:16 | access to parameter s | non-null | +| Guards.cs:70:31:70:31 | access to parameter s | Guards.cs:68:16:68:24 | ... != ... | Guards.cs:68:16:68:16 | access to parameter s | true | +| Guards.cs:79:31:79:31 | access to parameter s | Guards.cs:78:13:78:13 | access to parameter s | Guards.cs:78:13:78:13 | access to parameter s | non-null | +| Guards.cs:79:31:79:31 | access to parameter s | Guards.cs:78:13:78:26 | ... == ... | Guards.cs:78:13:78:13 | access to parameter s | true | +| Guards.cs:79:31:79:31 | access to parameter s | Guards.cs:78:15:78:21 | access to property Length | Guards.cs:78:13:78:13 | access to parameter s | non-null | +| Guards.cs:81:31:81:31 | access to parameter s | Guards.cs:80:13:80:13 | access to parameter s | Guards.cs:80:13:80:13 | access to parameter s | non-null | +| Guards.cs:81:31:81:31 | access to parameter s | Guards.cs:80:13:80:25 | ... > ... | Guards.cs:80:13:80:13 | access to parameter s | true | +| Guards.cs:81:31:81:31 | access to parameter s | Guards.cs:80:15:80:21 | access to property Length | Guards.cs:80:13:80:13 | access to parameter s | non-null | +| Guards.cs:83:31:83:31 | access to parameter s | Guards.cs:82:13:82:13 | access to parameter s | Guards.cs:82:13:82:13 | access to parameter s | non-null | +| Guards.cs:83:31:83:31 | access to parameter s | Guards.cs:82:13:82:26 | ... >= ... | Guards.cs:82:13:82:13 | access to parameter s | true | +| Guards.cs:83:31:83:31 | access to parameter s | Guards.cs:82:15:82:21 | access to property Length | Guards.cs:82:13:82:13 | access to parameter s | non-null | +| Guards.cs:85:31:85:31 | access to parameter s | Guards.cs:84:13:84:13 | access to parameter s | Guards.cs:84:13:84:13 | access to parameter s | non-null | +| Guards.cs:85:31:85:31 | access to parameter s | Guards.cs:84:13:84:26 | ... < ... | Guards.cs:84:13:84:13 | access to parameter s | true | +| Guards.cs:85:31:85:31 | access to parameter s | Guards.cs:84:15:84:21 | access to property Length | Guards.cs:84:13:84:13 | access to parameter s | non-null | +| Guards.cs:87:31:87:31 | access to parameter s | Guards.cs:86:13:86:13 | access to parameter s | Guards.cs:86:13:86:13 | access to parameter s | non-null | +| Guards.cs:87:31:87:31 | access to parameter s | Guards.cs:86:13:86:27 | ... <= ... | Guards.cs:86:13:86:13 | access to parameter s | true | +| Guards.cs:87:31:87:31 | access to parameter s | Guards.cs:86:15:86:21 | access to property Length | Guards.cs:86:13:86:13 | access to parameter s | non-null | +| Guards.cs:89:31:89:31 | access to parameter s | Guards.cs:88:13:88:13 | access to parameter s | Guards.cs:88:13:88:13 | access to parameter s | non-null | +| Guards.cs:89:31:89:31 | access to parameter s | Guards.cs:88:13:88:29 | ... != ... | Guards.cs:88:13:88:13 | access to parameter s | true | +| Guards.cs:89:31:89:31 | access to parameter s | Guards.cs:88:15:88:21 | access to property Length | Guards.cs:88:13:88:13 | access to parameter s | non-null | +| Guards.cs:91:31:91:31 | access to parameter s | Guards.cs:88:13:88:13 | access to parameter s | Guards.cs:88:13:88:13 | access to parameter s | null | +| Guards.cs:91:31:91:31 | access to parameter s | Guards.cs:88:13:88:29 | ... != ... | Guards.cs:88:13:88:13 | access to parameter s | false | +| Guards.cs:91:31:91:31 | access to parameter s | Guards.cs:88:15:88:21 | access to property Length | Guards.cs:88:13:88:13 | access to parameter s | null | +| Guards.cs:93:31:93:31 | access to parameter s | Guards.cs:92:13:92:30 | ... != ... | Guards.cs:92:13:92:13 | access to parameter s | true | +| Guards.cs:95:31:95:31 | access to parameter s | Guards.cs:92:13:92:13 | access to parameter s | Guards.cs:92:13:92:13 | access to parameter s | non-null | +| Guards.cs:95:31:95:31 | access to parameter s | Guards.cs:92:13:92:25 | ... - ... | Guards.cs:92:13:92:13 | access to parameter s | non-null | +| Guards.cs:95:31:95:31 | access to parameter s | Guards.cs:92:13:92:30 | ... != ... | Guards.cs:92:13:92:13 | access to parameter s | false | +| Guards.cs:95:31:95:31 | access to parameter s | Guards.cs:92:15:92:21 | access to property Length | Guards.cs:92:13:92:13 | access to parameter s | non-null | +| Guards.cs:97:31:97:31 | access to parameter s | Guards.cs:96:13:96:13 | access to parameter s | Guards.cs:96:13:96:13 | access to parameter s | non-null | +| Guards.cs:97:31:97:31 | access to parameter s | Guards.cs:96:13:96:19 | ... == ... | Guards.cs:96:13:96:13 | access to parameter s | true | +| Guards.cs:99:31:99:31 | access to parameter s | Guards.cs:96:13:96:19 | ... == ... | Guards.cs:96:13:96:13 | access to parameter s | false | +| Guards.cs:106:9:106:9 | access to parameter g | Guards.cs:104:13:104:37 | access to field Field | Guards.cs:104:13:104:13 | access to parameter g | non-null | +| Guards.cs:106:9:106:9 | access to parameter g | Guards.cs:104:13:104:45 | ... == ... | Guards.cs:104:13:104:13 | access to parameter g | false | +| Guards.cs:107:27:107:27 | access to parameter g | Guards.cs:104:13:104:37 | access to field Field | Guards.cs:104:13:104:13 | access to parameter g | non-null | +| Guards.cs:107:27:107:27 | access to parameter g | Guards.cs:104:13:104:45 | ... == ... | Guards.cs:104:13:104:13 | access to parameter g | false | +| Guards.cs:108:27:108:27 | access to parameter g | Guards.cs:104:13:104:37 | access to field Field | Guards.cs:104:13:104:13 | access to parameter g | non-null | +| Guards.cs:108:27:108:27 | access to parameter g | Guards.cs:104:13:104:45 | ... == ... | Guards.cs:104:13:104:13 | access to parameter g | false | +| Guards.cs:114:14:114:14 | access to parameter g | Guards.cs:113:21:113:45 | access to field Field | Guards.cs:113:21:113:21 | access to parameter g | null | +| Guards.cs:114:14:114:23 | access to property Property | Guards.cs:113:21:113:45 | access to field Field | Guards.cs:113:21:113:30 | access to property Property | null | +| Guards.cs:114:14:114:32 | access to property Property | Guards.cs:113:21:113:45 | access to field Field | Guards.cs:113:21:113:39 | access to property Property | null | +| Guards.cs:114:14:114:38 | access to field Field | Guards.cs:113:21:113:45 | access to field Field | Guards.cs:113:21:113:45 | access to field Field | null | +| Guards.cs:116:27:116:27 | access to parameter g | Guards.cs:115:17:115:41 | access to field Field | Guards.cs:115:17:115:17 | access to parameter g | non-null | +| Guards.cs:116:27:116:36 | access to property Property | Guards.cs:115:17:115:41 | access to field Field | Guards.cs:115:17:115:26 | access to property Property | non-null | +| Guards.cs:116:27:116:45 | access to property Property | Guards.cs:115:17:115:41 | access to field Field | Guards.cs:115:17:115:35 | access to property Property | non-null | +| Guards.cs:116:27:116:51 | access to field Field | Guards.cs:115:17:115:41 | access to field Field | Guards.cs:115:17:115:41 | access to field Field | non-null | +| Guards.cs:117:9:117:9 | access to parameter g | Guards.cs:115:17:115:41 | access to field Field | Guards.cs:115:17:115:17 | access to parameter g | non-null | +| Guards.cs:118:27:118:27 | access to parameter g | Guards.cs:115:17:115:41 | access to field Field | Guards.cs:115:17:115:17 | access to parameter g | non-null | +| Guards.cs:119:27:119:27 | access to parameter g | Guards.cs:115:17:115:41 | access to field Field | Guards.cs:115:17:115:17 | access to parameter g | non-null | +| Guards.cs:125:29:125:30 | access to parameter s1 | Guards.cs:125:18:125:19 | access to parameter s1 | Guards.cs:125:18:125:19 | access to parameter s1 | non-null | +| Guards.cs:131:20:131:20 | access to parameter s | Guards.cs:130:13:130:13 | access to parameter s | Guards.cs:130:13:130:13 | access to parameter s | null | +| Guards.cs:131:20:131:20 | access to parameter s | Guards.cs:130:13:130:21 | ... is ... | Guards.cs:130:13:130:13 | access to parameter s | true | +| Guards.cs:132:16:132:16 | access to parameter s | Guards.cs:130:13:130:13 | access to parameter s | Guards.cs:130:13:130:13 | access to parameter s | non-null | +| Guards.cs:132:16:132:16 | access to parameter s | Guards.cs:130:13:130:21 | ... is ... | Guards.cs:130:13:130:13 | access to parameter s | false | +| Guards.cs:138:20:138:20 | access to parameter s | Guards.cs:137:13:137:13 | access to parameter s | Guards.cs:137:13:137:13 | access to parameter s | non-null | +| Guards.cs:138:20:138:20 | access to parameter s | Guards.cs:137:13:137:23 | ... is ... | Guards.cs:137:13:137:13 | access to parameter s | true | +| Guards.cs:139:16:139:16 | access to parameter s | Guards.cs:137:13:137:13 | access to parameter s | Guards.cs:137:13:137:13 | access to parameter s | null | +| Guards.cs:139:16:139:16 | access to parameter s | Guards.cs:137:13:137:23 | ... is ... | Guards.cs:137:13:137:13 | access to parameter s | false | +| Guards.cs:146:16:146:16 | access to parameter o | Guards.cs:144:13:144:25 | ... is ... | Guards.cs:144:13:144:13 | access to parameter o | false | +| Guards.cs:154:24:154:24 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | match case Action: | +| Guards.cs:154:24:154:24 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | non-null | +| Guards.cs:158:24:158:24 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | match case ...: | +| Guards.cs:158:24:158:24 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | non-match case Action: | +| Guards.cs:158:24:158:24 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | non-match case Action a: | +| Guards.cs:158:24:158:24 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | non-null | +| Guards.cs:160:24:160:24 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | match case ...: | +| Guards.cs:160:24:160:24 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | non-match case ...: | +| Guards.cs:160:24:160:24 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | non-match case Action: | +| Guards.cs:160:24:160:24 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | non-match case Action a: | +| Guards.cs:160:24:160:24 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | null | +| Guards.cs:162:24:162:24 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | non-match case ...: | +| Guards.cs:162:24:162:24 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | non-match case ...: | +| Guards.cs:162:24:162:24 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | non-match case Action: | +| Guards.cs:162:24:162:24 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | non-match case Action a: | +| Guards.cs:162:24:162:24 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | non-null | +| Guards.cs:169:31:169:31 | access to parameter x | Guards.cs:168:14:168:41 | call to method IsNullOrWhiteSpace | Guards.cs:168:40:168:40 | access to parameter x | false | +| Guards.cs:169:31:169:31 | access to parameter x | Guards.cs:168:40:168:40 | access to parameter x | Guards.cs:168:40:168:40 | access to parameter x | non-null | +| Guards.cs:190:31:190:31 | access to parameter s | Guards.cs:189:14:189:25 | call to method NullTest1 | Guards.cs:189:24:189:24 | access to parameter s | false | +| Guards.cs:190:31:190:31 | access to parameter s | Guards.cs:189:24:189:24 | access to parameter s | Guards.cs:189:24:189:24 | access to parameter s | non-null | +| Guards.cs:192:31:192:31 | access to parameter s | Guards.cs:191:14:191:25 | call to method NullTest2 | Guards.cs:191:24:191:24 | access to parameter s | false | +| Guards.cs:192:31:192:31 | access to parameter s | Guards.cs:191:24:191:24 | access to parameter s | Guards.cs:191:24:191:24 | access to parameter s | non-null | +| Guards.cs:194:31:194:31 | access to parameter s | Guards.cs:193:14:193:25 | call to method NullTest3 | Guards.cs:193:24:193:24 | access to parameter s | false | +| Guards.cs:194:31:194:31 | access to parameter s | Guards.cs:193:24:193:24 | access to parameter s | Guards.cs:193:24:193:24 | access to parameter s | non-null | +| Guards.cs:196:31:196:31 | access to parameter s | Guards.cs:195:13:195:27 | call to method NotNullTest4 | Guards.cs:195:26:195:26 | access to parameter s | true | +| Guards.cs:196:31:196:31 | access to parameter s | Guards.cs:195:26:195:26 | access to parameter s | Guards.cs:195:26:195:26 | access to parameter s | non-null | +| Guards.cs:198:31:198:31 | access to parameter s | Guards.cs:197:14:197:29 | call to method NullTestWrong | Guards.cs:197:28:197:28 | access to parameter s | false | +| Guards.cs:205:13:205:13 | access to parameter o | Guards.cs:203:13:203:13 | access to parameter o | Guards.cs:203:13:203:13 | access to parameter o | non-null | +| Guards.cs:205:13:205:13 | access to parameter o | Guards.cs:203:13:203:21 | ... != ... | Guards.cs:203:13:203:13 | access to parameter o | true | +| Guards.cs:208:17:208:17 | access to parameter o | Guards.cs:203:13:203:13 | access to parameter o | Guards.cs:203:13:203:13 | access to parameter o | non-null | +| Guards.cs:208:17:208:17 | access to parameter o | Guards.cs:203:13:203:21 | ... != ... | Guards.cs:203:13:203:13 | access to parameter o | true | +| Splitting.cs:13:17:13:17 | [b (line 9): true] access to parameter o | Splitting.cs:12:17:12:17 | access to parameter o | Splitting.cs:12:17:12:17 | access to parameter o | non-null | +| Splitting.cs:13:17:13:17 | [b (line 9): true] access to parameter o | Splitting.cs:12:17:12:25 | ... != ... | Splitting.cs:12:17:12:17 | access to parameter o | true | +| Splitting.cs:14:13:14:13 | [b (line 9): false] access to parameter b | Splitting.cs:11:13:11:13 | access to parameter b | Splitting.cs:11:13:11:13 | access to parameter b | false | +| Splitting.cs:14:13:14:13 | [b (line 9): true] access to parameter b | Splitting.cs:11:13:11:13 | access to parameter b | Splitting.cs:11:13:11:13 | access to parameter b | true | +| Splitting.cs:23:24:23:24 | access to parameter o | Splitting.cs:22:17:22:17 | access to parameter o | Splitting.cs:22:17:22:17 | access to parameter o | non-null | +| Splitting.cs:23:24:23:24 | access to parameter o | Splitting.cs:22:17:22:25 | ... != ... | Splitting.cs:22:17:22:17 | access to parameter o | true | +| Splitting.cs:24:13:24:13 | [b (line 19): false] access to parameter b | Splitting.cs:21:13:21:13 | access to parameter b | Splitting.cs:21:13:21:13 | access to parameter b | false | +| Splitting.cs:24:13:24:13 | [b (line 19): true] access to parameter b | Splitting.cs:21:13:21:13 | access to parameter b | Splitting.cs:21:13:21:13 | access to parameter b | true | +| Splitting.cs:25:13:25:13 | access to parameter o | Splitting.cs:22:17:22:17 | access to parameter o | Splitting.cs:22:17:22:17 | access to parameter o | null | +| Splitting.cs:25:13:25:13 | access to parameter o | Splitting.cs:22:17:22:25 | ... != ... | Splitting.cs:22:17:22:17 | access to parameter o | false | +| Splitting.cs:34:13:34:13 | [b (line 29): false] access to parameter b | Splitting.cs:31:13:31:13 | access to parameter b | Splitting.cs:31:13:31:13 | access to parameter b | false | +| Splitting.cs:34:13:34:13 | [b (line 29): true] access to parameter b | Splitting.cs:31:13:31:13 | access to parameter b | Splitting.cs:31:13:31:13 | access to parameter b | true | +| Splitting.cs:35:13:35:13 | access to parameter o | Splitting.cs:32:17:32:17 | access to parameter o | Splitting.cs:32:17:32:17 | access to parameter o | non-null | +| Splitting.cs:35:13:35:13 | access to parameter o | Splitting.cs:32:17:32:25 | ... == ... | Splitting.cs:32:17:32:17 | access to parameter o | false | +| Splitting.cs:44:17:44:17 | [b (line 39): true] access to parameter o | Splitting.cs:41:13:41:13 | access to parameter o | Splitting.cs:41:13:41:13 | access to parameter o | non-null | +| Splitting.cs:44:17:44:17 | [b (line 39): true] access to parameter o | Splitting.cs:41:13:41:21 | ... != ... | Splitting.cs:41:13:41:13 | access to parameter o | true | +| Splitting.cs:45:17:45:17 | [b (line 39): false] access to parameter b | Splitting.cs:43:17:43:17 | access to parameter b | Splitting.cs:43:17:43:17 | access to parameter b | false | +| Splitting.cs:45:17:45:17 | [b (line 39): true] access to parameter b | Splitting.cs:43:17:43:17 | access to parameter b | Splitting.cs:43:17:43:17 | access to parameter b | true | +| Splitting.cs:46:17:46:17 | access to parameter o | Splitting.cs:41:13:41:13 | access to parameter o | Splitting.cs:41:13:41:13 | access to parameter o | non-null | +| Splitting.cs:46:17:46:17 | access to parameter o | Splitting.cs:41:13:41:21 | ... != ... | Splitting.cs:41:13:41:13 | access to parameter o | true | +| Splitting.cs:55:13:55:13 | [b (line 50): false] access to parameter o | Splitting.cs:54:13:54:13 | access to parameter o | Splitting.cs:54:13:54:13 | access to parameter o | non-null | +| Splitting.cs:55:13:55:13 | [b (line 50): false] access to parameter o | Splitting.cs:54:13:54:21 | ... != ... | Splitting.cs:54:13:54:13 | access to parameter o | true | +| Splitting.cs:55:13:55:13 | [b (line 50): true] access to parameter o | Splitting.cs:54:13:54:13 | access to parameter o | Splitting.cs:54:13:54:13 | access to parameter o | non-null | +| Splitting.cs:55:13:55:13 | [b (line 50): true] access to parameter o | Splitting.cs:54:13:54:21 | ... != ... | Splitting.cs:54:13:54:13 | access to parameter o | true | +| Splitting.cs:56:13:56:13 | [b (line 50): false] access to parameter b | Splitting.cs:52:13:52:13 | access to parameter b | Splitting.cs:52:13:52:13 | access to parameter b | false | +| Splitting.cs:56:13:56:13 | [b (line 50): true] access to parameter b | Splitting.cs:52:13:52:13 | access to parameter b | Splitting.cs:52:13:52:13 | access to parameter b | true | +| Splitting.cs:66:20:66:20 | access to parameter o | Splitting.cs:65:13:65:13 | access to parameter o | Splitting.cs:65:13:65:13 | access to parameter o | non-null | +| Splitting.cs:66:20:66:20 | access to parameter o | Splitting.cs:65:13:65:21 | ... != ... | Splitting.cs:65:13:65:13 | access to parameter o | true | +| Splitting.cs:67:13:67:13 | [b (line 61): false] access to parameter b | Splitting.cs:63:13:63:13 | access to parameter b | Splitting.cs:63:13:63:13 | access to parameter b | false | +| Splitting.cs:67:13:67:13 | [b (line 61): true] access to parameter b | Splitting.cs:63:13:63:13 | access to parameter b | Splitting.cs:63:13:63:13 | access to parameter b | true | +| Splitting.cs:68:13:68:13 | access to parameter o | Splitting.cs:65:13:65:13 | access to parameter o | Splitting.cs:65:13:65:13 | access to parameter o | null | +| Splitting.cs:68:13:68:13 | access to parameter o | Splitting.cs:65:13:65:21 | ... != ... | Splitting.cs:65:13:65:13 | access to parameter o | false | +| Splitting.cs:69:16:69:16 | access to parameter o | Splitting.cs:65:13:65:13 | access to parameter o | Splitting.cs:65:13:65:13 | access to parameter o | null | +| Splitting.cs:69:16:69:16 | access to parameter o | Splitting.cs:65:13:65:21 | ... != ... | Splitting.cs:65:13:65:13 | access to parameter o | false | +| Splitting.cs:78:24:78:24 | access to parameter o | Splitting.cs:76:13:76:13 | access to parameter o | Splitting.cs:76:13:76:13 | access to parameter o | non-null | +| Splitting.cs:78:24:78:24 | access to parameter o | Splitting.cs:76:13:76:21 | ... != ... | Splitting.cs:76:13:76:13 | access to parameter o | true | +| Splitting.cs:79:13:79:13 | [b (line 72): false] access to parameter b | Splitting.cs:74:13:74:13 | access to parameter b | Splitting.cs:74:13:74:13 | access to parameter b | false | +| Splitting.cs:79:13:79:13 | [b (line 72): true] access to parameter b | Splitting.cs:74:13:74:13 | access to parameter b | Splitting.cs:74:13:74:13 | access to parameter b | true | +| Splitting.cs:88:9:88:9 | [b (line 84): true] access to parameter o | Splitting.cs:87:26:87:26 | access to parameter o | Splitting.cs:87:26:87:26 | access to parameter o | non-null | +| Splitting.cs:88:9:88:9 | [b (line 84): true] access to parameter o | Splitting.cs:87:26:87:34 | ... != ... | Splitting.cs:87:26:87:26 | access to parameter o | true | +| Splitting.cs:89:13:89:13 | [b (line 84): false] access to parameter b | Splitting.cs:86:13:86:13 | access to parameter b | Splitting.cs:86:13:86:13 | access to parameter b | false | +| Splitting.cs:89:13:89:13 | [b (line 84): true] access to parameter b | Splitting.cs:86:13:86:13 | access to parameter b | Splitting.cs:86:13:86:13 | access to parameter b | true | +| Splitting.cs:90:13:90:13 | access to parameter o | Splitting.cs:87:26:87:26 | access to parameter o | Splitting.cs:87:26:87:26 | access to parameter o | non-null | +| Splitting.cs:90:13:90:13 | access to parameter o | Splitting.cs:87:26:87:34 | ... != ... | Splitting.cs:87:26:87:26 | access to parameter o | true | +| Splitting.cs:98:13:98:13 | [b (line 94): false] access to parameter b | Splitting.cs:96:13:96:13 | access to parameter b | Splitting.cs:96:13:96:13 | access to parameter b | false | +| Splitting.cs:98:13:98:13 | [b (line 94): true] access to parameter b | Splitting.cs:96:13:96:13 | access to parameter b | Splitting.cs:96:13:96:13 | access to parameter b | true | +| Splitting.cs:99:13:99:13 | access to parameter o | Splitting.cs:97:26:97:26 | access to parameter o | Splitting.cs:97:26:97:26 | access to parameter o | null | +| Splitting.cs:99:13:99:13 | access to parameter o | Splitting.cs:97:26:97:34 | ... == ... | Splitting.cs:97:26:97:26 | access to parameter o | true | +| Splitting.cs:107:13:107:13 | [b (line 103): true] access to parameter o | Splitting.cs:105:22:105:22 | access to parameter o | Splitting.cs:105:22:105:22 | access to parameter o | non-null | +| Splitting.cs:107:13:107:13 | [b (line 103): true] access to parameter o | Splitting.cs:105:22:105:30 | ... != ... | Splitting.cs:105:22:105:22 | access to parameter o | true | +| Splitting.cs:108:13:108:13 | [b (line 103): false] access to parameter b | Splitting.cs:106:13:106:13 | access to parameter b | Splitting.cs:106:13:106:13 | access to parameter b | false | +| Splitting.cs:108:13:108:13 | [b (line 103): true] access to parameter b | Splitting.cs:106:13:106:13 | access to parameter b | Splitting.cs:106:13:106:13 | access to parameter b | true | +| Splitting.cs:109:13:109:13 | access to parameter o | Splitting.cs:105:22:105:22 | access to parameter o | Splitting.cs:105:22:105:22 | access to parameter o | non-null | +| Splitting.cs:109:13:109:13 | access to parameter o | Splitting.cs:105:22:105:30 | ... != ... | Splitting.cs:105:22:105:22 | access to parameter o | true | +| Splitting.cs:117:9:117:9 | [b (line 112): false] access to parameter o | Splitting.cs:116:22:116:22 | access to parameter o | Splitting.cs:116:22:116:22 | access to parameter o | non-null | +| Splitting.cs:117:9:117:9 | [b (line 112): false] access to parameter o | Splitting.cs:116:22:116:30 | ... != ... | Splitting.cs:116:22:116:22 | access to parameter o | true | +| Splitting.cs:117:9:117:9 | [b (line 112): true] access to parameter o | Splitting.cs:116:22:116:22 | access to parameter o | Splitting.cs:116:22:116:22 | access to parameter o | non-null | +| Splitting.cs:117:9:117:9 | [b (line 112): true] access to parameter o | Splitting.cs:116:22:116:30 | ... != ... | Splitting.cs:116:22:116:22 | access to parameter o | true | +| Splitting.cs:118:13:118:13 | [b (line 112): false] access to parameter b | Splitting.cs:114:13:114:13 | access to parameter b | Splitting.cs:114:13:114:13 | access to parameter b | false | +| Splitting.cs:118:13:118:13 | [b (line 112): true] access to parameter b | Splitting.cs:114:13:114:13 | access to parameter b | Splitting.cs:114:13:114:13 | access to parameter b | true | +| Splitting.cs:119:13:119:13 | access to parameter o | Splitting.cs:116:22:116:22 | access to parameter o | Splitting.cs:116:22:116:22 | access to parameter o | non-null | +| Splitting.cs:119:13:119:13 | access to parameter o | Splitting.cs:116:22:116:30 | ... != ... | Splitting.cs:116:22:116:22 | access to parameter o | true | +| Splitting.cs:120:16:120:16 | access to parameter o | Splitting.cs:116:22:116:22 | access to parameter o | Splitting.cs:116:22:116:22 | access to parameter o | non-null | +| Splitting.cs:120:16:120:16 | access to parameter o | Splitting.cs:116:22:116:30 | ... != ... | Splitting.cs:116:22:116:22 | access to parameter o | true | +| Splitting.cs:130:21:130:21 | [b (line 123): false] access to parameter b | Splitting.cs:130:21:130:21 | access to parameter b | Splitting.cs:130:21:130:21 | access to parameter b | false | +| Splitting.cs:132:25:132:25 | [b (line 123): false] access to parameter b | Splitting.cs:130:21:130:21 | access to parameter b | Splitting.cs:130:21:130:21 | access to parameter b | false | diff --git a/csharp/ql/test/library-tests/controlflow/guards/GuardedControlFlowNode.ql b/csharp/ql/test/library-tests/controlflow/guards/GuardedControlFlowNode.ql new file mode 100644 index 00000000000..82d843a2a41 --- /dev/null +++ b/csharp/ql/test/library-tests/controlflow/guards/GuardedControlFlowNode.ql @@ -0,0 +1,5 @@ +import csharp +import semmle.code.csharp.controlflow.Guards + +from GuardedControlFlowNode gcfn, Expr sub, AbstractValue v +select gcfn, gcfn.getAGuard(sub, v), sub, v diff --git a/csharp/ql/test/library-tests/dataflow/ssa/SsaDefElement.expected b/csharp/ql/test/library-tests/dataflow/ssa/SsaDefElement.expected new file mode 100644 index 00000000000..04b5215b610 --- /dev/null +++ b/csharp/ql/test/library-tests/dataflow/ssa/SsaDefElement.expected @@ -0,0 +1,340 @@ +| Capture.cs:6:16:6:16 | SSA param(i) | Capture.cs:6:16:6:16 | i | +| Capture.cs:8:13:8:17 | SSA def(x) | Capture.cs:8:13:8:17 | Int32 x = ... | +| Capture.cs:10:16:27:9 | SSA def(a) | Capture.cs:10:16:27:9 | Action a = ... | +| Capture.cs:10:20:27:9 | SSA capture def(i) | Capture.cs:10:20:27:9 | (...) => ... | +| Capture.cs:13:13:13:17 | SSA def(i) | Capture.cs:13:13:13:17 | ... = ... | +| Capture.cs:15:13:15:17 | SSA def(x) | Capture.cs:15:13:15:17 | ... = ... | +| Capture.cs:17:17:17:21 | SSA def(y) | Capture.cs:17:17:17:21 | Int32 y = ... | +| Capture.cs:19:20:23:13 | SSA def(b) | Capture.cs:19:20:23:13 | Action b = ... | +| Capture.cs:19:24:23:13 | SSA capture def(x) | Capture.cs:19:24:23:13 | (...) => ... | +| Capture.cs:19:24:23:13 | SSA capture def(y) | Capture.cs:19:24:23:13 | (...) => ... | +| Capture.cs:29:13:29:17 | SSA def(z) | Capture.cs:29:13:29:17 | Int32 z = ... | +| Capture.cs:30:16:30:35 | SSA def(c) | Capture.cs:30:16:30:35 | Action c = ... | +| Capture.cs:30:28:30:32 | SSA def(z) | Capture.cs:30:28:30:32 | ... = ... | +| Capture.cs:32:9:32:11 | SSA call def(z) | Capture.cs:32:9:32:11 | delegate call | +| Capture.cs:37:9:37:13 | SSA def(z) | Capture.cs:37:9:37:13 | ... = ... | +| Capture.cs:38:9:38:11 | SSA call def(i) | Capture.cs:38:9:38:11 | delegate call | +| Capture.cs:38:9:38:11 | SSA call def(x) | Capture.cs:38:9:38:11 | delegate call | +| Capture.cs:43:9:43:13 | SSA def(x) | Capture.cs:43:9:43:13 | ... = ... | +| Capture.cs:44:9:44:12 | SSA call def(x) | Capture.cs:44:9:44:12 | call to method M | +| Capture.cs:50:20:50:20 | SSA param(a) | Capture.cs:50:20:50:20 | a | +| Capture.cs:52:16:52:43 | SSA def(b) | Capture.cs:52:16:52:43 | Action b = ... | +| Capture.cs:52:28:52:40 | SSA def(a) | Capture.cs:52:28:52:40 | ... = ... | +| Capture.cs:53:9:53:11 | SSA call def(a) | Capture.cs:53:9:53:11 | delegate call | +| Capture.cs:57:57:57:63 | SSA param(strings) | Capture.cs:57:57:57:63 | strings | +| Capture.cs:59:13:59:17 | SSA def(i) | Capture.cs:59:13:59:17 | Int32 i = ... | +| Capture.cs:60:27:60:38 | SSA def(e) | Capture.cs:60:27:60:38 | Func e = ... | +| Capture.cs:60:31:60:38 | SSA capture def(i) | Capture.cs:60:31:60:38 | (...) => ... | +| Capture.cs:60:36:60:38 | SSA def(i) | Capture.cs:60:36:60:38 | ...++ | +| Capture.cs:61:9:61:25 | SSA call def(i) | Capture.cs:61:9:61:25 | call to method Select | +| Capture.cs:65:45:65:51 | SSA param(strings) | Capture.cs:65:45:65:51 | strings | +| Capture.cs:67:13:67:19 | SSA def(c) | Capture.cs:67:13:67:19 | Char c = ... | +| Capture.cs:68:32:68:32 | SSA param(s) | Capture.cs:68:32:68:32 | s | +| Capture.cs:68:32:68:49 | SSA capture def(c) | Capture.cs:68:32:68:49 | (...) => ... | +| Capture.cs:69:9:69:62 | SSA capture def(c) | Capture.cs:69:9:69:62 | M | +| Capture.cs:69:25:69:25 | SSA param(s) | Capture.cs:69:25:69:25 | s | +| Capture.cs:73:67:73:73 | SSA param(strings) | Capture.cs:73:67:73:73 | strings | +| Capture.cs:75:13:75:17 | SSA def(i) | Capture.cs:75:13:75:17 | Int32 i = ... | +| Capture.cs:76:63:76:81 | SSA def(e) | Capture.cs:76:63:76:81 | Expression> e = ... | +| Capture.cs:76:67:76:81 | SSA capture def(i) | Capture.cs:76:67:76:81 | (...) => ... | +| Capture.cs:76:80:76:80 | SSA def(i) | Capture.cs:76:72:76:81 | call to method Inc | +| Capture.cs:77:9:77:25 | SSA call def(i) | Capture.cs:77:9:77:25 | call to method Select | +| Capture.cs:81:28:81:28 | SSA param(i) | Capture.cs:81:28:81:28 | i | +| Capture.cs:81:34:81:36 | SSA def(i) | Capture.cs:81:34:81:36 | ...++ | +| Capture.cs:83:65:83:71 | SSA param(strings) | Capture.cs:83:65:83:71 | strings | +| Capture.cs:85:13:85:20 | SSA def(b) | Capture.cs:85:13:85:20 | Boolean b = ... | +| Capture.cs:86:64:86:73 | SSA def(e) | Capture.cs:86:64:86:73 | Expression> e = ... | +| Capture.cs:86:68:86:73 | SSA capture def(b) | Capture.cs:86:68:86:73 | (...) => ... | +| Capture.cs:92:18:92:18 | SSA param(d) | Capture.cs:92:18:92:18 | d | +| Capture.cs:94:13:94:18 | SSA def(y) | Capture.cs:94:13:94:18 | Int32 y = ... | +| Capture.cs:96:12:100:9 | SSA capture def(y) | Capture.cs:96:12:100:9 | (...) => ... | +| Capture.cs:98:17:98:21 | SSA def(x) | Capture.cs:98:17:98:21 | Int32 x = ... | +| Capture.cs:105:13:105:17 | SSA def(z) | Capture.cs:105:13:105:17 | ... = ... | +| Capture.cs:114:13:114:18 | SSA def(a) | Capture.cs:114:13:114:18 | Int32 a = ... | +| Capture.cs:115:9:119:9 | SSA capture def(a) | Capture.cs:115:9:119:9 | M1 | +| Capture.cs:117:17:117:21 | SSA def(x) | Capture.cs:117:17:117:21 | Int32 x = ... | +| Capture.cs:125:13:125:17 | SSA def(b) | Capture.cs:125:13:125:17 | ... = ... | +| Capture.cs:130:13:130:18 | SSA def(c) | Capture.cs:130:13:130:18 | Int32 c = ... | +| Capture.cs:133:13:133:17 | SSA def(c) | Capture.cs:133:13:133:17 | ... = ... | +| Capture.cs:136:9:136:12 | SSA call def(c) | Capture.cs:136:9:136:12 | call to local function M3 | +| Capture.cs:139:13:139:18 | SSA def(d) | Capture.cs:139:13:139:18 | Int32 d = ... | +| Capture.cs:142:13:142:17 | SSA def(d) | Capture.cs:142:13:142:17 | ... = ... | +| Capture.cs:144:9:144:12 | SSA call def(d) | Capture.cs:144:9:144:12 | call to local function M4 | +| Capture.cs:148:9:152:9 | SSA capture def(e) | Capture.cs:148:9:152:9 | M5 | +| Capture.cs:154:13:154:18 | SSA def(f) | Capture.cs:154:13:154:18 | Int32 f = ... | +| Capture.cs:163:9:166:9 | SSA capture def(g) | Capture.cs:163:9:166:9 | M7 | +| Capture.cs:171:13:171:17 | SSA def(h) | Capture.cs:171:13:171:17 | ... = ... | +| Capture.cs:174:17:174:21 | SSA def(h) | Capture.cs:174:17:174:21 | ... = ... | +| Capture.cs:176:13:176:16 | SSA call def(h) | Capture.cs:176:13:176:16 | call to local function M9 | +| Capture.cs:182:17:182:21 | SSA def(i) | Capture.cs:182:17:182:21 | Int32 i = ... | +| Capture.cs:183:13:186:13 | SSA capture def(i) | Capture.cs:183:13:186:13 | M11 | +| Capture.cs:188:13:188:17 | SSA def(i) | Capture.cs:188:13:188:17 | ... = ... | +| Capture.cs:197:17:197:21 | SSA def(i) | Capture.cs:197:17:197:21 | Int32 i = ... | +| Capture.cs:198:28:198:44 | SSA def(eh) | Capture.cs:198:28:198:44 | MyEventHandler eh = ... | +| Capture.cs:198:33:198:44 | SSA capture def(i) | Capture.cs:198:33:198:44 | (...) => ... | +| Capture.cs:203:28:203:45 | SSA def(eh2) | Capture.cs:203:28:203:45 | MyEventHandler eh2 = ... | +| Capture.cs:203:34:203:45 | SSA capture def(i) | Capture.cs:203:34:203:45 | (...) => ... | +| Capture.cs:209:17:209:21 | SSA def(i) | Capture.cs:209:17:209:21 | Int32 i = ... | +| Capture.cs:210:24:210:59 | SSA def(p) | Capture.cs:210:24:210:59 | Process p = ... | +| Capture.cs:212:30:212:71 | SSA def(exited) | Capture.cs:212:30:212:71 | EventHandler exited = ... | +| Capture.cs:212:39:212:71 | SSA capture def(i) | Capture.cs:212:39:212:71 | (...) => ... | +| Capture.cs:231:9:231:49 | SSA capture def(i) | Capture.cs:231:9:231:49 | M2 | +| Capture.cs:232:9:232:13 | SSA def(i) | Capture.cs:232:9:232:13 | ... = ... | +| Capture.cs:235:21:235:25 | SSA def(i) | Capture.cs:235:21:235:25 | ... = ... | +| Capture.cs:236:9:236:12 | SSA call def(i) | Capture.cs:236:9:236:12 | call to local function M3 | +| Consistency.cs:7:25:7:25 | SSA param(b) | Consistency.cs:7:25:7:25 | b | +| Consistency.cs:15:17:15:21 | SSA def(i) | Consistency.cs:15:17:15:21 | Int32 i = ... | +| Consistency.cs:15:17:15:21 | [finally: exception(Exception)] SSA def(i) | Consistency.cs:15:17:15:21 | Int32 i = ... | +| Consistency.cs:25:29:25:29 | SSA def(c) | Consistency.cs:25:9:25:30 | call to method Out | +| Consistency.cs:25:29:25:29 | SSA qualifier def(c.Field) | Consistency.cs:25:9:25:30 | call to method Out | +| Consistency.cs:32:9:32:29 | SSA def(c) | Consistency.cs:32:9:32:29 | ... = ... | +| Consistency.cs:39:28:39:32 | SSA def(i) | Consistency.cs:39:28:39:32 | ... = ... | +| Consistency.cs:44:11:44:11 | SSA def(s) | Consistency.cs:44:11:44:11 | S s | +| Consistency.cs:49:30:49:30 | SSA param(a) | Consistency.cs:49:30:49:30 | a | +| Consistency.cs:49:37:49:37 | SSA param(i) | Consistency.cs:49:37:49:37 | i | +| Consistency.cs:51:20:51:20 | SSA param(a) | Consistency.cs:51:20:51:20 | a | +| Consistency.cs:56:17:56:40 | SSA def(k) | Consistency.cs:56:17:56:40 | Int32 k = ... | +| Consistency.cs:57:9:57:13 | SSA def(k) | Consistency.cs:57:9:57:13 | ... = ... | +| Consistency.cs:58:9:58:13 | SSA def(k) | Consistency.cs:58:9:58:13 | ... = ... | +| DefUse.cs:3:26:3:26 | SSA param(w) | DefUse.cs:3:26:3:26 | w | +| DefUse.cs:5:13:5:17 | SSA def(x) | DefUse.cs:5:13:5:17 | Int32 x = ... | +| DefUse.cs:6:14:6:19 | SSA def(y) | DefUse.cs:6:14:6:19 | Int64 y = ... | +| DefUse.cs:13:13:13:18 | SSA def(y) | DefUse.cs:13:13:13:18 | ... = ... | +| DefUse.cs:18:13:18:18 | SSA def(y) | DefUse.cs:18:13:18:18 | ... = ... | +| DefUse.cs:19:13:19:18 | SSA def(w) | DefUse.cs:19:13:19:18 | ... = ... | +| DefUse.cs:28:13:28:18 | SSA def(y) | DefUse.cs:28:13:28:18 | ... = ... | +| DefUse.cs:29:13:29:18 | SSA def(w) | DefUse.cs:29:13:29:18 | ... = ... | +| DefUse.cs:39:13:39:18 | SSA def(y) | DefUse.cs:39:13:39:18 | ... = ... | +| DefUse.cs:44:13:44:17 | SSA def(z) | DefUse.cs:44:13:44:17 | Int32 z = ... | +| DefUse.cs:47:23:47:23 | SSA def(z) | DefUse.cs:47:9:47:24 | call to method outMethod | +| DefUse.cs:50:23:50:23 | SSA def(z) | DefUse.cs:50:9:50:24 | call to method refMethod | +| DefUse.cs:53:9:53:17 | SSA def(this.Field) | DefUse.cs:53:9:53:17 | ... = ... | +| DefUse.cs:56:9:56:16 | SSA def(this.Prop) | DefUse.cs:56:9:56:16 | ... = ... | +| DefUse.cs:59:13:59:17 | SSA def(i) | DefUse.cs:59:13:59:17 | Int32 i = ... | +| DefUse.cs:63:9:63:18 | SSA def(this.Field2) | DefUse.cs:63:9:63:18 | ... = ... | +| DefUse.cs:66:9:66:18 | SSA def(this.Field3) | DefUse.cs:66:9:66:18 | ... = ... | +| DefUse.cs:67:19:67:27 | SSA def(tc) | DefUse.cs:67:19:67:27 | TestClass tc = ... | +| DefUse.cs:71:9:71:13 | SSA def(i) | DefUse.cs:71:9:71:13 | ... = ... | +| DefUse.cs:72:9:72:11 | SSA def(i) | DefUse.cs:72:9:72:11 | ...++ | +| DefUse.cs:75:9:75:13 | SSA def(i) | DefUse.cs:75:9:75:13 | ... = ... | +| DefUse.cs:76:9:76:11 | SSA def(i) | DefUse.cs:76:9:76:11 | ...-- | +| DefUse.cs:79:13:79:18 | SSA def(x1) | DefUse.cs:79:13:79:18 | Int32 x1 = ... | +| DefUse.cs:80:30:80:31 | SSA def(x1) | DefUse.cs:80:16:80:32 | call to method refMethod | +| DefUse.cs:83:13:83:18 | SSA def(x2) | DefUse.cs:83:13:83:18 | Int32 x2 = ... | +| DefUse.cs:85:15:85:16 | SSA def(x2) | DefUse.cs:84:9:86:17 | call to method refOutMethod | +| DefUse.cs:89:13:89:18 | SSA def(x3) | DefUse.cs:89:13:89:18 | Int32 x3 = ... | +| DefUse.cs:92:15:92:16 | SSA def(x3) | DefUse.cs:91:9:93:17 | call to method refOutMethod | +| DefUse.cs:93:15:93:16 | SSA def(x4) | DefUse.cs:91:9:93:17 | call to method refOutMethod | +| DefUse.cs:97:13:97:18 | SSA def(x5) | DefUse.cs:97:13:97:18 | Int32 x5 = ... | +| DefUse.cs:101:13:101:23 | SSA def(x5) | DefUse.cs:101:13:101:23 | ... = ... | +| DefUse.cs:104:9:104:15 | SSA def(x5) | DefUse.cs:104:9:104:15 | ... = ... | +| DefUse.cs:114:47:114:52 | SSA def(i) | DefUse.cs:114:47:114:52 | ... = ... | +| DefUse.cs:116:47:116:51 | SSA def(i) | DefUse.cs:116:47:116:51 | ... = ... | +| DefUse.cs:118:45:118:45 | SSA param(i) | DefUse.cs:118:45:118:45 | i | +| DefUse.cs:118:61:118:65 | SSA def(j) | DefUse.cs:118:61:118:65 | ... = ... | +| DefUse.cs:118:68:118:72 | SSA def(i) | DefUse.cs:118:68:118:72 | ... = ... | +| DefUse.cs:128:19:128:19 | SSA param(i) | DefUse.cs:128:19:128:19 | i | +| DefUse.cs:134:22:134:22 | SSA param(d) | DefUse.cs:134:22:134:22 | d | +| DefUse.cs:142:68:142:69 | SSA param(ie) | DefUse.cs:142:68:142:69 | ie | +| DefUse.cs:144:22:144:22 | SSA def(x) | DefUse.cs:144:22:144:22 | String x | +| DefUse.cs:155:9:155:18 | SSA def(this.Field4) | DefUse.cs:155:9:155:18 | ... = ... | +| DefUse.cs:160:10:160:16 | SSA entry def(this.Field4) | DefUse.cs:160:10:160:16 | FieldM2 | +| DefUse.cs:167:23:167:23 | SSA param(i) | DefUse.cs:167:23:167:23 | i | +| DefUse.cs:170:9:170:13 | SSA def(i) | DefUse.cs:170:9:170:13 | ... = ... | +| DefUse.cs:171:23:180:9 | SSA def(a) | DefUse.cs:171:23:180:9 | Action a = ... | +| DefUse.cs:173:13:173:17 | SSA def(i) | DefUse.cs:173:13:173:17 | ... = ... | +| DefUse.cs:175:32:179:13 | SSA capture def(i) | DefUse.cs:175:32:179:13 | (...) => ... | +| DefUse.cs:181:9:181:11 | SSA call def(i) | DefUse.cs:181:9:181:11 | delegate call | +| DefUse.cs:184:9:184:18 | SSA def(this.Field5) | DefUse.cs:184:9:184:18 | ... = ... | +| DefUse.cs:186:9:190:9 | SSA def(a) | DefUse.cs:186:9:190:9 | ... = ... | +| DefUse.cs:188:13:188:22 | SSA def(this.Field5) | DefUse.cs:188:13:188:22 | ... = ... | +| DefUse.cs:191:9:191:11 | SSA call def(this.Field5) | DefUse.cs:191:9:191:11 | delegate call | +| Example.cs:6:23:6:23 | SSA param(i) | Example.cs:6:23:6:23 | i | +| Example.cs:8:9:8:22 | SSA def(this.Field) | Example.cs:8:9:8:22 | ... = ... | +| Example.cs:11:13:11:30 | SSA def(this.Field) | Example.cs:11:13:11:30 | ... = ... | +| Example.cs:13:13:13:23 | SSA call def(this.Field) | Example.cs:13:13:13:23 | call to method SetField | +| Example.cs:18:16:18:16 | SSA param(p) | Example.cs:18:16:18:16 | p | +| Example.cs:18:24:18:24 | SSA param(b) | Example.cs:18:24:18:24 | b | +| Example.cs:23:13:23:17 | SSA def(p) | Example.cs:23:13:23:17 | ... = ... | +| Fields.cs:16:17:16:17 | SSA entry def(this.xs) | Fields.cs:16:17:16:17 | F | +| Fields.cs:19:9:19:13 | SSA call def(this.xs) | Fields.cs:19:9:19:13 | call to method Upd | +| Fields.cs:20:9:20:14 | SSA def(x) | Fields.cs:20:9:20:14 | ... = ... | +| Fields.cs:22:13:22:17 | SSA call def(this.xs) | Fields.cs:22:13:22:17 | call to method Upd | +| Fields.cs:24:9:24:23 | SSA def(this.xs) | Fields.cs:24:9:24:23 | ... = ... | +| Fields.cs:28:17:28:17 | SSA entry def(Fields.stat) | Fields.cs:28:17:28:17 | G | +| Fields.cs:28:17:28:17 | SSA entry def(this.xs) | Fields.cs:28:17:28:17 | G | +| Fields.cs:30:13:30:28 | SSA def(f) | Fields.cs:30:13:30:28 | Fields f = ... | +| Fields.cs:30:13:30:28 | SSA qualifier def(f.xs) | Fields.cs:30:13:30:28 | Fields f = ... | +| Fields.cs:30:17:30:28 | SSA call def(Fields.stat) | Fields.cs:30:17:30:28 | object creation of type Fields | +| Fields.cs:34:9:34:16 | SSA call def(Fields.stat) | Fields.cs:34:9:34:16 | call to method F | +| Fields.cs:34:9:34:16 | SSA call def(f.xs) | Fields.cs:34:9:34:16 | call to method F | +| Fields.cs:34:9:34:16 | SSA call def(this.xs) | Fields.cs:34:9:34:16 | call to method F | +| Fields.cs:38:9:38:13 | SSA call def(Fields.stat) | Fields.cs:38:9:38:13 | call to method F | +| Fields.cs:38:9:38:13 | SSA call def(f.xs) | Fields.cs:38:9:38:13 | call to method F | +| Fields.cs:38:9:38:13 | SSA call def(this.xs) | Fields.cs:38:9:38:13 | call to method F | +| Fields.cs:42:9:42:23 | SSA def(this.xs) | Fields.cs:42:9:42:23 | ... = ... | +| Fields.cs:45:9:45:25 | SSA def(f.xs) | Fields.cs:45:9:45:25 | ... = ... | +| Fields.cs:47:9:47:14 | SSA def(z) | Fields.cs:47:9:47:14 | ... = ... | +| Fields.cs:49:13:49:28 | SSA def(f) | Fields.cs:49:13:49:28 | ... = ... | +| Fields.cs:49:13:49:28 | SSA qualifier def(f.xs) | Fields.cs:49:13:49:28 | ... = ... | +| Fields.cs:49:17:49:28 | SSA call def(Fields.stat) | Fields.cs:49:17:49:28 | object creation of type Fields | +| Fields.cs:51:9:51:20 | SSA call def(Fields.stat) | Fields.cs:51:9:51:20 | object creation of type Fields | +| Fields.cs:61:17:61:17 | SSA entry def(this.LoopField) | Fields.cs:61:17:61:17 | H | +| Fields.cs:63:16:63:28 | SSA untracked def(this.VolatileField) | Fields.cs:63:16:63:28 | this access | +| Fields.cs:69:21:69:33 | SSA untracked def(this.VolatileField) | Fields.cs:69:21:69:33 | this access | +| Fields.cs:71:17:71:35 | SSA untracked def(this.SingleAccessedField) | Fields.cs:71:17:71:35 | this access | +| Fields.cs:76:20:76:38 | SSA untracked def(this.SingleAccessedField) | Fields.cs:76:20:76:38 | this access | +| Fields.cs:77:13:77:45 | SSA def(f) | Fields.cs:77:13:77:45 | Fields f = ... | +| Fields.cs:78:23:78:54 | SSA def(a) | Fields.cs:78:23:78:54 | Action a = ... | +| Fields.cs:78:27:78:54 | SSA capture def(f) | Fields.cs:78:27:78:54 | (...) => ... | +| Fields.cs:79:23:79:35 | SSA def(b) | Fields.cs:79:23:79:35 | Action b = ... | +| Fields.cs:80:9:80:25 | SSA def(f.xs) | Fields.cs:80:9:80:25 | ... = ... | +| Fields.cs:81:9:81:11 | SSA call def(f.xs) | Fields.cs:81:9:81:11 | delegate call | +| Fields.cs:83:9:83:25 | SSA def(f.xs) | Fields.cs:83:9:83:25 | ... = ... | +| Fields.cs:85:9:85:22 | SSA def(this.xs) | Fields.cs:85:9:85:22 | ... = ... | +| Fields.cs:86:9:86:47 | SSA call def(f.xs) | Fields.cs:86:9:86:47 | call to method Select | +| Fields.cs:86:24:86:46 | SSA capture def(a) | Fields.cs:86:24:86:46 | (...) => ... | +| Fields.cs:87:9:87:22 | SSA def(this.xs) | Fields.cs:87:9:87:22 | ... = ... | +| Fields.cs:88:9:88:25 | SSA def(f.xs) | Fields.cs:88:9:88:25 | ... = ... | +| Fields.cs:89:24:89:46 | SSA capture def(b) | Fields.cs:89:24:89:46 | (...) => ... | +| Fields.cs:95:19:95:19 | SSA param(f) | Fields.cs:95:19:95:19 | f | +| Fields.cs:97:9:97:30 | SSA def(f.Field) | Fields.cs:97:9:97:30 | ... = ... | +| Fields.cs:97:9:97:30 | SSA qualifier def(f.Field.Field) | Fields.cs:97:9:97:30 | ... = ... | +| Fields.cs:97:9:97:30 | SSA qualifier def(f.Field.Field.Field) | Fields.cs:97:9:97:30 | ... = ... | +| Fields.cs:97:9:97:30 | SSA qualifier def(f.Field.Field.Field.Field) | Fields.cs:97:9:97:30 | ... = ... | +| Fields.cs:102:9:102:28 | SSA def(this.Field) | Fields.cs:102:9:102:28 | ... = ... | +| Fields.cs:107:33:107:33 | SSA param(f) | Fields.cs:107:33:107:33 | f | +| Fields.cs:109:10:109:10 | SSA entry def(this.Field) | Fields.cs:109:10:109:10 | K | +| Fields.cs:109:10:109:10 | SSA entry def(this.Field.Field) | Fields.cs:109:10:109:10 | K | +| Fields.cs:109:10:109:10 | SSA entry def(this.Field.Field.xs) | Fields.cs:109:10:109:10 | K | +| Fields.cs:114:9:114:22 | SSA call def(this.Field) | Fields.cs:114:9:114:22 | call to method SetField | +| Fields.cs:114:9:114:22 | SSA call def(this.Field.Field) | Fields.cs:114:9:114:22 | call to method SetField | +| Fields.cs:114:9:114:22 | SSA qualifier def(this.Field.Field.xs) | Fields.cs:114:9:114:22 | call to method SetField | +| OutRef.cs:7:10:7:10 | SSA entry def(this.Field) | OutRef.cs:7:10:7:10 | M | +| OutRef.cs:9:13:9:17 | SSA def(j) | OutRef.cs:9:13:9:17 | Int32 j = ... | +| OutRef.cs:10:25:10:25 | SSA def(i) | OutRef.cs:10:9:10:33 | call to method OutRefM | +| OutRef.cs:10:32:10:32 | SSA def(j) | OutRef.cs:10:9:10:33 | call to method OutRefM | +| OutRef.cs:13:21:13:21 | SSA def(i) | OutRef.cs:13:9:13:33 | call to method OutRefM | +| OutRef.cs:13:28:13:32 | SSA def(this.Field) | OutRef.cs:13:9:13:33 | call to method OutRefM | +| OutRef.cs:16:21:16:25 | SSA def(this.Field) | OutRef.cs:16:9:16:37 | call to method OutRefM | +| OutRef.cs:18:13:18:28 | SSA def(t) | OutRef.cs:18:13:18:28 | OutRef t = ... | +| OutRef.cs:18:13:18:28 | SSA qualifier def(t.Field) | OutRef.cs:18:13:18:28 | OutRef t = ... | +| OutRef.cs:19:21:19:25 | SSA def(this.Field) | OutRef.cs:19:9:19:39 | call to method OutRefM | +| OutRef.cs:19:32:19:38 | SSA def(t.Field) | OutRef.cs:19:9:19:39 | call to method OutRefM | +| OutRef.cs:22:22:22:22 | SSA def(j) | OutRef.cs:22:9:22:30 | call to method OutRefM2 | +| OutRef.cs:24:29:24:29 | SSA def(j) | OutRef.cs:24:9:24:30 | call to method OutRefM3 | +| OutRef.cs:28:37:28:37 | SSA param(j) | OutRef.cs:28:37:28:37 | j | +| OutRef.cs:30:9:30:13 | SSA def(i) | OutRef.cs:30:9:30:13 | ... = ... | +| OutRef.cs:31:9:31:13 | SSA def(j) | OutRef.cs:31:9:31:13 | ... = ... | +| OutRef.cs:34:38:34:38 | SSA param(j) | OutRef.cs:34:38:34:38 | j | +| OutRef.cs:36:9:36:13 | SSA def(i) | OutRef.cs:36:9:36:13 | ... = ... | +| OutRef.cs:39:24:39:24 | SSA param(b) | OutRef.cs:39:24:39:24 | b | +| OutRef.cs:39:35:39:35 | SSA param(j) | OutRef.cs:39:35:39:35 | j | +| OutRef.cs:42:13:42:17 | SSA def(j) | OutRef.cs:42:13:42:17 | ... = ... | +| Patterns.cs:7:16:7:23 | SSA def(o) | Patterns.cs:7:16:7:23 | Object o = ... | +| Patterns.cs:8:18:8:23 | SSA def(i1) | Patterns.cs:8:18:8:23 | Int32 i1 | +| Patterns.cs:12:23:12:31 | SSA def(s1) | Patterns.cs:12:23:12:31 | String s1 | +| Patterns.cs:24:18:24:23 | SSA def(i2) | Patterns.cs:24:18:24:23 | Int32 i2 | +| Patterns.cs:27:18:27:23 | SSA def(i3) | Patterns.cs:27:18:27:23 | Int32 i3 | +| Patterns.cs:30:18:30:26 | SSA def(s2) | Patterns.cs:30:18:30:26 | String s2 | +| Properties.cs:16:17:16:17 | SSA entry def(this.xs) | Properties.cs:16:17:16:17 | F | +| Properties.cs:19:9:19:13 | SSA call def(this.xs) | Properties.cs:19:9:19:13 | call to method Upd | +| Properties.cs:20:9:20:14 | SSA def(x) | Properties.cs:20:9:20:14 | ... = ... | +| Properties.cs:22:13:22:17 | SSA call def(this.xs) | Properties.cs:22:13:22:17 | call to method Upd | +| Properties.cs:24:9:24:23 | SSA def(this.xs) | Properties.cs:24:9:24:23 | ... = ... | +| Properties.cs:28:17:28:17 | SSA entry def(Properties.stat) | Properties.cs:28:17:28:17 | G | +| Properties.cs:28:17:28:17 | SSA entry def(this.xs) | Properties.cs:28:17:28:17 | G | +| Properties.cs:30:13:30:32 | SSA def(f) | Properties.cs:30:13:30:32 | Properties f = ... | +| Properties.cs:30:13:30:32 | SSA qualifier def(f.xs) | Properties.cs:30:13:30:32 | Properties f = ... | +| Properties.cs:30:17:30:32 | SSA call def(Properties.stat) | Properties.cs:30:17:30:32 | object creation of type Properties | +| Properties.cs:34:9:34:16 | SSA call def(Properties.stat) | Properties.cs:34:9:34:16 | call to method F | +| Properties.cs:34:9:34:16 | SSA call def(f.xs) | Properties.cs:34:9:34:16 | call to method F | +| Properties.cs:34:9:34:16 | SSA call def(this.xs) | Properties.cs:34:9:34:16 | call to method F | +| Properties.cs:38:9:38:13 | SSA call def(Properties.stat) | Properties.cs:38:9:38:13 | call to method F | +| Properties.cs:38:9:38:13 | SSA call def(f.xs) | Properties.cs:38:9:38:13 | call to method F | +| Properties.cs:38:9:38:13 | SSA call def(this.xs) | Properties.cs:38:9:38:13 | call to method F | +| Properties.cs:42:9:42:23 | SSA def(this.xs) | Properties.cs:42:9:42:23 | ... = ... | +| Properties.cs:45:9:45:25 | SSA def(f.xs) | Properties.cs:45:9:45:25 | ... = ... | +| Properties.cs:47:9:47:14 | SSA def(z) | Properties.cs:47:9:47:14 | ... = ... | +| Properties.cs:49:13:49:32 | SSA def(f) | Properties.cs:49:13:49:32 | ... = ... | +| Properties.cs:49:13:49:32 | SSA qualifier def(f.xs) | Properties.cs:49:13:49:32 | ... = ... | +| Properties.cs:49:17:49:32 | SSA call def(Properties.stat) | Properties.cs:49:17:49:32 | object creation of type Properties | +| Properties.cs:51:9:51:24 | SSA call def(Properties.stat) | Properties.cs:51:9:51:24 | object creation of type Properties | +| Properties.cs:61:17:61:17 | SSA entry def(this.LoopProp) | Properties.cs:61:17:61:17 | H | +| Properties.cs:61:23:61:23 | SSA param(i) | Properties.cs:61:23:61:23 | i | +| Properties.cs:63:16:63:18 | SSA def(i) | Properties.cs:63:16:63:18 | ...-- | +| Properties.cs:67:21:67:38 | SSA untracked def(this.SingleAccessedProp) | Properties.cs:67:21:67:38 | this access | +| Properties.cs:72:20:72:37 | SSA untracked def(this.SingleAccessedProp) | Properties.cs:72:20:72:37 | this access | +| Properties.cs:73:13:73:32 | SSA def(f) | Properties.cs:73:13:73:32 | Properties f = ... | +| Properties.cs:74:23:74:54 | SSA def(a) | Properties.cs:74:23:74:54 | Action a = ... | +| Properties.cs:74:27:74:54 | SSA capture def(f) | Properties.cs:74:27:74:54 | (...) => ... | +| Properties.cs:75:23:75:35 | SSA def(b) | Properties.cs:75:23:75:35 | Action b = ... | +| Properties.cs:76:9:76:25 | SSA def(f.xs) | Properties.cs:76:9:76:25 | ... = ... | +| Properties.cs:77:9:77:11 | SSA call def(f.xs) | Properties.cs:77:9:77:11 | delegate call | +| Properties.cs:79:9:79:25 | SSA def(f.xs) | Properties.cs:79:9:79:25 | ... = ... | +| Properties.cs:81:9:81:22 | SSA def(this.xs) | Properties.cs:81:9:81:22 | ... = ... | +| Properties.cs:82:9:82:47 | SSA call def(f.xs) | Properties.cs:82:9:82:47 | call to method Select | +| Properties.cs:82:24:82:46 | SSA capture def(a) | Properties.cs:82:24:82:46 | (...) => ... | +| Properties.cs:83:9:83:22 | SSA def(this.xs) | Properties.cs:83:9:83:22 | ... = ... | +| Properties.cs:84:9:84:25 | SSA def(f.xs) | Properties.cs:84:9:84:25 | ... = ... | +| Properties.cs:85:24:85:46 | SSA capture def(b) | Properties.cs:85:24:85:46 | (...) => ... | +| Properties.cs:95:20:95:38 | SSA untracked def(this.NonTrivialProp) | Properties.cs:95:20:95:23 | this access | +| Properties.cs:98:16:98:31 | SSA untracked def(this.VirtualProp) | Properties.cs:98:16:98:19 | this access | +| Properties.cs:100:9:100:26 | SSA untracked def(this.VolatileField) | Properties.cs:100:9:100:12 | this access | +| Properties.cs:101:21:101:38 | SSA untracked def(this.VolatileField) | Properties.cs:101:21:101:24 | this access | +| Properties.cs:101:21:101:41 | SSA untracked def(this.VolatileField.xs) | Properties.cs:101:21:101:38 | access to field VolatileField | +| Properties.cs:106:37:106:37 | SSA param(p) | Properties.cs:106:37:106:37 | p | +| Properties.cs:108:10:108:10 | SSA entry def(this.Props) | Properties.cs:108:10:108:10 | K | +| Properties.cs:108:10:108:10 | SSA entry def(this.Props.Props) | Properties.cs:108:10:108:10 | K | +| Properties.cs:108:10:108:10 | SSA entry def(this.Props.Props.xs) | Properties.cs:108:10:108:10 | K | +| Properties.cs:113:9:113:22 | SSA call def(this.Props) | Properties.cs:113:9:113:22 | call to method SetProps | +| Properties.cs:113:9:113:22 | SSA call def(this.Props.Props) | Properties.cs:113:9:113:22 | call to method SetProps | +| Properties.cs:113:9:113:22 | SSA qualifier def(this.Props.Props.xs) | Properties.cs:113:9:113:22 | call to method SetProps | +| Splitting.cs:3:18:3:18 | SSA param(b) | Splitting.cs:3:18:3:18 | b | +| Splitting.cs:7:13:7:19 | [b (line 3): true] SSA def(x) | Splitting.cs:7:13:7:19 | ... = ... | +| Splitting.cs:10:13:10:19 | [b (line 3): false] SSA def(x) | Splitting.cs:10:13:10:19 | ... = ... | +| Splitting.cs:22:18:22:18 | SSA param(b) | Splitting.cs:22:18:22:18 | b | +| Splitting.cs:29:13:29:19 | [b (line 22): false] SSA def(x) | Splitting.cs:29:13:29:19 | ... = ... | +| Splitting.cs:32:9:32:15 | [b (line 22): false] SSA def(x) | Splitting.cs:32:9:32:15 | ... = ... | +| Splitting.cs:32:9:32:15 | [b (line 22): true] SSA def(x) | Splitting.cs:32:9:32:15 | ... = ... | +| Splitting.cs:42:18:42:18 | SSA param(b) | Splitting.cs:42:18:42:18 | b | +| Splitting.cs:46:13:46:19 | [b (line 42): true] SSA def(x) | Splitting.cs:46:13:46:19 | ... = ... | +| Splitting.cs:49:13:49:19 | [b (line 42): false] SSA def(x) | Splitting.cs:49:13:49:19 | ... = ... | +| Test.cs:5:15:5:20 | SSA param(param1) | Test.cs:5:15:5:20 | param1 | +| Test.cs:5:67:5:72 | SSA param(param2) | Test.cs:5:67:5:72 | param2 | +| Test.cs:7:9:7:17 | SSA def(this.field) | Test.cs:7:9:7:17 | ... = ... | +| Test.cs:8:13:8:17 | SSA def(x) | Test.cs:8:13:8:17 | Int32 x = ... | +| Test.cs:13:13:13:15 | SSA def(x) | Test.cs:13:13:13:15 | ...++ | +| Test.cs:14:13:14:19 | SSA def(y) | Test.cs:14:13:14:19 | ... = ... | +| Test.cs:14:17:14:19 | SSA def(x) | Test.cs:14:17:14:19 | ++... | +| Test.cs:15:13:15:17 | SSA def(z) | Test.cs:15:13:15:17 | ... = ... | +| Test.cs:19:13:19:17 | SSA def(y) | Test.cs:19:13:19:17 | ... = ... | +| Test.cs:20:13:20:18 | SSA def(y) | Test.cs:20:13:20:18 | ... = ... | +| Test.cs:21:13:21:22 | SSA def(this.field) | Test.cs:21:13:21:22 | ... = ... | +| Test.cs:22:13:22:17 | SSA def(z) | Test.cs:22:13:22:17 | ... = ... | +| Test.cs:27:17:27:24 | SSA def(param1) | Test.cs:27:17:27:24 | ...++ | +| Test.cs:31:13:31:18 | SSA def(y) | Test.cs:31:13:31:18 | ... = ... | +| Test.cs:34:18:34:22 | SSA def(i) | Test.cs:34:18:34:22 | Int32 i = ... | +| Test.cs:34:33:34:35 | SSA def(i) | Test.cs:34:33:34:35 | ...++ | +| Test.cs:36:13:36:18 | SSA def(x) | Test.cs:36:13:36:18 | ... = ... | +| Test.cs:39:22:39:22 | SSA def(w) | Test.cs:39:22:39:22 | Int32 w | +| Test.cs:41:13:41:23 | SSA def(param1) | Test.cs:41:13:41:23 | ... = ... | +| Test.cs:46:10:46:10 | SSA entry def(this.field) | Test.cs:46:10:46:10 | g | +| Test.cs:46:16:46:18 | SSA param(in) | Test.cs:46:16:46:18 | in | +| Test.cs:50:13:50:20 | SSA def(out) | Test.cs:50:13:50:20 | ... = ... | +| Test.cs:54:13:54:20 | SSA def(out) | Test.cs:54:13:54:20 | ... = ... | +| Test.cs:57:9:57:17 | SSA def(this.field) | Test.cs:57:9:57:17 | ... = ... | +| Test.cs:68:45:68:45 | [exception: DivideByZeroException] SSA def(e) | Test.cs:68:45:68:45 | DivideByZeroException e | +| Tuples.cs:10:9:10:54 | SSA def(b) | Tuples.cs:10:9:10:54 | ... = ... | +| Tuples.cs:10:9:10:54 | SSA def(s) | Tuples.cs:10:9:10:54 | ... = ... | +| Tuples.cs:10:9:10:54 | SSA def(x) | Tuples.cs:10:9:10:54 | ... = ... | +| Tuples.cs:14:9:14:32 | SSA def(b) | Tuples.cs:14:9:14:32 | ... = ... | +| Tuples.cs:14:9:14:32 | SSA def(s) | Tuples.cs:14:9:14:32 | ... = ... | +| Tuples.cs:14:9:14:32 | SSA def(x) | Tuples.cs:14:9:14:32 | ... = ... | +| Tuples.cs:18:40:18:57 | SSA def(tuple) | Tuples.cs:18:40:18:57 | (Int32,(Boolean,String)) tuple = ... | +| Tuples.cs:20:9:20:34 | SSA def(this.Field) | Tuples.cs:20:9:20:34 | ... = ... | +| Tuples.cs:20:9:20:34 | SSA def(this.Property) | Tuples.cs:20:9:20:34 | ... = ... | +| Tuples.cs:23:9:23:37 | SSA def(x) | Tuples.cs:23:9:23:37 | ... = ... | +| Tuples.cs:25:13:25:28 | SSA def(t) | Tuples.cs:25:13:25:28 | Tuples t = ... | +| Tuples.cs:26:9:26:33 | SSA def(t.Field) | Tuples.cs:26:9:26:33 | ... = ... | +| Tuples.cs:26:9:26:33 | SSA def(this.Field) | Tuples.cs:26:9:26:33 | ... = ... | diff --git a/csharp/ql/test/library-tests/dataflow/ssa/SsaDefElement.ql b/csharp/ql/test/library-tests/dataflow/ssa/SsaDefElement.ql new file mode 100644 index 00000000000..e404aee7767 --- /dev/null +++ b/csharp/ql/test/library-tests/dataflow/ssa/SsaDefElement.ql @@ -0,0 +1,4 @@ +import csharp + +from Ssa::Definition def +select def, def.getElement() From f768abb0e62c0af5e2ce60972a5305250849fa27 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Fri, 4 Jan 2019 10:43:19 +0100 Subject: [PATCH 04/33] C#: Add data flow test with CFG splitting --- .../dataflow/global/DataFlow.expected | 76 ++++----- .../library-tests/dataflow/global/DataFlow.ql | 8 +- .../dataflow/global/DataFlowPath.expected | 87 +++++----- .../dataflow/global/DataFlowPath.ql | 2 +- .../dataflow/global/Splitting.cs | 17 ++ .../dataflow/global/TaintTracking.expected | 108 ++++++------- .../dataflow/global/TaintTracking.ql | 8 +- .../global/TaintTrackingPath.expected | 119 +++++++------- .../dataflow/global/TaintTrackingPath.ql | 2 +- .../dataflow/local/DataFlow.expected | 43 ++--- .../library-tests/dataflow/local/DataFlow.ql | 16 +- .../dataflow/local/DataFlowStep.expected | 82 ++++++++-- .../dataflow/local/LocalDataFlow.cs | 6 +- .../library-tests/dataflow/local/Splitting.cs | 66 ++++++++ .../dataflow/local/TaintTracking.expected | 149 +++++++++--------- .../dataflow/local/TaintTracking.ql | 16 +- .../dataflow/local/TaintTrackingStep.expected | 107 +++++++++++-- 17 files changed, 588 insertions(+), 324 deletions(-) create mode 100644 csharp/ql/test/library-tests/dataflow/global/Splitting.cs create mode 100644 csharp/ql/test/library-tests/dataflow/local/Splitting.cs diff --git a/csharp/ql/test/library-tests/dataflow/global/DataFlow.expected b/csharp/ql/test/library-tests/dataflow/global/DataFlow.expected index 57084e1b711..13d0656a168 100644 --- a/csharp/ql/test/library-tests/dataflow/global/DataFlow.expected +++ b/csharp/ql/test/library-tests/dataflow/global/DataFlow.expected @@ -1,37 +1,39 @@ -| access to field SinkField0 | -| access to local variable sink0 | -| access to local variable sink1 | -| access to local variable sink10 | -| access to local variable sink11 | -| access to local variable sink19 | -| access to local variable sink2 | -| access to local variable sink20 | -| access to local variable sink23 | -| access to local variable sink27 | -| access to local variable sink28 | -| access to local variable sink29 | -| access to local variable sink3 | -| access to local variable sink30 | -| access to local variable sink31 | -| access to local variable sink32 | -| access to local variable sink33 | -| access to local variable sink34 | -| access to local variable sink35 | -| access to local variable sink36 | -| access to local variable sink37 | -| access to local variable sink38 | -| access to local variable sink4 | -| access to local variable sink5 | -| access to local variable sink6 | -| access to local variable sink7 | -| access to local variable sink8 | -| access to local variable sink9 | -| access to parameter sinkParam0 | -| access to parameter sinkParam1 | -| access to parameter sinkParam2 | -| access to parameter sinkParam3 | -| access to parameter sinkParam4 | -| access to parameter sinkParam5 | -| access to parameter sinkParam6 | -| access to parameter sinkParam7 | -| access to property SinkProperty0 | +| Capture.cs:12:19:12:24 | access to local variable sink27 | +| Capture.cs:21:23:21:28 | access to local variable sink28 | +| Capture.cs:30:19:30:24 | access to local variable sink29 | +| Capture.cs:60:15:60:20 | access to local variable sink30 | +| Capture.cs:72:15:72:20 | access to local variable sink31 | +| Capture.cs:81:15:81:20 | access to local variable sink32 | +| Capture.cs:109:15:109:20 | access to local variable sink33 | +| Capture.cs:121:15:121:20 | access to local variable sink34 | +| Capture.cs:130:15:130:20 | access to local variable sink35 | +| Capture.cs:137:15:137:20 | access to local variable sink36 | +| Capture.cs:145:15:145:20 | access to local variable sink37 | +| Capture.cs:171:15:171:20 | access to local variable sink38 | +| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 | +| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 | +| GlobalDataFlow.cs:44:50:44:59 | access to parameter sinkParam2 | +| GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 | +| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 | +| GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 | +| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 | +| GlobalDataFlow.cs:132:15:132:19 | access to local variable sink4 | +| GlobalDataFlow.cs:140:15:140:19 | access to local variable sink5 | +| GlobalDataFlow.cs:150:15:150:19 | access to local variable sink6 | +| GlobalDataFlow.cs:153:15:153:19 | access to local variable sink7 | +| GlobalDataFlow.cs:156:15:156:19 | access to local variable sink8 | +| GlobalDataFlow.cs:160:15:160:20 | access to local variable sink23 | +| GlobalDataFlow.cs:177:15:177:19 | access to local variable sink9 | +| GlobalDataFlow.cs:186:15:186:20 | access to local variable sink10 | +| GlobalDataFlow.cs:194:15:194:20 | access to local variable sink19 | +| GlobalDataFlow.cs:233:15:233:24 | access to parameter sinkParam0 | +| GlobalDataFlow.cs:238:15:238:24 | access to parameter sinkParam1 | +| GlobalDataFlow.cs:243:15:243:24 | access to parameter sinkParam3 | +| GlobalDataFlow.cs:248:15:248:24 | access to parameter sinkParam4 | +| GlobalDataFlow.cs:253:15:253:24 | access to parameter sinkParam5 | +| GlobalDataFlow.cs:258:15:258:24 | access to parameter sinkParam6 | +| GlobalDataFlow.cs:263:15:263:24 | access to parameter sinkParam7 | +| GlobalDataFlow.cs:376:15:376:20 | access to local variable sink11 | +| GlobalDataFlow.cs:399:41:399:46 | access to local variable sink20 | +| Splitting.cs:9:15:9:15 | access to local variable x | +| Splitting.cs:11:19:11:19 | access to local variable x | diff --git a/csharp/ql/test/library-tests/dataflow/global/DataFlow.ql b/csharp/ql/test/library-tests/dataflow/global/DataFlow.ql index efc827dd6e6..62cfb8e7dc2 100644 --- a/csharp/ql/test/library-tests/dataflow/global/DataFlow.ql +++ b/csharp/ql/test/library-tests/dataflow/global/DataFlow.ql @@ -1,8 +1,6 @@ import csharp import Common -from Config c, DataFlow::Node source, DataFlow::Node sink, string s -where - c.hasFlow(source, sink) and - s = sink.toString() -select s order by s +from Config c, DataFlow::Node source, DataFlow::Node sink +where c.hasFlow(source, sink) +select sink diff --git a/csharp/ql/test/library-tests/dataflow/global/DataFlowPath.expected b/csharp/ql/test/library-tests/dataflow/global/DataFlowPath.expected index d02b28059d6..0b0c2deb051 100644 --- a/csharp/ql/test/library-tests/dataflow/global/DataFlowPath.expected +++ b/csharp/ql/test/library-tests/dataflow/global/DataFlowPath.expected @@ -172,6 +172,10 @@ edges | GlobalDataFlow.cs:377:16:377:21 | access to local variable sink11 | GlobalDataFlow.cs:159:22:159:43 | call to method TaintedParam | | GlobalDataFlow.cs:399:9:399:11 | value | GlobalDataFlow.cs:399:41:399:46 | access to local variable sink20 | | GlobalDataFlow.cs:410:22:410:35 | "taint source" | GlobalDataFlow.cs:193:22:193:32 | access to property OutProperty | +| Splitting.cs:3:28:3:34 | tainted | Splitting.cs:8:24:8:30 | access to parameter tainted | +| Splitting.cs:8:17:8:31 | call to method Return | Splitting.cs:9:15:9:15 | access to local variable x | +| Splitting.cs:8:17:8:31 | call to method Return | Splitting.cs:11:19:11:19 | access to local variable x | +| Splitting.cs:8:24:8:30 | access to parameter tainted | Splitting.cs:8:17:8:31 | call to method Return | nodes | Capture.cs:7:20:7:26 | tainted | | Capture.cs:9:9:13:9 | SSA capture def(tainted) | @@ -302,42 +306,49 @@ nodes | GlobalDataFlow.cs:399:9:399:11 | value | | GlobalDataFlow.cs:399:41:399:46 | access to local variable sink20 | | GlobalDataFlow.cs:410:22:410:35 | "taint source" | +| Splitting.cs:3:28:3:34 | tainted | +| Splitting.cs:8:17:8:31 | call to method Return | +| Splitting.cs:8:24:8:30 | access to parameter tainted | +| Splitting.cs:9:15:9:15 | access to local variable x | +| Splitting.cs:11:19:11:19 | access to local variable x | #select -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 | access to field SinkField0 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 | -| GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 | access to local variable sink0 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 | access to local variable sink1 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 | -| GlobalDataFlow.cs:186:15:186:20 | access to local variable sink10 | access to local variable sink10 | GlobalDataFlow.cs:313:16:313:29 | "taint source" | GlobalDataFlow.cs:186:15:186:20 | access to local variable sink10 | -| GlobalDataFlow.cs:376:15:376:20 | access to local variable sink11 | access to local variable sink11 | GlobalDataFlow.cs:373:39:373:45 | tainted | GlobalDataFlow.cs:376:15:376:20 | access to local variable sink11 | -| GlobalDataFlow.cs:194:15:194:20 | access to local variable sink19 | access to local variable sink19 | GlobalDataFlow.cs:410:22:410:35 | "taint source" | GlobalDataFlow.cs:194:15:194:20 | access to local variable sink19 | -| GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 | access to local variable sink2 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 | -| GlobalDataFlow.cs:399:41:399:46 | access to local variable sink20 | access to local variable sink20 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:399:41:399:46 | access to local variable sink20 | -| GlobalDataFlow.cs:160:15:160:20 | access to local variable sink23 | access to local variable sink23 | GlobalDataFlow.cs:373:39:373:45 | tainted | GlobalDataFlow.cs:160:15:160:20 | access to local variable sink23 | -| Capture.cs:12:19:12:24 | access to local variable sink27 | access to local variable sink27 | Capture.cs:7:20:7:26 | tainted | Capture.cs:12:19:12:24 | access to local variable sink27 | -| Capture.cs:21:23:21:28 | access to local variable sink28 | access to local variable sink28 | Capture.cs:7:20:7:26 | tainted | Capture.cs:21:23:21:28 | access to local variable sink28 | -| Capture.cs:30:19:30:24 | access to local variable sink29 | access to local variable sink29 | Capture.cs:7:20:7:26 | tainted | Capture.cs:30:19:30:24 | access to local variable sink29 | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 | access to local variable sink3 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 | -| Capture.cs:60:15:60:20 | access to local variable sink30 | access to local variable sink30 | Capture.cs:57:22:57:35 | "taint source" | Capture.cs:60:15:60:20 | access to local variable sink30 | -| Capture.cs:72:15:72:20 | access to local variable sink31 | access to local variable sink31 | Capture.cs:67:26:67:39 | "taint source" | Capture.cs:72:15:72:20 | access to local variable sink31 | -| Capture.cs:81:15:81:20 | access to local variable sink32 | access to local variable sink32 | Capture.cs:77:22:77:35 | "taint source" | Capture.cs:81:15:81:20 | access to local variable sink32 | -| Capture.cs:109:15:109:20 | access to local variable sink33 | access to local variable sink33 | Capture.cs:101:25:101:31 | tainted | Capture.cs:109:15:109:20 | access to local variable sink33 | -| Capture.cs:121:15:121:20 | access to local variable sink34 | access to local variable sink34 | Capture.cs:101:25:101:31 | tainted | Capture.cs:121:15:121:20 | access to local variable sink34 | -| Capture.cs:130:15:130:20 | access to local variable sink35 | access to local variable sink35 | Capture.cs:101:25:101:31 | tainted | Capture.cs:130:15:130:20 | access to local variable sink35 | -| Capture.cs:137:15:137:20 | access to local variable sink36 | access to local variable sink36 | Capture.cs:101:25:101:31 | tainted | Capture.cs:137:15:137:20 | access to local variable sink36 | -| Capture.cs:145:15:145:20 | access to local variable sink37 | access to local variable sink37 | Capture.cs:101:25:101:31 | tainted | Capture.cs:145:15:145:20 | access to local variable sink37 | -| Capture.cs:171:15:171:20 | access to local variable sink38 | access to local variable sink38 | Capture.cs:101:25:101:31 | tainted | Capture.cs:171:15:171:20 | access to local variable sink38 | -| GlobalDataFlow.cs:132:15:132:19 | access to local variable sink4 | access to local variable sink4 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:132:15:132:19 | access to local variable sink4 | -| GlobalDataFlow.cs:140:15:140:19 | access to local variable sink5 | access to local variable sink5 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:140:15:140:19 | access to local variable sink5 | -| GlobalDataFlow.cs:150:15:150:19 | access to local variable sink6 | access to local variable sink6 | GlobalDataFlow.cs:313:16:313:29 | "taint source" | GlobalDataFlow.cs:150:15:150:19 | access to local variable sink6 | -| GlobalDataFlow.cs:153:15:153:19 | access to local variable sink7 | access to local variable sink7 | GlobalDataFlow.cs:318:13:318:26 | "taint source" | GlobalDataFlow.cs:153:15:153:19 | access to local variable sink7 | -| GlobalDataFlow.cs:156:15:156:19 | access to local variable sink8 | access to local variable sink8 | GlobalDataFlow.cs:323:13:323:26 | "taint source" | GlobalDataFlow.cs:156:15:156:19 | access to local variable sink8 | -| GlobalDataFlow.cs:177:15:177:19 | access to local variable sink9 | access to local variable sink9 | GlobalDataFlow.cs:175:35:175:48 | "taint source" | GlobalDataFlow.cs:177:15:177:19 | access to local variable sink9 | -| GlobalDataFlow.cs:233:15:233:24 | access to parameter sinkParam0 | access to parameter sinkParam0 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:233:15:233:24 | access to parameter sinkParam0 | -| GlobalDataFlow.cs:233:15:233:24 | access to parameter sinkParam0 | access to parameter sinkParam0 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:233:15:233:24 | access to parameter sinkParam0 | -| GlobalDataFlow.cs:238:15:238:24 | access to parameter sinkParam1 | access to parameter sinkParam1 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:238:15:238:24 | access to parameter sinkParam1 | -| GlobalDataFlow.cs:44:50:44:59 | access to parameter sinkParam2 | access to parameter sinkParam2 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:44:50:44:59 | access to parameter sinkParam2 | -| GlobalDataFlow.cs:243:15:243:24 | access to parameter sinkParam3 | access to parameter sinkParam3 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:243:15:243:24 | access to parameter sinkParam3 | -| GlobalDataFlow.cs:248:15:248:24 | access to parameter sinkParam4 | access to parameter sinkParam4 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:248:15:248:24 | access to parameter sinkParam4 | -| GlobalDataFlow.cs:253:15:253:24 | access to parameter sinkParam5 | access to parameter sinkParam5 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:253:15:253:24 | access to parameter sinkParam5 | -| GlobalDataFlow.cs:258:15:258:24 | access to parameter sinkParam6 | access to parameter sinkParam6 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:258:15:258:24 | access to parameter sinkParam6 | -| GlobalDataFlow.cs:263:15:263:24 | access to parameter sinkParam7 | access to parameter sinkParam7 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:263:15:263:24 | access to parameter sinkParam7 | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 | access to property SinkProperty0 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 | +| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 | access to field SinkField0 | +| GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 | access to local variable sink0 | +| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 | access to local variable sink1 | +| GlobalDataFlow.cs:186:15:186:20 | access to local variable sink10 | GlobalDataFlow.cs:313:16:313:29 | "taint source" | GlobalDataFlow.cs:186:15:186:20 | access to local variable sink10 | access to local variable sink10 | +| GlobalDataFlow.cs:376:15:376:20 | access to local variable sink11 | GlobalDataFlow.cs:373:39:373:45 | tainted | GlobalDataFlow.cs:376:15:376:20 | access to local variable sink11 | access to local variable sink11 | +| GlobalDataFlow.cs:194:15:194:20 | access to local variable sink19 | GlobalDataFlow.cs:410:22:410:35 | "taint source" | GlobalDataFlow.cs:194:15:194:20 | access to local variable sink19 | access to local variable sink19 | +| GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 | access to local variable sink2 | +| GlobalDataFlow.cs:399:41:399:46 | access to local variable sink20 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:399:41:399:46 | access to local variable sink20 | access to local variable sink20 | +| GlobalDataFlow.cs:160:15:160:20 | access to local variable sink23 | GlobalDataFlow.cs:373:39:373:45 | tainted | GlobalDataFlow.cs:160:15:160:20 | access to local variable sink23 | access to local variable sink23 | +| Capture.cs:12:19:12:24 | access to local variable sink27 | Capture.cs:7:20:7:26 | tainted | Capture.cs:12:19:12:24 | access to local variable sink27 | access to local variable sink27 | +| Capture.cs:21:23:21:28 | access to local variable sink28 | Capture.cs:7:20:7:26 | tainted | Capture.cs:21:23:21:28 | access to local variable sink28 | access to local variable sink28 | +| Capture.cs:30:19:30:24 | access to local variable sink29 | Capture.cs:7:20:7:26 | tainted | Capture.cs:30:19:30:24 | access to local variable sink29 | access to local variable sink29 | +| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 | access to local variable sink3 | +| Capture.cs:60:15:60:20 | access to local variable sink30 | Capture.cs:57:22:57:35 | "taint source" | Capture.cs:60:15:60:20 | access to local variable sink30 | access to local variable sink30 | +| Capture.cs:72:15:72:20 | access to local variable sink31 | Capture.cs:67:26:67:39 | "taint source" | Capture.cs:72:15:72:20 | access to local variable sink31 | access to local variable sink31 | +| Capture.cs:81:15:81:20 | access to local variable sink32 | Capture.cs:77:22:77:35 | "taint source" | Capture.cs:81:15:81:20 | access to local variable sink32 | access to local variable sink32 | +| Capture.cs:109:15:109:20 | access to local variable sink33 | Capture.cs:101:25:101:31 | tainted | Capture.cs:109:15:109:20 | access to local variable sink33 | access to local variable sink33 | +| Capture.cs:121:15:121:20 | access to local variable sink34 | Capture.cs:101:25:101:31 | tainted | Capture.cs:121:15:121:20 | access to local variable sink34 | access to local variable sink34 | +| Capture.cs:130:15:130:20 | access to local variable sink35 | Capture.cs:101:25:101:31 | tainted | Capture.cs:130:15:130:20 | access to local variable sink35 | access to local variable sink35 | +| Capture.cs:137:15:137:20 | access to local variable sink36 | Capture.cs:101:25:101:31 | tainted | Capture.cs:137:15:137:20 | access to local variable sink36 | access to local variable sink36 | +| Capture.cs:145:15:145:20 | access to local variable sink37 | Capture.cs:101:25:101:31 | tainted | Capture.cs:145:15:145:20 | access to local variable sink37 | access to local variable sink37 | +| Capture.cs:171:15:171:20 | access to local variable sink38 | Capture.cs:101:25:101:31 | tainted | Capture.cs:171:15:171:20 | access to local variable sink38 | access to local variable sink38 | +| GlobalDataFlow.cs:132:15:132:19 | access to local variable sink4 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:132:15:132:19 | access to local variable sink4 | access to local variable sink4 | +| GlobalDataFlow.cs:140:15:140:19 | access to local variable sink5 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:140:15:140:19 | access to local variable sink5 | access to local variable sink5 | +| GlobalDataFlow.cs:150:15:150:19 | access to local variable sink6 | GlobalDataFlow.cs:313:16:313:29 | "taint source" | GlobalDataFlow.cs:150:15:150:19 | access to local variable sink6 | access to local variable sink6 | +| GlobalDataFlow.cs:153:15:153:19 | access to local variable sink7 | GlobalDataFlow.cs:318:13:318:26 | "taint source" | GlobalDataFlow.cs:153:15:153:19 | access to local variable sink7 | access to local variable sink7 | +| GlobalDataFlow.cs:156:15:156:19 | access to local variable sink8 | GlobalDataFlow.cs:323:13:323:26 | "taint source" | GlobalDataFlow.cs:156:15:156:19 | access to local variable sink8 | access to local variable sink8 | +| GlobalDataFlow.cs:177:15:177:19 | access to local variable sink9 | GlobalDataFlow.cs:175:35:175:48 | "taint source" | GlobalDataFlow.cs:177:15:177:19 | access to local variable sink9 | access to local variable sink9 | +| Splitting.cs:9:15:9:15 | access to local variable x | Splitting.cs:3:28:3:34 | tainted | Splitting.cs:9:15:9:15 | access to local variable x | access to local variable x | +| Splitting.cs:11:19:11:19 | access to local variable x | Splitting.cs:3:28:3:34 | tainted | Splitting.cs:11:19:11:19 | access to local variable x | access to local variable x | +| GlobalDataFlow.cs:233:15:233:24 | access to parameter sinkParam0 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:233:15:233:24 | access to parameter sinkParam0 | access to parameter sinkParam0 | +| GlobalDataFlow.cs:233:15:233:24 | access to parameter sinkParam0 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:233:15:233:24 | access to parameter sinkParam0 | access to parameter sinkParam0 | +| GlobalDataFlow.cs:238:15:238:24 | access to parameter sinkParam1 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:238:15:238:24 | access to parameter sinkParam1 | access to parameter sinkParam1 | +| GlobalDataFlow.cs:44:50:44:59 | access to parameter sinkParam2 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:44:50:44:59 | access to parameter sinkParam2 | access to parameter sinkParam2 | +| GlobalDataFlow.cs:243:15:243:24 | access to parameter sinkParam3 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:243:15:243:24 | access to parameter sinkParam3 | access to parameter sinkParam3 | +| GlobalDataFlow.cs:248:15:248:24 | access to parameter sinkParam4 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:248:15:248:24 | access to parameter sinkParam4 | access to parameter sinkParam4 | +| GlobalDataFlow.cs:253:15:253:24 | access to parameter sinkParam5 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:253:15:253:24 | access to parameter sinkParam5 | access to parameter sinkParam5 | +| GlobalDataFlow.cs:258:15:258:24 | access to parameter sinkParam6 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:258:15:258:24 | access to parameter sinkParam6 | access to parameter sinkParam6 | +| GlobalDataFlow.cs:263:15:263:24 | access to parameter sinkParam7 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:263:15:263:24 | access to parameter sinkParam7 | access to parameter sinkParam7 | +| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 | access to property SinkProperty0 | diff --git a/csharp/ql/test/library-tests/dataflow/global/DataFlowPath.ql b/csharp/ql/test/library-tests/dataflow/global/DataFlowPath.ql index a995769f0ed..fd042e29be3 100644 --- a/csharp/ql/test/library-tests/dataflow/global/DataFlowPath.ql +++ b/csharp/ql/test/library-tests/dataflow/global/DataFlowPath.ql @@ -10,4 +10,4 @@ from Config c, DataFlow::PathNode source, DataFlow::PathNode sink, string s where c.hasFlowPath(source, sink) and s = sink.toString() -select sink, s, source, sink order by s +select sink, source, sink, s order by s diff --git a/csharp/ql/test/library-tests/dataflow/global/Splitting.cs b/csharp/ql/test/library-tests/dataflow/global/Splitting.cs new file mode 100644 index 00000000000..f313dafc65b --- /dev/null +++ b/csharp/ql/test/library-tests/dataflow/global/Splitting.cs @@ -0,0 +1,17 @@ +class Splitting +{ + void M1(bool b, string tainted) + { + if (b) + if (tainted == null) + return; + var x = Return(tainted); + Check(x); + if (b) + Check(x); + } + + static void Check(T x) { } + + static T Return(T x) => x; +} diff --git a/csharp/ql/test/library-tests/dataflow/global/TaintTracking.expected b/csharp/ql/test/library-tests/dataflow/global/TaintTracking.expected index 7fe5b2cb1de..404e468b421 100644 --- a/csharp/ql/test/library-tests/dataflow/global/TaintTracking.expected +++ b/csharp/ql/test/library-tests/dataflow/global/TaintTracking.expected @@ -1,53 +1,55 @@ -| access to field SinkField0 | -| access to local variable sink0 | -| access to local variable sink1 | -| access to local variable sink10 | -| access to local variable sink11 | -| access to local variable sink12 | -| access to local variable sink13 | -| access to local variable sink14 | -| access to local variable sink15 | -| access to local variable sink16 | -| access to local variable sink17 | -| access to local variable sink18 | -| access to local variable sink19 | -| access to local variable sink2 | -| access to local variable sink20 | -| access to local variable sink21 | -| access to local variable sink22 | -| access to local variable sink23 | -| access to local variable sink24 | -| access to local variable sink25 | -| access to local variable sink26 | -| access to local variable sink27 | -| access to local variable sink28 | -| access to local variable sink29 | -| access to local variable sink3 | -| access to local variable sink30 | -| access to local variable sink31 | -| access to local variable sink32 | -| access to local variable sink33 | -| access to local variable sink34 | -| access to local variable sink35 | -| access to local variable sink36 | -| access to local variable sink37 | -| access to local variable sink38 | -| access to local variable sink4 | -| access to local variable sink5 | -| access to local variable sink6 | -| access to local variable sink7 | -| access to local variable sink8 | -| access to local variable sink9 | -| access to parameter sinkParam0 | -| access to parameter sinkParam1 | -| access to parameter sinkParam10 | -| access to parameter sinkParam11 | -| access to parameter sinkParam2 | -| access to parameter sinkParam3 | -| access to parameter sinkParam4 | -| access to parameter sinkParam5 | -| access to parameter sinkParam6 | -| access to parameter sinkParam7 | -| access to parameter sinkParam8 | -| access to parameter sinkParam9 | -| access to property SinkProperty0 | +| Capture.cs:12:19:12:24 | access to local variable sink27 | +| Capture.cs:21:23:21:28 | access to local variable sink28 | +| Capture.cs:30:19:30:24 | access to local variable sink29 | +| Capture.cs:60:15:60:20 | access to local variable sink30 | +| Capture.cs:72:15:72:20 | access to local variable sink31 | +| Capture.cs:81:15:81:20 | access to local variable sink32 | +| Capture.cs:109:15:109:20 | access to local variable sink33 | +| Capture.cs:121:15:121:20 | access to local variable sink34 | +| Capture.cs:130:15:130:20 | access to local variable sink35 | +| Capture.cs:137:15:137:20 | access to local variable sink36 | +| Capture.cs:145:15:145:20 | access to local variable sink37 | +| Capture.cs:171:15:171:20 | access to local variable sink38 | +| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 | +| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 | +| GlobalDataFlow.cs:44:50:44:59 | access to parameter sinkParam2 | +| GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 | +| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 | +| GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 | +| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 | +| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 | +| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 | +| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 | +| GlobalDataFlow.cs:87:15:87:20 | access to local variable sink16 | +| GlobalDataFlow.cs:89:15:89:20 | access to local variable sink17 | +| GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 | +| GlobalDataFlow.cs:94:15:94:20 | access to local variable sink21 | +| GlobalDataFlow.cs:97:15:97:20 | access to local variable sink22 | +| GlobalDataFlow.cs:132:15:132:19 | access to local variable sink4 | +| GlobalDataFlow.cs:140:15:140:19 | access to local variable sink5 | +| GlobalDataFlow.cs:150:15:150:19 | access to local variable sink6 | +| GlobalDataFlow.cs:153:15:153:19 | access to local variable sink7 | +| GlobalDataFlow.cs:156:15:156:19 | access to local variable sink8 | +| GlobalDataFlow.cs:158:15:158:20 | access to local variable sink12 | +| GlobalDataFlow.cs:160:15:160:20 | access to local variable sink23 | +| GlobalDataFlow.cs:177:15:177:19 | access to local variable sink9 | +| GlobalDataFlow.cs:186:15:186:20 | access to local variable sink10 | +| GlobalDataFlow.cs:194:15:194:20 | access to local variable sink19 | +| GlobalDataFlow.cs:204:58:204:68 | access to parameter sinkParam10 | +| GlobalDataFlow.cs:207:15:207:20 | access to local variable sink24 | +| GlobalDataFlow.cs:209:15:209:20 | access to local variable sink25 | +| GlobalDataFlow.cs:211:15:211:20 | access to local variable sink26 | +| GlobalDataFlow.cs:233:15:233:24 | access to parameter sinkParam0 | +| GlobalDataFlow.cs:238:15:238:24 | access to parameter sinkParam1 | +| GlobalDataFlow.cs:243:15:243:24 | access to parameter sinkParam3 | +| GlobalDataFlow.cs:248:15:248:24 | access to parameter sinkParam4 | +| GlobalDataFlow.cs:253:15:253:24 | access to parameter sinkParam5 | +| GlobalDataFlow.cs:258:15:258:24 | access to parameter sinkParam6 | +| GlobalDataFlow.cs:263:15:263:24 | access to parameter sinkParam7 | +| GlobalDataFlow.cs:289:15:289:24 | access to parameter sinkParam8 | +| GlobalDataFlow.cs:295:15:295:24 | access to parameter sinkParam9 | +| GlobalDataFlow.cs:301:15:301:25 | access to parameter sinkParam11 | +| GlobalDataFlow.cs:376:15:376:20 | access to local variable sink11 | +| GlobalDataFlow.cs:399:41:399:46 | access to local variable sink20 | +| Splitting.cs:9:15:9:15 | access to local variable x | +| Splitting.cs:11:19:11:19 | access to local variable x | diff --git a/csharp/ql/test/library-tests/dataflow/global/TaintTracking.ql b/csharp/ql/test/library-tests/dataflow/global/TaintTracking.ql index d57eb8e1e87..1fc9bb63fc2 100644 --- a/csharp/ql/test/library-tests/dataflow/global/TaintTracking.ql +++ b/csharp/ql/test/library-tests/dataflow/global/TaintTracking.ql @@ -11,8 +11,6 @@ class TTConfig extends TaintTracking::Configuration { override predicate isSink(DataFlow::Node sink) { c.isSink(sink) } } -from TTConfig c, DataFlow::Node source, DataFlow::Node sink, string s -where - c.hasFlow(source, sink) and - s = sink.toString() -select s order by s +from TTConfig c, DataFlow::Node source, DataFlow::Node sink +where c.hasFlow(source, sink) +select sink diff --git a/csharp/ql/test/library-tests/dataflow/global/TaintTrackingPath.expected b/csharp/ql/test/library-tests/dataflow/global/TaintTrackingPath.expected index 7c1c2b73e46..e6dafba170b 100644 --- a/csharp/ql/test/library-tests/dataflow/global/TaintTrackingPath.expected +++ b/csharp/ql/test/library-tests/dataflow/global/TaintTrackingPath.expected @@ -215,6 +215,10 @@ edges | GlobalDataFlow.cs:377:16:377:21 | access to local variable sink11 | GlobalDataFlow.cs:159:22:159:43 | call to method TaintedParam | | GlobalDataFlow.cs:399:9:399:11 | value | GlobalDataFlow.cs:399:41:399:46 | access to local variable sink20 | | GlobalDataFlow.cs:410:22:410:35 | "taint source" | GlobalDataFlow.cs:193:22:193:32 | access to property OutProperty | +| Splitting.cs:3:28:3:34 | tainted | Splitting.cs:8:24:8:30 | access to parameter tainted | +| Splitting.cs:8:17:8:31 | call to method Return | Splitting.cs:9:15:9:15 | access to local variable x | +| Splitting.cs:8:17:8:31 | call to method Return | Splitting.cs:11:19:11:19 | access to local variable x | +| Splitting.cs:8:24:8:30 | access to parameter tainted | Splitting.cs:8:17:8:31 | call to method Return | nodes | Capture.cs:7:20:7:26 | tainted | | Capture.cs:9:9:13:9 | SSA capture def(tainted) | @@ -390,58 +394,65 @@ nodes | GlobalDataFlow.cs:399:9:399:11 | value | | GlobalDataFlow.cs:399:41:399:46 | access to local variable sink20 | | GlobalDataFlow.cs:410:22:410:35 | "taint source" | +| Splitting.cs:3:28:3:34 | tainted | +| Splitting.cs:8:17:8:31 | call to method Return | +| Splitting.cs:8:24:8:30 | access to parameter tainted | +| Splitting.cs:9:15:9:15 | access to local variable x | +| Splitting.cs:11:19:11:19 | access to local variable x | #select -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 | access to field SinkField0 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 | -| GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 | access to local variable sink0 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 | access to local variable sink1 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 | -| GlobalDataFlow.cs:186:15:186:20 | access to local variable sink10 | access to local variable sink10 | GlobalDataFlow.cs:313:16:313:29 | "taint source" | GlobalDataFlow.cs:186:15:186:20 | access to local variable sink10 | -| GlobalDataFlow.cs:376:15:376:20 | access to local variable sink11 | access to local variable sink11 | GlobalDataFlow.cs:373:39:373:45 | tainted | GlobalDataFlow.cs:376:15:376:20 | access to local variable sink11 | -| GlobalDataFlow.cs:158:15:158:20 | access to local variable sink12 | access to local variable sink12 | GlobalDataFlow.cs:329:22:329:35 | "taint source" | GlobalDataFlow.cs:158:15:158:20 | access to local variable sink12 | -| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 | access to local variable sink13 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 | access to local variable sink14 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 | -| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 | access to local variable sink15 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 | -| GlobalDataFlow.cs:87:15:87:20 | access to local variable sink16 | access to local variable sink16 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:87:15:87:20 | access to local variable sink16 | -| GlobalDataFlow.cs:89:15:89:20 | access to local variable sink17 | access to local variable sink17 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:89:15:89:20 | access to local variable sink17 | -| GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 | access to local variable sink18 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 | -| GlobalDataFlow.cs:194:15:194:20 | access to local variable sink19 | access to local variable sink19 | GlobalDataFlow.cs:410:22:410:35 | "taint source" | GlobalDataFlow.cs:194:15:194:20 | access to local variable sink19 | -| GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 | access to local variable sink2 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 | -| GlobalDataFlow.cs:399:41:399:46 | access to local variable sink20 | access to local variable sink20 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:399:41:399:46 | access to local variable sink20 | -| GlobalDataFlow.cs:94:15:94:20 | access to local variable sink21 | access to local variable sink21 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:94:15:94:20 | access to local variable sink21 | -| GlobalDataFlow.cs:97:15:97:20 | access to local variable sink22 | access to local variable sink22 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:97:15:97:20 | access to local variable sink22 | -| GlobalDataFlow.cs:160:15:160:20 | access to local variable sink23 | access to local variable sink23 | GlobalDataFlow.cs:373:39:373:45 | tainted | GlobalDataFlow.cs:160:15:160:20 | access to local variable sink23 | -| GlobalDataFlow.cs:207:15:207:20 | access to local variable sink24 | access to local variable sink24 | GlobalDataFlow.cs:201:39:201:45 | tainted | GlobalDataFlow.cs:207:15:207:20 | access to local variable sink24 | -| GlobalDataFlow.cs:209:15:209:20 | access to local variable sink25 | access to local variable sink25 | GlobalDataFlow.cs:201:39:201:45 | tainted | GlobalDataFlow.cs:209:15:209:20 | access to local variable sink25 | -| GlobalDataFlow.cs:211:15:211:20 | access to local variable sink26 | access to local variable sink26 | GlobalDataFlow.cs:201:39:201:45 | tainted | GlobalDataFlow.cs:211:15:211:20 | access to local variable sink26 | -| Capture.cs:12:19:12:24 | access to local variable sink27 | access to local variable sink27 | Capture.cs:7:20:7:26 | tainted | Capture.cs:12:19:12:24 | access to local variable sink27 | -| Capture.cs:21:23:21:28 | access to local variable sink28 | access to local variable sink28 | Capture.cs:7:20:7:26 | tainted | Capture.cs:21:23:21:28 | access to local variable sink28 | -| Capture.cs:30:19:30:24 | access to local variable sink29 | access to local variable sink29 | Capture.cs:7:20:7:26 | tainted | Capture.cs:30:19:30:24 | access to local variable sink29 | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 | access to local variable sink3 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 | -| Capture.cs:60:15:60:20 | access to local variable sink30 | access to local variable sink30 | Capture.cs:57:22:57:35 | "taint source" | Capture.cs:60:15:60:20 | access to local variable sink30 | -| Capture.cs:72:15:72:20 | access to local variable sink31 | access to local variable sink31 | Capture.cs:67:26:67:39 | "taint source" | Capture.cs:72:15:72:20 | access to local variable sink31 | -| Capture.cs:81:15:81:20 | access to local variable sink32 | access to local variable sink32 | Capture.cs:77:22:77:35 | "taint source" | Capture.cs:81:15:81:20 | access to local variable sink32 | -| Capture.cs:109:15:109:20 | access to local variable sink33 | access to local variable sink33 | Capture.cs:101:25:101:31 | tainted | Capture.cs:109:15:109:20 | access to local variable sink33 | -| Capture.cs:121:15:121:20 | access to local variable sink34 | access to local variable sink34 | Capture.cs:101:25:101:31 | tainted | Capture.cs:121:15:121:20 | access to local variable sink34 | -| Capture.cs:130:15:130:20 | access to local variable sink35 | access to local variable sink35 | Capture.cs:101:25:101:31 | tainted | Capture.cs:130:15:130:20 | access to local variable sink35 | -| Capture.cs:137:15:137:20 | access to local variable sink36 | access to local variable sink36 | Capture.cs:101:25:101:31 | tainted | Capture.cs:137:15:137:20 | access to local variable sink36 | -| Capture.cs:145:15:145:20 | access to local variable sink37 | access to local variable sink37 | Capture.cs:101:25:101:31 | tainted | Capture.cs:145:15:145:20 | access to local variable sink37 | -| Capture.cs:171:15:171:20 | access to local variable sink38 | access to local variable sink38 | Capture.cs:101:25:101:31 | tainted | Capture.cs:171:15:171:20 | access to local variable sink38 | -| GlobalDataFlow.cs:132:15:132:19 | access to local variable sink4 | access to local variable sink4 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:132:15:132:19 | access to local variable sink4 | -| GlobalDataFlow.cs:140:15:140:19 | access to local variable sink5 | access to local variable sink5 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:140:15:140:19 | access to local variable sink5 | -| GlobalDataFlow.cs:150:15:150:19 | access to local variable sink6 | access to local variable sink6 | GlobalDataFlow.cs:313:16:313:29 | "taint source" | GlobalDataFlow.cs:150:15:150:19 | access to local variable sink6 | -| GlobalDataFlow.cs:153:15:153:19 | access to local variable sink7 | access to local variable sink7 | GlobalDataFlow.cs:318:13:318:26 | "taint source" | GlobalDataFlow.cs:153:15:153:19 | access to local variable sink7 | -| GlobalDataFlow.cs:156:15:156:19 | access to local variable sink8 | access to local variable sink8 | GlobalDataFlow.cs:323:13:323:26 | "taint source" | GlobalDataFlow.cs:156:15:156:19 | access to local variable sink8 | -| GlobalDataFlow.cs:177:15:177:19 | access to local variable sink9 | access to local variable sink9 | GlobalDataFlow.cs:175:35:175:48 | "taint source" | GlobalDataFlow.cs:177:15:177:19 | access to local variable sink9 | -| GlobalDataFlow.cs:233:15:233:24 | access to parameter sinkParam0 | access to parameter sinkParam0 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:233:15:233:24 | access to parameter sinkParam0 | -| GlobalDataFlow.cs:233:15:233:24 | access to parameter sinkParam0 | access to parameter sinkParam0 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:233:15:233:24 | access to parameter sinkParam0 | -| GlobalDataFlow.cs:238:15:238:24 | access to parameter sinkParam1 | access to parameter sinkParam1 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:238:15:238:24 | access to parameter sinkParam1 | -| GlobalDataFlow.cs:204:58:204:68 | access to parameter sinkParam10 | access to parameter sinkParam10 | GlobalDataFlow.cs:201:39:201:45 | tainted | GlobalDataFlow.cs:204:58:204:68 | access to parameter sinkParam10 | -| GlobalDataFlow.cs:301:15:301:25 | access to parameter sinkParam11 | access to parameter sinkParam11 | GlobalDataFlow.cs:201:39:201:45 | tainted | GlobalDataFlow.cs:301:15:301:25 | access to parameter sinkParam11 | -| GlobalDataFlow.cs:44:50:44:59 | access to parameter sinkParam2 | access to parameter sinkParam2 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:44:50:44:59 | access to parameter sinkParam2 | -| GlobalDataFlow.cs:243:15:243:24 | access to parameter sinkParam3 | access to parameter sinkParam3 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:243:15:243:24 | access to parameter sinkParam3 | -| GlobalDataFlow.cs:248:15:248:24 | access to parameter sinkParam4 | access to parameter sinkParam4 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:248:15:248:24 | access to parameter sinkParam4 | -| GlobalDataFlow.cs:253:15:253:24 | access to parameter sinkParam5 | access to parameter sinkParam5 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:253:15:253:24 | access to parameter sinkParam5 | -| GlobalDataFlow.cs:258:15:258:24 | access to parameter sinkParam6 | access to parameter sinkParam6 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:258:15:258:24 | access to parameter sinkParam6 | -| GlobalDataFlow.cs:263:15:263:24 | access to parameter sinkParam7 | access to parameter sinkParam7 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:263:15:263:24 | access to parameter sinkParam7 | -| GlobalDataFlow.cs:289:15:289:24 | access to parameter sinkParam8 | access to parameter sinkParam8 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:289:15:289:24 | access to parameter sinkParam8 | -| GlobalDataFlow.cs:295:15:295:24 | access to parameter sinkParam9 | access to parameter sinkParam9 | GlobalDataFlow.cs:201:39:201:45 | tainted | GlobalDataFlow.cs:295:15:295:24 | access to parameter sinkParam9 | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 | access to property SinkProperty0 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 | +| Capture.cs:12:19:12:24 | access to local variable sink27 | Capture.cs:7:20:7:26 | tainted | Capture.cs:12:19:12:24 | access to local variable sink27 | access to local variable sink27 | +| Capture.cs:21:23:21:28 | access to local variable sink28 | Capture.cs:7:20:7:26 | tainted | Capture.cs:21:23:21:28 | access to local variable sink28 | access to local variable sink28 | +| Capture.cs:30:19:30:24 | access to local variable sink29 | Capture.cs:7:20:7:26 | tainted | Capture.cs:30:19:30:24 | access to local variable sink29 | access to local variable sink29 | +| Capture.cs:60:15:60:20 | access to local variable sink30 | Capture.cs:57:22:57:35 | "taint source" | Capture.cs:60:15:60:20 | access to local variable sink30 | access to local variable sink30 | +| Capture.cs:72:15:72:20 | access to local variable sink31 | Capture.cs:67:26:67:39 | "taint source" | Capture.cs:72:15:72:20 | access to local variable sink31 | access to local variable sink31 | +| Capture.cs:81:15:81:20 | access to local variable sink32 | Capture.cs:77:22:77:35 | "taint source" | Capture.cs:81:15:81:20 | access to local variable sink32 | access to local variable sink32 | +| Capture.cs:109:15:109:20 | access to local variable sink33 | Capture.cs:101:25:101:31 | tainted | Capture.cs:109:15:109:20 | access to local variable sink33 | access to local variable sink33 | +| Capture.cs:121:15:121:20 | access to local variable sink34 | Capture.cs:101:25:101:31 | tainted | Capture.cs:121:15:121:20 | access to local variable sink34 | access to local variable sink34 | +| Capture.cs:130:15:130:20 | access to local variable sink35 | Capture.cs:101:25:101:31 | tainted | Capture.cs:130:15:130:20 | access to local variable sink35 | access to local variable sink35 | +| Capture.cs:137:15:137:20 | access to local variable sink36 | Capture.cs:101:25:101:31 | tainted | Capture.cs:137:15:137:20 | access to local variable sink36 | access to local variable sink36 | +| Capture.cs:145:15:145:20 | access to local variable sink37 | Capture.cs:101:25:101:31 | tainted | Capture.cs:145:15:145:20 | access to local variable sink37 | access to local variable sink37 | +| Capture.cs:171:15:171:20 | access to local variable sink38 | Capture.cs:101:25:101:31 | tainted | Capture.cs:171:15:171:20 | access to local variable sink38 | access to local variable sink38 | +| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 | access to field SinkField0 | +| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 | access to property SinkProperty0 | +| GlobalDataFlow.cs:44:50:44:59 | access to parameter sinkParam2 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:44:50:44:59 | access to parameter sinkParam2 | access to parameter sinkParam2 | +| GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 | access to local variable sink0 | +| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 | access to local variable sink1 | +| GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 | access to local variable sink2 | +| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 | access to local variable sink3 | +| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 | access to local variable sink13 | +| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 | access to local variable sink14 | +| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 | access to local variable sink15 | +| GlobalDataFlow.cs:87:15:87:20 | access to local variable sink16 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:87:15:87:20 | access to local variable sink16 | access to local variable sink16 | +| GlobalDataFlow.cs:89:15:89:20 | access to local variable sink17 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:89:15:89:20 | access to local variable sink17 | access to local variable sink17 | +| GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 | access to local variable sink18 | +| GlobalDataFlow.cs:94:15:94:20 | access to local variable sink21 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:94:15:94:20 | access to local variable sink21 | access to local variable sink21 | +| GlobalDataFlow.cs:97:15:97:20 | access to local variable sink22 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:97:15:97:20 | access to local variable sink22 | access to local variable sink22 | +| GlobalDataFlow.cs:132:15:132:19 | access to local variable sink4 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:132:15:132:19 | access to local variable sink4 | access to local variable sink4 | +| GlobalDataFlow.cs:140:15:140:19 | access to local variable sink5 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:140:15:140:19 | access to local variable sink5 | access to local variable sink5 | +| GlobalDataFlow.cs:150:15:150:19 | access to local variable sink6 | GlobalDataFlow.cs:313:16:313:29 | "taint source" | GlobalDataFlow.cs:150:15:150:19 | access to local variable sink6 | access to local variable sink6 | +| GlobalDataFlow.cs:153:15:153:19 | access to local variable sink7 | GlobalDataFlow.cs:318:13:318:26 | "taint source" | GlobalDataFlow.cs:153:15:153:19 | access to local variable sink7 | access to local variable sink7 | +| GlobalDataFlow.cs:156:15:156:19 | access to local variable sink8 | GlobalDataFlow.cs:323:13:323:26 | "taint source" | GlobalDataFlow.cs:156:15:156:19 | access to local variable sink8 | access to local variable sink8 | +| GlobalDataFlow.cs:158:15:158:20 | access to local variable sink12 | GlobalDataFlow.cs:329:22:329:35 | "taint source" | GlobalDataFlow.cs:158:15:158:20 | access to local variable sink12 | access to local variable sink12 | +| GlobalDataFlow.cs:160:15:160:20 | access to local variable sink23 | GlobalDataFlow.cs:373:39:373:45 | tainted | GlobalDataFlow.cs:160:15:160:20 | access to local variable sink23 | access to local variable sink23 | +| GlobalDataFlow.cs:177:15:177:19 | access to local variable sink9 | GlobalDataFlow.cs:175:35:175:48 | "taint source" | GlobalDataFlow.cs:177:15:177:19 | access to local variable sink9 | access to local variable sink9 | +| GlobalDataFlow.cs:186:15:186:20 | access to local variable sink10 | GlobalDataFlow.cs:313:16:313:29 | "taint source" | GlobalDataFlow.cs:186:15:186:20 | access to local variable sink10 | access to local variable sink10 | +| GlobalDataFlow.cs:194:15:194:20 | access to local variable sink19 | GlobalDataFlow.cs:410:22:410:35 | "taint source" | GlobalDataFlow.cs:194:15:194:20 | access to local variable sink19 | access to local variable sink19 | +| GlobalDataFlow.cs:204:58:204:68 | access to parameter sinkParam10 | GlobalDataFlow.cs:201:39:201:45 | tainted | GlobalDataFlow.cs:204:58:204:68 | access to parameter sinkParam10 | access to parameter sinkParam10 | +| GlobalDataFlow.cs:207:15:207:20 | access to local variable sink24 | GlobalDataFlow.cs:201:39:201:45 | tainted | GlobalDataFlow.cs:207:15:207:20 | access to local variable sink24 | access to local variable sink24 | +| GlobalDataFlow.cs:209:15:209:20 | access to local variable sink25 | GlobalDataFlow.cs:201:39:201:45 | tainted | GlobalDataFlow.cs:209:15:209:20 | access to local variable sink25 | access to local variable sink25 | +| GlobalDataFlow.cs:211:15:211:20 | access to local variable sink26 | GlobalDataFlow.cs:201:39:201:45 | tainted | GlobalDataFlow.cs:211:15:211:20 | access to local variable sink26 | access to local variable sink26 | +| GlobalDataFlow.cs:233:15:233:24 | access to parameter sinkParam0 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:233:15:233:24 | access to parameter sinkParam0 | access to parameter sinkParam0 | +| GlobalDataFlow.cs:233:15:233:24 | access to parameter sinkParam0 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:233:15:233:24 | access to parameter sinkParam0 | access to parameter sinkParam0 | +| GlobalDataFlow.cs:238:15:238:24 | access to parameter sinkParam1 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:238:15:238:24 | access to parameter sinkParam1 | access to parameter sinkParam1 | +| GlobalDataFlow.cs:243:15:243:24 | access to parameter sinkParam3 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:243:15:243:24 | access to parameter sinkParam3 | access to parameter sinkParam3 | +| GlobalDataFlow.cs:248:15:248:24 | access to parameter sinkParam4 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:248:15:248:24 | access to parameter sinkParam4 | access to parameter sinkParam4 | +| GlobalDataFlow.cs:253:15:253:24 | access to parameter sinkParam5 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:253:15:253:24 | access to parameter sinkParam5 | access to parameter sinkParam5 | +| GlobalDataFlow.cs:258:15:258:24 | access to parameter sinkParam6 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:258:15:258:24 | access to parameter sinkParam6 | access to parameter sinkParam6 | +| GlobalDataFlow.cs:263:15:263:24 | access to parameter sinkParam7 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:263:15:263:24 | access to parameter sinkParam7 | access to parameter sinkParam7 | +| GlobalDataFlow.cs:289:15:289:24 | access to parameter sinkParam8 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:289:15:289:24 | access to parameter sinkParam8 | access to parameter sinkParam8 | +| GlobalDataFlow.cs:295:15:295:24 | access to parameter sinkParam9 | GlobalDataFlow.cs:201:39:201:45 | tainted | GlobalDataFlow.cs:295:15:295:24 | access to parameter sinkParam9 | access to parameter sinkParam9 | +| GlobalDataFlow.cs:301:15:301:25 | access to parameter sinkParam11 | GlobalDataFlow.cs:201:39:201:45 | tainted | GlobalDataFlow.cs:301:15:301:25 | access to parameter sinkParam11 | access to parameter sinkParam11 | +| GlobalDataFlow.cs:376:15:376:20 | access to local variable sink11 | GlobalDataFlow.cs:373:39:373:45 | tainted | GlobalDataFlow.cs:376:15:376:20 | access to local variable sink11 | access to local variable sink11 | +| GlobalDataFlow.cs:399:41:399:46 | access to local variable sink20 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:399:41:399:46 | access to local variable sink20 | access to local variable sink20 | +| Splitting.cs:9:15:9:15 | access to local variable x | Splitting.cs:3:28:3:34 | tainted | Splitting.cs:9:15:9:15 | access to local variable x | access to local variable x | +| Splitting.cs:11:19:11:19 | access to local variable x | Splitting.cs:3:28:3:34 | tainted | Splitting.cs:11:19:11:19 | access to local variable x | access to local variable x | diff --git a/csharp/ql/test/library-tests/dataflow/global/TaintTrackingPath.ql b/csharp/ql/test/library-tests/dataflow/global/TaintTrackingPath.ql index 71975ecd111..e0eccb70461 100644 --- a/csharp/ql/test/library-tests/dataflow/global/TaintTrackingPath.ql +++ b/csharp/ql/test/library-tests/dataflow/global/TaintTrackingPath.ql @@ -20,4 +20,4 @@ from TTConfig c, DataFlow::PathNode source, DataFlow::PathNode sink, string s where c.hasFlowPath(source, sink) and s = sink.toString() -select sink, s, source, sink order by s +select sink, source, sink, s diff --git a/csharp/ql/test/library-tests/dataflow/local/DataFlow.expected b/csharp/ql/test/library-tests/dataflow/local/DataFlow.expected index b1ae50cefe4..ab16c42f2cb 100644 --- a/csharp/ql/test/library-tests/dataflow/local/DataFlow.expected +++ b/csharp/ql/test/library-tests/dataflow/local/DataFlow.expected @@ -1,19 +1,24 @@ -| access to field SsaFieldSink0 | -| access to field SsaFieldSink1 | -| access to local variable sink0 | -| access to local variable sink40 | -| access to local variable sink41 | -| access to local variable sink42 | -| access to local variable sink43 | -| access to local variable sink67 | -| access to local variable sink68 | -| access to local variable sink70 | -| access to local variable sink71 | -| access to local variable sink72 | -| access to local variable ssaSink0 | -| access to local variable ssaSink1 | -| access to local variable ssaSink2 | -| access to local variable ssaSink3 | -| access to local variable ssaSink4 | -| access to local variable ssaSink5 | -| access to parameter tainted | +| LocalDataFlow.cs:53:15:53:19 | access to local variable sink0 | +| LocalDataFlow.cs:300:15:300:20 | access to local variable sink40 | +| LocalDataFlow.cs:302:15:302:20 | access to local variable sink41 | +| LocalDataFlow.cs:304:15:304:20 | access to local variable sink42 | +| LocalDataFlow.cs:306:15:306:20 | access to local variable sink43 | +| LocalDataFlow.cs:392:15:392:20 | access to local variable sink67 | +| LocalDataFlow.cs:394:15:394:20 | access to local variable sink68 | +| LocalDataFlow.cs:412:15:412:20 | access to local variable sink70 | +| LocalDataFlow.cs:420:19:420:24 | access to local variable sink71 | +| LocalDataFlow.cs:430:23:430:28 | access to local variable sink72 | +| LocalDataFlow.cs:466:15:466:21 | access to parameter tainted | +| SSA.cs:9:15:9:22 | access to local variable ssaSink0 | +| SSA.cs:25:15:25:22 | access to local variable ssaSink1 | +| SSA.cs:43:15:43:22 | access to local variable ssaSink2 | +| SSA.cs:60:15:60:22 | access to local variable ssaSink3 | +| SSA.cs:69:15:69:34 | access to field SsaFieldSink0 | +| SSA.cs:98:15:98:22 | access to local variable ssaSink4 | +| SSA.cs:124:15:124:34 | access to field SsaFieldSink1 | +| SSA.cs:180:15:180:22 | access to local variable ssaSink5 | +| Splitting.cs:8:19:8:19 | access to local variable x | +| Splitting.cs:12:15:12:15 | access to local variable x | +| Splitting.cs:25:15:25:15 | access to local variable x | +| Splitting.cs:27:19:27:19 | access to local variable x | +| Splitting.cs:29:19:29:19 | access to local variable x | diff --git a/csharp/ql/test/library-tests/dataflow/local/DataFlow.ql b/csharp/ql/test/library-tests/dataflow/local/DataFlow.ql index d51032520e6..918de64c60f 100644 --- a/csharp/ql/test/library-tests/dataflow/local/DataFlow.ql +++ b/csharp/ql/test/library-tests/dataflow/local/DataFlow.ql @@ -1,9 +1,15 @@ import csharp import Common +import semmle.code.csharp.controlflow.Guards -from MyFlowSource source, Access target, string s +predicate step(DataFlow::Node pred, DataFlow::Node succ) { + DataFlow::localFlowStep(pred, succ) and + not succ.asExpr() instanceof NullGuardedExpr +} + +from MyFlowSource source, DataFlow::Node sink, Access target where - DataFlow::localFlowStep+(source, DataFlow::exprNode(target)) and - exists(MethodCall mc | mc.getTarget().getName() = "Check" and mc.getAnArgument() = target) and - s = target.toString() -select s order by s + step+(source, sink) and + sink = DataFlow::exprNode(target) and + exists(MethodCall mc | mc.getTarget().getName() = "Check" and mc.getAnArgument() = target) +select sink diff --git a/csharp/ql/test/library-tests/dataflow/local/DataFlowStep.expected b/csharp/ql/test/library-tests/dataflow/local/DataFlowStep.expected index 777b702ef10..5f2b280d79a 100644 --- a/csharp/ql/test/library-tests/dataflow/local/DataFlowStep.expected +++ b/csharp/ql/test/library-tests/dataflow/local/DataFlowStep.expected @@ -14,6 +14,7 @@ | Capture.cs:58:21:58:21 | 1 | Capture.cs:58:17:58:21 | SSA def(i) | | Capture.cs:61:17:61:17 | 1 | Capture.cs:61:13:61:17 | SSA def(i) | | Capture.cs:63:9:63:17 | SSA call def(i) | Capture.cs:64:13:64:13 | access to local variable i | +| LocalDataFlow.cs:49:30:49:30 | b | LocalDataFlow.cs:96:21:96:21 | access to parameter b | | LocalDataFlow.cs:52:13:52:34 | SSA def(sink0) | LocalDataFlow.cs:53:15:53:19 | access to local variable sink0 | | LocalDataFlow.cs:52:21:52:34 | "taint source" | LocalDataFlow.cs:52:13:52:34 | SSA def(sink0) | | LocalDataFlow.cs:53:15:53:19 | access to local variable sink0 | LocalDataFlow.cs:61:18:61:22 | access to local variable sink0 | @@ -48,18 +49,22 @@ | LocalDataFlow.cs:85:15:85:22 | access to local variable nonSink0 | LocalDataFlow.cs:92:21:92:28 | access to local variable nonSink0 | | LocalDataFlow.cs:88:13:88:27 | SSA def(sink6) | LocalDataFlow.cs:89:15:89:19 | access to local variable sink6 | | LocalDataFlow.cs:88:22:88:26 | access to local variable sink5 | LocalDataFlow.cs:88:13:88:27 | SSA def(sink6) | -| LocalDataFlow.cs:89:15:89:19 | access to local variable sink6 | LocalDataFlow.cs:96:35:96:39 | access to local variable sink6 | +| LocalDataFlow.cs:89:15:89:19 | access to local variable sink6 | LocalDataFlow.cs:96:31:96:35 | access to local variable sink6 | | LocalDataFlow.cs:92:9:92:29 | SSA def(nonSink0) | LocalDataFlow.cs:93:15:93:22 | access to local variable nonSink0 | | LocalDataFlow.cs:92:21:92:28 | access to local variable nonSink0 | LocalDataFlow.cs:92:9:92:29 | SSA def(nonSink0) | -| LocalDataFlow.cs:96:13:96:39 | SSA def(sink7) | LocalDataFlow.cs:97:15:97:19 | access to local variable sink7 | -| LocalDataFlow.cs:96:21:96:39 | ... ? ... : ... | LocalDataFlow.cs:96:13:96:39 | SSA def(sink7) | -| LocalDataFlow.cs:96:29:96:31 | "a" | LocalDataFlow.cs:96:21:96:39 | ... ? ... : ... | -| LocalDataFlow.cs:96:35:96:39 | access to local variable sink6 | LocalDataFlow.cs:96:21:96:39 | ... ? ... : ... | -| LocalDataFlow.cs:97:15:97:19 | access to local variable sink7 | LocalDataFlow.cs:104:29:104:33 | access to local variable sink7 | -| LocalDataFlow.cs:100:9:100:41 | SSA def(nonSink0) | LocalDataFlow.cs:101:15:101:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:100:20:100:41 | ... ? ... : ... | LocalDataFlow.cs:100:9:100:41 | SSA def(nonSink0) | -| LocalDataFlow.cs:100:29:100:33 | "abc" | LocalDataFlow.cs:100:20:100:41 | ... ? ... : ... | -| LocalDataFlow.cs:100:37:100:41 | "def" | LocalDataFlow.cs:100:20:100:41 | ... ? ... : ... | +| LocalDataFlow.cs:96:13:96:35 | [b (line 49): false] SSA def(sink7) | LocalDataFlow.cs:97:15:97:19 | access to local variable sink7 | +| LocalDataFlow.cs:96:13:96:35 | [b (line 49): true] SSA def(sink7) | LocalDataFlow.cs:97:15:97:19 | access to local variable sink7 | +| LocalDataFlow.cs:96:21:96:21 | access to parameter b | LocalDataFlow.cs:100:20:100:20 | access to parameter b | +| LocalDataFlow.cs:96:21:96:35 | ... ? ... : ... | LocalDataFlow.cs:96:13:96:35 | [b (line 49): false] SSA def(sink7) | +| LocalDataFlow.cs:96:21:96:35 | ... ? ... : ... | LocalDataFlow.cs:96:13:96:35 | [b (line 49): true] SSA def(sink7) | +| LocalDataFlow.cs:96:25:96:27 | "a" | LocalDataFlow.cs:96:21:96:35 | ... ? ... : ... | +| LocalDataFlow.cs:96:31:96:35 | access to local variable sink6 | LocalDataFlow.cs:96:21:96:35 | ... ? ... : ... | +| LocalDataFlow.cs:97:15:97:19 | access to local variable sink7 | LocalDataFlow.cs:100:9:100:36 | SSA phi(sink7) | +| LocalDataFlow.cs:100:9:100:36 | SSA def(nonSink0) | LocalDataFlow.cs:101:15:101:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:100:9:100:36 | SSA phi(sink7) | LocalDataFlow.cs:104:29:104:33 | access to local variable sink7 | +| LocalDataFlow.cs:100:20:100:36 | ... ? ... : ... | LocalDataFlow.cs:100:9:100:36 | SSA def(nonSink0) | +| LocalDataFlow.cs:100:24:100:28 | "abc" | LocalDataFlow.cs:100:20:100:36 | ... ? ... : ... | +| LocalDataFlow.cs:100:32:100:36 | "def" | LocalDataFlow.cs:100:20:100:36 | ... ? ... : ... | | LocalDataFlow.cs:101:15:101:22 | access to local variable nonSink0 | LocalDataFlow.cs:108:32:108:39 | access to local variable nonSink0 | | LocalDataFlow.cs:104:13:104:33 | SSA def(sink8) | LocalDataFlow.cs:105:15:105:19 | access to local variable sink8 | | LocalDataFlow.cs:104:21:104:33 | (...) ... | LocalDataFlow.cs:104:13:104:33 | SSA def(sink8) | @@ -638,3 +643,60 @@ | SSA.cs:177:21:177:28 | access to local variable ssaSink5 | SSA.cs:176:21:176:28 | access to local variable ssaSink5 | | SSA.cs:177:21:177:28 | access to local variable ssaSink5 | SSA.cs:180:9:180:24 | SSA phi(ssaSink5) | | SSA.cs:180:9:180:24 | SSA phi(ssaSink5) | SSA.cs:180:15:180:22 | access to local variable ssaSink5 | +| Splitting.cs:3:18:3:18 | b | Splitting.cs:6:13:6:13 | access to parameter b | +| Splitting.cs:3:28:3:34 | tainted | Splitting.cs:5:17:5:23 | access to parameter tainted | +| Splitting.cs:5:13:5:23 | SSA def(x) | Splitting.cs:8:19:8:19 | access to local variable x | +| Splitting.cs:5:13:5:23 | SSA def(x) | Splitting.cs:12:15:12:15 | access to local variable x | +| Splitting.cs:5:17:5:23 | access to parameter tainted | Splitting.cs:5:13:5:23 | SSA def(x) | +| Splitting.cs:6:13:6:13 | access to parameter b | Splitting.cs:13:13:13:13 | access to parameter b | +| Splitting.cs:8:19:8:19 | access to local variable x | Splitting.cs:9:17:9:17 | access to local variable x | +| Splitting.cs:12:15:12:15 | access to local variable x | Splitting.cs:14:19:14:19 | access to local variable x | +| Splitting.cs:17:18:17:18 | b | Splitting.cs:20:13:20:13 | access to parameter b | +| Splitting.cs:19:13:19:18 | SSA def(x) | Splitting.cs:22:19:22:19 | access to local variable x | +| Splitting.cs:19:13:19:18 | SSA def(x) | Splitting.cs:25:15:25:15 | access to local variable x | +| Splitting.cs:19:17:19:18 | "" | Splitting.cs:19:13:19:18 | SSA def(x) | +| Splitting.cs:20:13:20:13 | access to parameter b | Splitting.cs:26:13:26:13 | access to parameter b | +| Splitting.cs:23:13:23:30 | [b (line 17): true] SSA def(x) | Splitting.cs:25:15:25:15 | access to local variable x | +| Splitting.cs:23:17:23:30 | "taint source" | Splitting.cs:23:13:23:30 | [b (line 17): true] SSA def(x) | +| Splitting.cs:25:15:25:15 | access to local variable x | Splitting.cs:27:19:27:19 | access to local variable x | +| Splitting.cs:25:15:25:15 | access to local variable x | Splitting.cs:29:19:29:19 | access to local variable x | +| Splitting.cs:32:18:32:18 | b | Splitting.cs:35:13:35:13 | access to parameter b | +| Splitting.cs:35:13:35:13 | access to parameter b | Splitting.cs:39:15:39:15 | access to parameter b | +| Splitting.cs:37:9:37:15 | [b (line 32): false] SSA def(x) | Splitting.cs:38:15:38:15 | access to local variable x | +| Splitting.cs:37:9:37:15 | [b (line 32): true] SSA def(x) | Splitting.cs:38:15:38:15 | access to local variable x | +| Splitting.cs:37:13:37:15 | "b" | Splitting.cs:37:9:37:15 | [b (line 32): false] SSA def(x) | +| Splitting.cs:37:13:37:15 | "b" | Splitting.cs:37:9:37:15 | [b (line 32): true] SSA def(x) | +| Splitting.cs:38:15:38:15 | access to local variable x | Splitting.cs:39:19:39:19 | access to local variable x | +| Splitting.cs:39:15:39:15 | access to parameter b | Splitting.cs:42:13:42:13 | access to parameter b | +| Splitting.cs:39:19:39:19 | access to local variable x | Splitting.cs:39:15:39:25 | ... ? ... : ... | +| Splitting.cs:39:23:39:25 | "c" | Splitting.cs:39:15:39:25 | ... ? ... : ... | +| Splitting.cs:40:23:40:23 | access to local variable x | Splitting.cs:40:15:40:23 | (...) ... | +| Splitting.cs:41:19:41:21 | "d" | Splitting.cs:41:15:41:21 | ... = ... | +| Splitting.cs:46:18:46:18 | b | Splitting.cs:49:13:49:13 | access to parameter b | +| Splitting.cs:48:13:48:18 | SSA def(x) | Splitting.cs:53:13:53:13 | access to local variable x | +| Splitting.cs:48:17:48:18 | "" | Splitting.cs:48:13:48:18 | SSA def(x) | +| Splitting.cs:49:13:49:13 | access to parameter b | Splitting.cs:60:13:60:13 | access to parameter b | +| Splitting.cs:50:13:50:21 | [b (line 46): true] SSA def(x) | Splitting.cs:53:13:53:13 | access to local variable x | +| Splitting.cs:50:17:50:21 | "abc" | Splitting.cs:50:13:50:21 | [b (line 46): true] SSA def(x) | +| Splitting.cs:51:13:51:36 | [b (line 46): false] SSA def(y) | Splitting.cs:52:9:52:9 | access to local variable y | +| Splitting.cs:51:13:51:36 | [b (line 46): true] SSA def(y) | Splitting.cs:52:9:52:9 | access to local variable y | +| Splitting.cs:51:17:51:36 | array creation of type String[] | Splitting.cs:51:13:51:36 | [b (line 46): false] SSA def(y) | +| Splitting.cs:51:17:51:36 | array creation of type String[] | Splitting.cs:51:13:51:36 | [b (line 46): true] SSA def(y) | +| Splitting.cs:52:9:52:9 | access to local variable y | Splitting.cs:53:17:53:17 | access to local variable y | +| Splitting.cs:53:9:53:20 | [b (line 46): false] SSA def(x) | Splitting.cs:54:17:54:17 | access to local variable x | +| Splitting.cs:53:9:53:20 | [b (line 46): true] SSA def(x) | Splitting.cs:54:17:54:17 | access to local variable x | +| Splitting.cs:53:13:53:20 | ... + ... | Splitting.cs:53:9:53:20 | [b (line 46): false] SSA def(x) | +| Splitting.cs:53:13:53:20 | ... + ... | Splitting.cs:53:9:53:20 | [b (line 46): true] SSA def(x) | +| Splitting.cs:53:17:53:17 | access to local variable y | Splitting.cs:57:17:57:17 | access to local variable y | +| Splitting.cs:54:13:54:23 | [b (line 46): false] SSA def(z) | Splitting.cs:55:14:55:14 | access to local variable z | +| Splitting.cs:54:13:54:23 | [b (line 46): true] SSA def(z) | Splitting.cs:55:14:55:14 | access to local variable z | +| Splitting.cs:54:17:54:17 | access to local variable x | Splitting.cs:56:17:56:17 | access to local variable x | +| Splitting.cs:54:17:54:23 | ... == ... | Splitting.cs:54:13:54:23 | [b (line 46): false] SSA def(z) | +| Splitting.cs:54:17:54:23 | ... == ... | Splitting.cs:54:13:54:23 | [b (line 46): true] SSA def(z) | +| Splitting.cs:56:9:56:19 | [b (line 46): false] SSA def(x) | Splitting.cs:57:14:57:14 | access to local variable x | +| Splitting.cs:56:9:56:19 | [b (line 46): true] SSA def(x) | Splitting.cs:57:14:57:14 | access to local variable x | +| Splitting.cs:56:13:56:19 | $"..." | Splitting.cs:56:9:56:19 | [b (line 46): false] SSA def(x) | +| Splitting.cs:56:13:56:19 | $"..." | Splitting.cs:56:9:56:19 | [b (line 46): true] SSA def(x) | +| Splitting.cs:57:17:57:17 | access to local variable y | Splitting.cs:58:27:58:27 | access to local variable y | +| Splitting.cs:58:22:58:22 | [b (line 46): false] SSA def(s) | Splitting.cs:59:19:59:19 | access to local variable s | +| Splitting.cs:58:22:58:22 | [b (line 46): true] SSA def(s) | Splitting.cs:59:19:59:19 | access to local variable s | diff --git a/csharp/ql/test/library-tests/dataflow/local/LocalDataFlow.cs b/csharp/ql/test/library-tests/dataflow/local/LocalDataFlow.cs index 242725aa7c2..154b4d5fcb9 100644 --- a/csharp/ql/test/library-tests/dataflow/local/LocalDataFlow.cs +++ b/csharp/ql/test/library-tests/dataflow/local/LocalDataFlow.cs @@ -46,7 +46,7 @@ namespace System.Runtime.Serialization /// public class LocalDataFlow { - public async void M() + public async void M(bool b) { // Assignment, tainted var sink0 = "taint source"; @@ -93,11 +93,11 @@ public class LocalDataFlow Check(nonSink0); // Conditional expression, tainted - var sink7 = 1 > 2 ? "a" : sink6; + var sink7 = b ? "a" : sink6; Check(sink7); // Conditional expression, not tainted - nonSink0 = 4 == 2 ? "abc" : "def"; + nonSink0 = b ? "abc" : "def"; Check(nonSink0); // Cast, tainted diff --git a/csharp/ql/test/library-tests/dataflow/local/Splitting.cs b/csharp/ql/test/library-tests/dataflow/local/Splitting.cs new file mode 100644 index 00000000000..531e61f7963 --- /dev/null +++ b/csharp/ql/test/library-tests/dataflow/local/Splitting.cs @@ -0,0 +1,66 @@ +class Splitting +{ + void M1(bool b, string tainted) + { + var x = tainted; + if (b) + { + Check(x); + if (x == null) + return; + } + Check(x); + if (b) + Check(x); + } + + void M2(bool b) + { + var x = ""; + if (b) + { + Check(x); + x = "taint source"; + } + Check(x); + if (b) + Check(x); + else + Check(x); + } + + void M3(bool b) + { + var x = ""; + if (b) + x = "a"; + x = "b"; + Check(x); + Check(b ? x : "c"); + Check((object)x); + Check(x = "d"); + if (b) + return; + } + + void M4(bool b) + { + var x = ""; + if (b) + x = "abc"; + var y = new string[] { "a" }; + y[0] = "b"; + x = x + y[0]; + var z = x == ""; + z = !z; + x = $"c{x}"; + x = (x, y).Item1; + foreach (var s in y) + Check(s); + if (b) + return; + } + + string Field; + static void Check(T x) { } +} diff --git a/csharp/ql/test/library-tests/dataflow/local/TaintTracking.expected b/csharp/ql/test/library-tests/dataflow/local/TaintTracking.expected index 3ef16a3f828..71dc4a1b7c7 100644 --- a/csharp/ql/test/library-tests/dataflow/local/TaintTracking.expected +++ b/csharp/ql/test/library-tests/dataflow/local/TaintTracking.expected @@ -1,72 +1,77 @@ -| access to field SsaFieldSink0 | -| access to field SsaFieldSink1 | -| access to local variable sink0 | -| access to local variable sink1 | -| access to local variable sink10 | -| access to local variable sink11 | -| access to local variable sink12 | -| access to local variable sink13 | -| access to local variable sink14 | -| access to local variable sink15 | -| access to local variable sink16 | -| access to local variable sink17 | -| access to local variable sink18 | -| access to local variable sink19 | -| access to local variable sink2 | -| access to local variable sink20 | -| access to local variable sink21 | -| access to local variable sink22 | -| access to local variable sink23 | -| access to local variable sink24 | -| access to local variable sink25 | -| access to local variable sink26 | -| access to local variable sink27 | -| access to local variable sink28 | -| access to local variable sink29 | -| access to local variable sink3 | -| access to local variable sink30 | -| access to local variable sink31 | -| access to local variable sink32 | -| access to local variable sink33 | -| access to local variable sink34 | -| access to local variable sink35 | -| access to local variable sink36 | -| access to local variable sink40 | -| access to local variable sink41 | -| access to local variable sink42 | -| access to local variable sink43 | -| access to local variable sink45 | -| access to local variable sink46 | -| access to local variable sink47 | -| access to local variable sink48 | -| access to local variable sink49 | -| access to local variable sink5 | -| access to local variable sink50 | -| access to local variable sink51 | -| access to local variable sink52 | -| access to local variable sink53 | -| access to local variable sink54 | -| access to local variable sink6 | -| access to local variable sink60 | -| access to local variable sink61 | -| access to local variable sink62 | -| access to local variable sink63 | -| access to local variable sink64 | -| access to local variable sink65 | -| access to local variable sink66 | -| access to local variable sink67 | -| access to local variable sink68 | -| access to local variable sink69 | -| access to local variable sink7 | -| access to local variable sink70 | -| access to local variable sink71 | -| access to local variable sink72 | -| access to local variable sink8 | -| access to local variable sink9 | -| access to local variable ssaSink0 | -| access to local variable ssaSink1 | -| access to local variable ssaSink2 | -| access to local variable ssaSink3 | -| access to local variable ssaSink4 | -| access to local variable ssaSink5 | -| access to parameter tainted | +| LocalDataFlow.cs:53:15:53:19 | access to local variable sink0 | +| LocalDataFlow.cs:62:15:62:19 | access to local variable sink1 | +| LocalDataFlow.cs:71:15:71:19 | access to local variable sink2 | +| LocalDataFlow.cs:81:15:81:19 | access to local variable sink5 | +| LocalDataFlow.cs:89:15:89:19 | access to local variable sink6 | +| LocalDataFlow.cs:97:15:97:19 | access to local variable sink7 | +| LocalDataFlow.cs:105:15:105:19 | access to local variable sink8 | +| LocalDataFlow.cs:113:15:113:19 | access to local variable sink9 | +| LocalDataFlow.cs:121:15:121:20 | access to local variable sink10 | +| LocalDataFlow.cs:129:15:129:20 | access to local variable sink11 | +| LocalDataFlow.cs:137:15:137:20 | access to local variable sink14 | +| LocalDataFlow.cs:145:15:145:20 | access to local variable sink15 | +| LocalDataFlow.cs:148:15:148:20 | access to local variable sink16 | +| LocalDataFlow.cs:150:15:150:20 | access to local variable sink17 | +| LocalDataFlow.cs:152:15:152:20 | access to local variable sink18 | +| LocalDataFlow.cs:154:15:154:20 | access to local variable sink19 | +| LocalDataFlow.cs:156:15:156:20 | access to local variable sink45 | +| LocalDataFlow.cs:159:15:159:20 | access to local variable sink46 | +| LocalDataFlow.cs:161:15:161:20 | access to local variable sink47 | +| LocalDataFlow.cs:163:15:163:20 | access to local variable sink49 | +| LocalDataFlow.cs:165:15:165:20 | access to local variable sink50 | +| LocalDataFlow.cs:167:15:167:20 | access to local variable sink51 | +| LocalDataFlow.cs:169:15:169:20 | access to local variable sink52 | +| LocalDataFlow.cs:197:15:197:20 | access to local variable sink20 | +| LocalDataFlow.cs:199:15:199:20 | access to local variable sink21 | +| LocalDataFlow.cs:201:15:201:20 | access to local variable sink22 | +| LocalDataFlow.cs:211:15:211:20 | access to local variable sink23 | +| LocalDataFlow.cs:219:15:219:20 | access to local variable sink24 | +| LocalDataFlow.cs:227:15:227:20 | access to local variable sink25 | +| LocalDataFlow.cs:235:15:235:20 | access to local variable sink26 | +| LocalDataFlow.cs:237:15:237:20 | access to local variable sink27 | +| LocalDataFlow.cs:239:15:239:20 | access to local variable sink28 | +| LocalDataFlow.cs:241:15:241:20 | access to local variable sink29 | +| LocalDataFlow.cs:243:15:243:20 | access to local variable sink30 | +| LocalDataFlow.cs:259:15:259:20 | access to local variable sink31 | +| LocalDataFlow.cs:261:15:261:20 | access to local variable sink32 | +| LocalDataFlow.cs:271:15:271:20 | access to local variable sink33 | +| LocalDataFlow.cs:273:15:273:20 | access to local variable sink48 | +| LocalDataFlow.cs:283:15:283:20 | access to local variable sink34 | +| LocalDataFlow.cs:285:15:285:20 | access to local variable sink35 | +| LocalDataFlow.cs:288:15:288:20 | access to local variable sink36 | +| LocalDataFlow.cs:300:15:300:20 | access to local variable sink40 | +| LocalDataFlow.cs:302:15:302:20 | access to local variable sink41 | +| LocalDataFlow.cs:304:15:304:20 | access to local variable sink42 | +| LocalDataFlow.cs:306:15:306:20 | access to local variable sink43 | +| LocalDataFlow.cs:321:15:321:19 | access to local variable sink3 | +| LocalDataFlow.cs:323:15:323:20 | access to local variable sink12 | +| LocalDataFlow.cs:325:15:325:20 | access to local variable sink13 | +| LocalDataFlow.cs:339:15:339:20 | access to local variable sink53 | +| LocalDataFlow.cs:341:15:341:20 | access to local variable sink54 | +| LocalDataFlow.cs:355:15:355:20 | access to local variable sink60 | +| LocalDataFlow.cs:364:19:364:24 | access to local variable sink61 | +| LocalDataFlow.cs:366:15:366:20 | access to local variable sink62 | +| LocalDataFlow.cs:368:15:368:20 | access to local variable sink63 | +| LocalDataFlow.cs:370:15:370:20 | access to local variable sink64 | +| LocalDataFlow.cs:372:15:372:20 | access to local variable sink65 | +| LocalDataFlow.cs:374:15:374:20 | access to local variable sink66 | +| LocalDataFlow.cs:392:15:392:20 | access to local variable sink67 | +| LocalDataFlow.cs:394:15:394:20 | access to local variable sink68 | +| LocalDataFlow.cs:404:15:404:20 | access to local variable sink69 | +| LocalDataFlow.cs:412:15:412:20 | access to local variable sink70 | +| LocalDataFlow.cs:420:19:420:24 | access to local variable sink71 | +| LocalDataFlow.cs:430:23:430:28 | access to local variable sink72 | +| LocalDataFlow.cs:466:15:466:21 | access to parameter tainted | +| SSA.cs:9:15:9:22 | access to local variable ssaSink0 | +| SSA.cs:25:15:25:22 | access to local variable ssaSink1 | +| SSA.cs:43:15:43:22 | access to local variable ssaSink2 | +| SSA.cs:60:15:60:22 | access to local variable ssaSink3 | +| SSA.cs:69:15:69:34 | access to field SsaFieldSink0 | +| SSA.cs:98:15:98:22 | access to local variable ssaSink4 | +| SSA.cs:124:15:124:34 | access to field SsaFieldSink1 | +| SSA.cs:180:15:180:22 | access to local variable ssaSink5 | +| Splitting.cs:8:19:8:19 | access to local variable x | +| Splitting.cs:12:15:12:15 | access to local variable x | +| Splitting.cs:25:15:25:15 | access to local variable x | +| Splitting.cs:27:19:27:19 | access to local variable x | +| Splitting.cs:29:19:29:19 | access to local variable x | diff --git a/csharp/ql/test/library-tests/dataflow/local/TaintTracking.ql b/csharp/ql/test/library-tests/dataflow/local/TaintTracking.ql index f7b5e4dab88..32b3e84d476 100644 --- a/csharp/ql/test/library-tests/dataflow/local/TaintTracking.ql +++ b/csharp/ql/test/library-tests/dataflow/local/TaintTracking.ql @@ -1,9 +1,15 @@ import csharp import Common +import semmle.code.csharp.controlflow.Guards -from MyFlowSource source, Access sink, string s +predicate step(DataFlow::Node pred, DataFlow::Node succ) { + TaintTracking::localTaintStep(pred, succ) and + not succ.asExpr() instanceof NullGuardedExpr +} + +from MyFlowSource source, DataFlow::Node sink, Access target where - TaintTracking::localTaintStep+(source, DataFlow::exprNode(sink)) and - exists(MethodCall mc | mc.getTarget().getName() = "Check" and mc.getAnArgument() = sink) and - s = sink.toString() -select s order by s + step+(source, sink) and + sink = DataFlow::exprNode(target) and + exists(MethodCall mc | mc.getTarget().getName() = "Check" and mc.getAnArgument() = target) +select sink diff --git a/csharp/ql/test/library-tests/dataflow/local/TaintTrackingStep.expected b/csharp/ql/test/library-tests/dataflow/local/TaintTrackingStep.expected index 7d41dc3ad68..355893339a1 100644 --- a/csharp/ql/test/library-tests/dataflow/local/TaintTrackingStep.expected +++ b/csharp/ql/test/library-tests/dataflow/local/TaintTrackingStep.expected @@ -14,6 +14,7 @@ | Capture.cs:58:21:58:21 | 1 | Capture.cs:58:17:58:21 | SSA def(i) | | Capture.cs:61:17:61:17 | 1 | Capture.cs:61:13:61:17 | SSA def(i) | | Capture.cs:63:9:63:17 | SSA call def(i) | Capture.cs:64:13:64:13 | access to local variable i | +| LocalDataFlow.cs:49:30:49:30 | b | LocalDataFlow.cs:96:21:96:21 | access to parameter b | | LocalDataFlow.cs:52:13:52:34 | SSA def(sink0) | LocalDataFlow.cs:53:15:53:19 | access to local variable sink0 | | LocalDataFlow.cs:52:21:52:34 | "taint source" | LocalDataFlow.cs:52:13:52:34 | SSA def(sink0) | | LocalDataFlow.cs:53:15:53:19 | access to local variable sink0 | LocalDataFlow.cs:61:18:61:22 | access to local variable sink0 | @@ -64,24 +65,24 @@ | LocalDataFlow.cs:85:15:85:22 | access to local variable nonSink0 | LocalDataFlow.cs:92:21:92:28 | access to local variable nonSink0 | | LocalDataFlow.cs:88:13:88:27 | SSA def(sink6) | LocalDataFlow.cs:89:15:89:19 | access to local variable sink6 | | LocalDataFlow.cs:88:22:88:26 | access to local variable sink5 | LocalDataFlow.cs:88:13:88:27 | SSA def(sink6) | -| LocalDataFlow.cs:89:15:89:19 | access to local variable sink6 | LocalDataFlow.cs:96:35:96:39 | access to local variable sink6 | +| LocalDataFlow.cs:89:15:89:19 | access to local variable sink6 | LocalDataFlow.cs:96:31:96:35 | access to local variable sink6 | | LocalDataFlow.cs:92:9:92:29 | SSA def(nonSink0) | LocalDataFlow.cs:93:15:93:22 | access to local variable nonSink0 | | LocalDataFlow.cs:92:21:92:28 | access to local variable nonSink0 | LocalDataFlow.cs:92:9:92:29 | SSA def(nonSink0) | -| LocalDataFlow.cs:96:13:96:39 | SSA def(sink7) | LocalDataFlow.cs:97:15:97:19 | access to local variable sink7 | -| LocalDataFlow.cs:96:21:96:21 | 1 | LocalDataFlow.cs:96:21:96:25 | ... > ... | -| LocalDataFlow.cs:96:21:96:25 | ... > ... | LocalDataFlow.cs:96:21:96:39 | ... ? ... : ... | -| LocalDataFlow.cs:96:21:96:39 | ... ? ... : ... | LocalDataFlow.cs:96:13:96:39 | SSA def(sink7) | -| LocalDataFlow.cs:96:25:96:25 | 2 | LocalDataFlow.cs:96:21:96:25 | ... > ... | -| LocalDataFlow.cs:96:29:96:31 | "a" | LocalDataFlow.cs:96:21:96:39 | ... ? ... : ... | -| LocalDataFlow.cs:96:35:96:39 | access to local variable sink6 | LocalDataFlow.cs:96:21:96:39 | ... ? ... : ... | -| LocalDataFlow.cs:97:15:97:19 | access to local variable sink7 | LocalDataFlow.cs:104:29:104:33 | access to local variable sink7 | -| LocalDataFlow.cs:100:9:100:41 | SSA def(nonSink0) | LocalDataFlow.cs:101:15:101:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:100:20:100:20 | 4 | LocalDataFlow.cs:100:20:100:25 | ... == ... | -| LocalDataFlow.cs:100:20:100:25 | ... == ... | LocalDataFlow.cs:100:20:100:41 | ... ? ... : ... | -| LocalDataFlow.cs:100:20:100:41 | ... ? ... : ... | LocalDataFlow.cs:100:9:100:41 | SSA def(nonSink0) | -| LocalDataFlow.cs:100:25:100:25 | 2 | LocalDataFlow.cs:100:20:100:25 | ... == ... | -| LocalDataFlow.cs:100:29:100:33 | "abc" | LocalDataFlow.cs:100:20:100:41 | ... ? ... : ... | -| LocalDataFlow.cs:100:37:100:41 | "def" | LocalDataFlow.cs:100:20:100:41 | ... ? ... : ... | +| LocalDataFlow.cs:96:13:96:35 | [b (line 49): false] SSA def(sink7) | LocalDataFlow.cs:97:15:97:19 | access to local variable sink7 | +| LocalDataFlow.cs:96:13:96:35 | [b (line 49): true] SSA def(sink7) | LocalDataFlow.cs:97:15:97:19 | access to local variable sink7 | +| LocalDataFlow.cs:96:21:96:21 | access to parameter b | LocalDataFlow.cs:96:21:96:35 | ... ? ... : ... | +| LocalDataFlow.cs:96:21:96:21 | access to parameter b | LocalDataFlow.cs:100:20:100:20 | access to parameter b | +| LocalDataFlow.cs:96:21:96:35 | ... ? ... : ... | LocalDataFlow.cs:96:13:96:35 | [b (line 49): false] SSA def(sink7) | +| LocalDataFlow.cs:96:21:96:35 | ... ? ... : ... | LocalDataFlow.cs:96:13:96:35 | [b (line 49): true] SSA def(sink7) | +| LocalDataFlow.cs:96:25:96:27 | "a" | LocalDataFlow.cs:96:21:96:35 | ... ? ... : ... | +| LocalDataFlow.cs:96:31:96:35 | access to local variable sink6 | LocalDataFlow.cs:96:21:96:35 | ... ? ... : ... | +| LocalDataFlow.cs:97:15:97:19 | access to local variable sink7 | LocalDataFlow.cs:100:9:100:36 | SSA phi(sink7) | +| LocalDataFlow.cs:100:9:100:36 | SSA def(nonSink0) | LocalDataFlow.cs:101:15:101:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:100:9:100:36 | SSA phi(sink7) | LocalDataFlow.cs:104:29:104:33 | access to local variable sink7 | +| LocalDataFlow.cs:100:20:100:20 | access to parameter b | LocalDataFlow.cs:100:20:100:36 | ... ? ... : ... | +| LocalDataFlow.cs:100:20:100:36 | ... ? ... : ... | LocalDataFlow.cs:100:9:100:36 | SSA def(nonSink0) | +| LocalDataFlow.cs:100:24:100:28 | "abc" | LocalDataFlow.cs:100:20:100:36 | ... ? ... : ... | +| LocalDataFlow.cs:100:32:100:36 | "def" | LocalDataFlow.cs:100:20:100:36 | ... ? ... : ... | | LocalDataFlow.cs:101:15:101:22 | access to local variable nonSink0 | LocalDataFlow.cs:108:32:108:39 | access to local variable nonSink0 | | LocalDataFlow.cs:104:13:104:33 | SSA def(sink8) | LocalDataFlow.cs:105:15:105:19 | access to local variable sink8 | | LocalDataFlow.cs:104:21:104:33 | (...) ... | LocalDataFlow.cs:104:13:104:33 | SSA def(sink8) | @@ -802,3 +803,77 @@ | SSA.cs:177:21:177:28 | access to local variable ssaSink5 | SSA.cs:176:21:176:28 | access to local variable ssaSink5 | | SSA.cs:177:21:177:28 | access to local variable ssaSink5 | SSA.cs:180:9:180:24 | SSA phi(ssaSink5) | | SSA.cs:180:9:180:24 | SSA phi(ssaSink5) | SSA.cs:180:15:180:22 | access to local variable ssaSink5 | +| Splitting.cs:3:18:3:18 | b | Splitting.cs:6:13:6:13 | access to parameter b | +| Splitting.cs:3:28:3:34 | tainted | Splitting.cs:5:17:5:23 | access to parameter tainted | +| Splitting.cs:5:13:5:23 | SSA def(x) | Splitting.cs:8:19:8:19 | access to local variable x | +| Splitting.cs:5:13:5:23 | SSA def(x) | Splitting.cs:12:15:12:15 | access to local variable x | +| Splitting.cs:5:17:5:23 | access to parameter tainted | Splitting.cs:5:13:5:23 | SSA def(x) | +| Splitting.cs:6:13:6:13 | access to parameter b | Splitting.cs:13:13:13:13 | access to parameter b | +| Splitting.cs:8:19:8:19 | access to local variable x | Splitting.cs:9:17:9:17 | access to local variable x | +| Splitting.cs:9:17:9:17 | access to local variable x | Splitting.cs:9:17:9:25 | ... == ... | +| Splitting.cs:12:15:12:15 | access to local variable x | Splitting.cs:14:19:14:19 | access to local variable x | +| Splitting.cs:17:18:17:18 | b | Splitting.cs:20:13:20:13 | access to parameter b | +| Splitting.cs:19:13:19:18 | SSA def(x) | Splitting.cs:22:19:22:19 | access to local variable x | +| Splitting.cs:19:13:19:18 | SSA def(x) | Splitting.cs:25:15:25:15 | access to local variable x | +| Splitting.cs:19:17:19:18 | "" | Splitting.cs:19:13:19:18 | SSA def(x) | +| Splitting.cs:20:13:20:13 | access to parameter b | Splitting.cs:26:13:26:13 | access to parameter b | +| Splitting.cs:23:13:23:30 | [b (line 17): true] SSA def(x) | Splitting.cs:25:15:25:15 | access to local variable x | +| Splitting.cs:23:17:23:30 | "taint source" | Splitting.cs:23:13:23:30 | [b (line 17): true] SSA def(x) | +| Splitting.cs:25:15:25:15 | access to local variable x | Splitting.cs:27:19:27:19 | access to local variable x | +| Splitting.cs:25:15:25:15 | access to local variable x | Splitting.cs:29:19:29:19 | access to local variable x | +| Splitting.cs:32:18:32:18 | b | Splitting.cs:35:13:35:13 | access to parameter b | +| Splitting.cs:35:13:35:13 | access to parameter b | Splitting.cs:39:15:39:15 | access to parameter b | +| Splitting.cs:37:9:37:15 | [b (line 32): false] SSA def(x) | Splitting.cs:38:15:38:15 | access to local variable x | +| Splitting.cs:37:9:37:15 | [b (line 32): true] SSA def(x) | Splitting.cs:38:15:38:15 | access to local variable x | +| Splitting.cs:37:13:37:15 | "b" | Splitting.cs:37:9:37:15 | [b (line 32): false] SSA def(x) | +| Splitting.cs:37:13:37:15 | "b" | Splitting.cs:37:9:37:15 | [b (line 32): true] SSA def(x) | +| Splitting.cs:38:15:38:15 | access to local variable x | Splitting.cs:39:19:39:19 | access to local variable x | +| Splitting.cs:39:15:39:15 | access to parameter b | Splitting.cs:39:15:39:25 | ... ? ... : ... | +| Splitting.cs:39:15:39:15 | access to parameter b | Splitting.cs:42:13:42:13 | access to parameter b | +| Splitting.cs:39:19:39:19 | access to local variable x | Splitting.cs:39:15:39:25 | ... ? ... : ... | +| Splitting.cs:39:23:39:25 | "c" | Splitting.cs:39:15:39:25 | ... ? ... : ... | +| Splitting.cs:40:23:40:23 | access to local variable x | Splitting.cs:40:15:40:23 | (...) ... | +| Splitting.cs:41:19:41:21 | "d" | Splitting.cs:41:15:41:21 | ... = ... | +| Splitting.cs:46:18:46:18 | b | Splitting.cs:49:13:49:13 | access to parameter b | +| Splitting.cs:48:13:48:18 | SSA def(x) | Splitting.cs:53:13:53:13 | access to local variable x | +| Splitting.cs:48:17:48:18 | "" | Splitting.cs:48:13:48:18 | SSA def(x) | +| Splitting.cs:49:13:49:13 | access to parameter b | Splitting.cs:60:13:60:13 | access to parameter b | +| Splitting.cs:50:13:50:21 | [b (line 46): true] SSA def(x) | Splitting.cs:53:13:53:13 | access to local variable x | +| Splitting.cs:50:17:50:21 | "abc" | Splitting.cs:50:13:50:21 | [b (line 46): true] SSA def(x) | +| Splitting.cs:51:13:51:36 | [b (line 46): false] SSA def(y) | Splitting.cs:52:9:52:9 | access to local variable y | +| Splitting.cs:51:13:51:36 | [b (line 46): true] SSA def(y) | Splitting.cs:52:9:52:9 | access to local variable y | +| Splitting.cs:51:17:51:36 | array creation of type String[] | Splitting.cs:51:13:51:36 | [b (line 46): false] SSA def(y) | +| Splitting.cs:51:17:51:36 | array creation of type String[] | Splitting.cs:51:13:51:36 | [b (line 46): true] SSA def(y) | +| Splitting.cs:51:32:51:34 | "a" | Splitting.cs:51:17:51:36 | array creation of type String[] | +| Splitting.cs:52:9:52:9 | access to local variable y | Splitting.cs:52:9:52:12 | access to array element | +| Splitting.cs:52:9:52:9 | access to local variable y | Splitting.cs:53:17:53:17 | access to local variable y | +| Splitting.cs:52:16:52:18 | "b" | Splitting.cs:52:9:52:9 | access to local variable y | +| Splitting.cs:53:9:53:20 | [b (line 46): false] SSA def(x) | Splitting.cs:54:17:54:17 | access to local variable x | +| Splitting.cs:53:9:53:20 | [b (line 46): true] SSA def(x) | Splitting.cs:54:17:54:17 | access to local variable x | +| Splitting.cs:53:13:53:13 | access to local variable x | Splitting.cs:53:13:53:20 | ... + ... | +| Splitting.cs:53:13:53:20 | ... + ... | Splitting.cs:53:9:53:20 | [b (line 46): false] SSA def(x) | +| Splitting.cs:53:13:53:20 | ... + ... | Splitting.cs:53:9:53:20 | [b (line 46): true] SSA def(x) | +| Splitting.cs:53:17:53:17 | access to local variable y | Splitting.cs:53:17:53:20 | access to array element | +| Splitting.cs:53:17:53:17 | access to local variable y | Splitting.cs:57:17:57:17 | access to local variable y | +| Splitting.cs:53:17:53:20 | access to array element | Splitting.cs:53:13:53:20 | ... + ... | +| Splitting.cs:54:13:54:23 | [b (line 46): false] SSA def(z) | Splitting.cs:55:14:55:14 | access to local variable z | +| Splitting.cs:54:13:54:23 | [b (line 46): true] SSA def(z) | Splitting.cs:55:14:55:14 | access to local variable z | +| Splitting.cs:54:17:54:17 | access to local variable x | Splitting.cs:54:17:54:23 | ... == ... | +| Splitting.cs:54:17:54:17 | access to local variable x | Splitting.cs:56:17:56:17 | access to local variable x | +| Splitting.cs:54:17:54:23 | ... == ... | Splitting.cs:54:13:54:23 | [b (line 46): false] SSA def(z) | +| Splitting.cs:54:17:54:23 | ... == ... | Splitting.cs:54:13:54:23 | [b (line 46): true] SSA def(z) | +| Splitting.cs:55:14:55:14 | access to local variable z | Splitting.cs:55:13:55:14 | !... | +| Splitting.cs:56:9:56:19 | [b (line 46): false] SSA def(x) | Splitting.cs:57:14:57:14 | access to local variable x | +| Splitting.cs:56:9:56:19 | [b (line 46): true] SSA def(x) | Splitting.cs:57:14:57:14 | access to local variable x | +| Splitting.cs:56:13:56:19 | $"..." | Splitting.cs:56:9:56:19 | [b (line 46): false] SSA def(x) | +| Splitting.cs:56:13:56:19 | $"..." | Splitting.cs:56:9:56:19 | [b (line 46): true] SSA def(x) | +| Splitting.cs:56:15:56:15 | "c" | Splitting.cs:56:13:56:19 | $"..." | +| Splitting.cs:56:17:56:17 | access to local variable x | Splitting.cs:56:13:56:19 | $"..." | +| Splitting.cs:57:13:57:18 | (..., ...) | Splitting.cs:57:13:57:24 | access to field Item1 | +| Splitting.cs:57:14:57:14 | access to local variable x | Splitting.cs:57:13:57:18 | (..., ...) | +| Splitting.cs:57:17:57:17 | access to local variable y | Splitting.cs:57:13:57:18 | (..., ...) | +| Splitting.cs:57:17:57:17 | access to local variable y | Splitting.cs:58:27:58:27 | access to local variable y | +| Splitting.cs:58:22:58:22 | [b (line 46): false] SSA def(s) | Splitting.cs:59:19:59:19 | access to local variable s | +| Splitting.cs:58:22:58:22 | [b (line 46): true] SSA def(s) | Splitting.cs:59:19:59:19 | access to local variable s | +| Splitting.cs:58:27:58:27 | access to local variable y | Splitting.cs:58:22:58:22 | [b (line 46): false] SSA def(s) | +| Splitting.cs:58:27:58:27 | access to local variable y | Splitting.cs:58:22:58:22 | [b (line 46): true] SSA def(s) | From b2f99dbbc75bce10ff8a7bc4eb42b4648b301293 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Thu, 3 Jan 2019 15:28:15 +0100 Subject: [PATCH 05/33] C#: Teach data flow library about CFG splitting Data flow nodes for expressions do not take CFG splitting into account. Example: ``` if (b) x = tainted; x = x.ToLower(); if (!b) Use(x); ``` Flow is incorrectly reported from `tainted` to `x` in `Use(x)`, because the step from `tainted` to `x.ToLower()` throws away the information that `b = true`. The solution is to remember the splitting in data flow expression nodes, that is, to represent the exact control flow node instead of just the expression. With that we get flow from `tainted` to `[b = true] x.ToLower()`, but not from `tainted` to `[b = false] x.ToLower()`. The data flow API remains unchanged, but in order for analyses to fully benefit from CFG splitting, sanitizers in particular should be CFG-based instead of expression-based: ``` if (b) x = tainted; if (IsInvalid(x)) return; Use(x); ``` If the call to `IsInvalid()` is a sanitizer, then defining an expression node to be a sanitizer using `GuardedExpr` will be too conservative (`x` in `Use(x)` is in fact not guarded). However, `[b = true] x` in `[b = true] Use(x)` is guarded, and to help defining guard-based sanitizers, the class `GuardedDataFlowNode` has been introduced. --- .../ql/src/semmle/code/csharp/Assignable.qll | 14 +- csharp/ql/src/semmle/code/csharp/Stmt.qll | 3 + .../semmle/code/csharp/controlflow/Guards.qll | 64 +++ .../semmle/code/csharp/dataflow/DataFlow.qll | 372 +++++++++++++++--- .../code/csharp/dataflow/TaintTracking.qll | 216 ++++++---- .../ql/src/semmle/code/csharp/exprs/Call.qll | 13 +- .../ql/src/semmle/code/csharp/exprs/Expr.qll | 5 +- .../csharp/security/dataflow/TaintedPath.qll | 6 +- .../csharp/security/dataflow/UrlRedirect.qll | 5 +- .../code/csharp/security/dataflow/ZipSlip.qll | 6 +- .../csharp7/LocalTaintFlow.expected | 6 - .../csharp7/TupleAccess.expected | 6 +- .../dataflow/callablereturnsarg/Common.qll | 5 +- .../dataflow/global/DataFlow.expected | 3 +- .../dataflow/global/DataFlowPath.expected | 36 +- .../dataflow/global/TaintTracking.expected | 3 +- .../global/TaintTrackingPath.expected | 36 +- .../dataflow/local/DataFlow.expected | 7 +- .../library-tests/dataflow/local/DataFlow.ql | 2 +- .../dataflow/local/DataFlowStep.expected | 135 ++++--- .../dataflow/local/TaintTracking.expected | 10 +- .../dataflow/local/TaintTracking.ql | 2 +- .../dataflow/local/TaintTrackingStep.expected | 186 +++++---- .../library-tests/dispatch/CallGraph.expected | 3 +- .../dispatch/GetADynamicTarget.expected | 2 +- .../library-tests/dispatch/ViableCallable.cs | 4 +- .../CWE-209/ExceptionInformationExposure.cs | 5 +- 27 files changed, 811 insertions(+), 344 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/Assignable.qll b/csharp/ql/src/semmle/code/csharp/Assignable.qll index 96022dd22b1..92de7230866 100644 --- a/csharp/ql/src/semmle/code/csharp/Assignable.qll +++ b/csharp/ql/src/semmle/code/csharp/Assignable.qll @@ -39,6 +39,12 @@ class AssignableMemberAccess extends MemberAccess, AssignableAccess { override AssignableMember getTarget() { result = AssignableAccess.super.getTarget() } } +private predicate nameOfChild(NameOfExpr noe, Expr child) { + child = noe + or + exists(Expr mid | nameOfChild(noe, mid) | child = mid.getAChildExpr()) +} + /** * An access to an assignable that reads the underlying value. Either a * variable read (`VariableRead`), a property read (`PropertyRead`), an @@ -67,7 +73,7 @@ class AssignableRead extends AssignableAccess { or this = any(AssignableDefinitions::AddressOfDefinition def).getTargetAccess() ) and - not this = any(NameOfExpr noe).getAChildExpr*() + not nameOfChild(_, this) } /** @@ -669,6 +675,9 @@ module AssignableDefinitions { IsPatternDefinition() { this = TIsPatternDefinition(ipe) } + /** Gets the underlying `is` expression. */ + IsPatternExpr getIsPatternExpr() { result = ipe } + /** Gets the underlying local variable declaration. */ LocalVariableDeclExpr getDeclaration() { result = ipe.getVariableDeclExpr() } @@ -696,6 +705,9 @@ module AssignableDefinitions { TypeCasePatternDefinition() { this = TTypeCasePatternDefinition(tc) } + /** Gets the underlying `case` statement. */ + TypeCase getTypeCase() { result = tc } + /** Gets the underlying local variable declaration. */ LocalVariableDeclExpr getDeclaration() { result = tc.getVariableDeclExpr() } diff --git a/csharp/ql/src/semmle/code/csharp/Stmt.qll b/csharp/ql/src/semmle/code/csharp/Stmt.qll index 51f1ccaefb0..2adbb38902b 100644 --- a/csharp/ql/src/semmle/code/csharp/Stmt.qll +++ b/csharp/ql/src/semmle/code/csharp/Stmt.qll @@ -262,6 +262,9 @@ class CaseStmt extends Stmt, @case { * ``` */ Expr getCondition() { result = this.getChild(2) } + + /** Gets the `switch` statement that this `case` statement belongs to. */ + SwitchStmt getSwitchStmt() { result.getACase() = this } } /** diff --git a/csharp/ql/src/semmle/code/csharp/controlflow/Guards.qll b/csharp/ql/src/semmle/code/csharp/controlflow/Guards.qll index 34e8889e099..856a45ad711 100644 --- a/csharp/ql/src/semmle/code/csharp/controlflow/Guards.qll +++ b/csharp/ql/src/semmle/code/csharp/controlflow/Guards.qll @@ -581,6 +581,63 @@ class GuardedControlFlowNode extends ControlFlow::Nodes::ElementNode { } } +/** + * A guarded data flow node. A guarded data flow node is like a guarded expression + * (`GuardedExpr`), except control flow graph splitting is taken into account. That + * is, one data flow node belonging to an expression may be guarded, while another + * split need not be guarded: + * + * ``` + * if (b) + * if (x == null) + * return; + * x.ToString(); + * if (b) + * ... + * ``` + * + * In the example above, the node for `x.ToString()` is null-guarded in the + * split `b == true`, but not in the split `b == false`. + */ +class GuardedDataFlowNode extends DataFlow::ExprNode { + private Guard g; + private AccessOrCallExpr sub0; + private AbstractValue v0; + + GuardedDataFlowNode() { + exists(ControlFlow::Nodes::ElementNode cfn | + exists(this.getExprAtNode(cfn)) | + isGuardedByNode(cfn, g, sub0, v0) + ) + } + + /** + * Gets an expression that guards this data flow node. That is, this data flow + * node is only reached when the returned expression has abstract value `v`. + * + * The expression `sub` is a sub expression of the guarding expression that is + * structurally equal to the expression belonging to this data flow node. + * + * In case this data flow node or `sub` accesses an SSA variable in its + * left-most qualifier, then so must the other (accessing the same SSA + * variable). + */ + Expr getAGuard(Expr sub, AbstractValue v) { + result = g and + sub = sub0 and + v = v0 + } + + /** + * Holds if this data flow node must have abstract value `v`. That is, this + * data flow node is guarded by a structurally equal expression having + * abstract value `v`. + */ + predicate mustHaveValue(AbstractValue v) { + exists(Expr e | e = this.getAGuard(e, v)) + } +} + /** An expression guarded by a `null` check. */ class NullGuardedExpr extends GuardedExpr { NullGuardedExpr() { @@ -588,6 +645,13 @@ class NullGuardedExpr extends GuardedExpr { } } +/** A data flow node guarded by a `null` check. */ +class NullGuardedDataFlowNode extends GuardedDataFlowNode { + NullGuardedDataFlowNode() { + this.mustHaveValue(any(NullValue v | not v.isNull())) + } +} + /** INTERNAL: Do not use. */ module Internal { private import ControlFlow::Internal diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/DataFlow.qll b/csharp/ql/src/semmle/code/csharp/dataflow/DataFlow.qll index 2af9d3d3e27..1d4cd002ebe 100755 --- a/csharp/ql/src/semmle/code/csharp/dataflow/DataFlow.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/DataFlow.qll @@ -21,6 +21,12 @@ module DataFlow { /** Gets the expression corresponding to this node, if any. */ DotNet::Expr asExpr() { result = this.(ExprNode).getExpr() } + /** Gets the expression corresponding to this node, at control flow node `cfn`, if any. */ + Expr asExprAtNode(ControlFlow::Nodes::ElementNode cfn) { + this = TExprNode(cfn) and + result = cfn.getElement() + } + /** Gets the parameter corresponding to this node, if any. */ DotNet::Parameter asParameter() { result = this.(ParameterNode).getParameter() } @@ -41,30 +47,47 @@ module DataFlow { /** * An expression, viewed as a node in a data flow graph. */ - class ExprNode extends Node, TExprNode { - DotNet::Expr expr; - - ExprNode() { this = TExprNode(expr) } + class ExprNode extends Node { + ExprNode() { this = TExprNode(_) or this = TCilExprNode(_) } /** Gets the expression corresponding to this node. */ - DotNet::Expr getExpr() { result = expr } + DotNet::Expr getExpr() { + result = this.getExprAtNode(_) + or + this = TCilExprNode(result) + } - override DotNet::Type getType() { result = expr.getType() } + /** Gets the expression corresponding to this node, at control flow node `cfn`. */ + Expr getExprAtNode(ControlFlow::Nodes::ElementNode cfn) { + this = TExprNode(cfn) and + result = cfn.getElement() + } - override DotNet::Callable getEnclosingCallable() { result = expr.getEnclosingCallable() } + override DotNet::Type getType() { result = this.getExpr().getType() } + + override DotNet::Callable getEnclosingCallable() { result = this.getExpr().getEnclosingCallable() } override string toString() { - result = expr.(Expr).toString() + exists(ControlFlow::Nodes::ElementNode cfn | + this = TExprNode(cfn) | + result = cfn.toString() + ) or - expr instanceof CIL::Expr and + this = TCilExprNode(_) and result = "CIL expression" } override Location getLocation() { - result = expr.(Expr).getLocation() + exists(ControlFlow::Nodes::ElementNode cfn | + this = TExprNode(cfn) | + result = cfn.getLocation() + ) or result.getFile().isPdbSourceFile() and - result = expr.(CIL::Expr).getALocation() + exists(CIL::Expr e | + this = TCilExprNode(e) | + result = e.getALocation() + ) } } @@ -83,9 +106,7 @@ module DataFlow { DotNet::Parameter getParameter() { none() } } - /** - * Gets the node corresponding to expression `e`. - */ + /** Gets a node corresponding to expression `e`. */ ExprNode exprNode(DotNet::Expr e) { result.getExpr() = e } /** @@ -258,9 +279,7 @@ module DataFlow { } } - /** - * INTERNAL: Do not use. - */ + /** INTERNAL: Do not use. */ module Internal { private import semmle.code.csharp.dataflow.DelegateDataFlow private import semmle.code.csharp.dispatch.Dispatch @@ -473,6 +492,9 @@ module DataFlow { /** Gets the context corresponding to this argument node. */ bindingset [config] abstract ArgumentContext getContext(Configuration config); + + /** Holds if this argument node does not have an associated control flow node. */ + abstract predicate hasNoControlFlowNode(); } /** A data flow node that represents an explicit call argument. */ @@ -511,6 +533,11 @@ module DataFlow { override ExplicitArgumentContext getContext(Configuration config) { result.getCallContext() = this.getArgumentCallContext(config) } + + override predicate hasNoControlFlowNode() { + this.asExpr() instanceof CIL::Expr or + this instanceof ImplicitDelegateCallNode + } } /** @@ -558,6 +585,8 @@ module DataFlow { exists(config) // eliminate warning } + override predicate hasNoControlFlowNode() { any() } + override Type getType() { result = v.getType() } override Callable getEnclosingCallable() { result = c.getEnclosingCallable() } @@ -699,9 +728,181 @@ module DataFlow { } /** - * Provides predicates related to local data flow. + * A helper class for defining expression-based data flow steps, while properly + * taking control flow into account. */ + abstract class ExprStep extends string { + bindingset[this] + ExprStep() { any() } + + /** + * Holds if data can flow from expression `exprFrom` to expression `exprTo`, + * but only by following control flow successors (resp. predecessors, as + * specified by `isSuccesor`) inside the scope `scope`. The Boolean `exactScope` + * indicates whether a transitive child of `scope` is allowed + * (`exactScope = false`). + */ + predicate stepsToExpr(Expr exprFrom, Expr exprTo, ControlFlowElement scope, boolean exactScope, boolean isSuccessor) { none() } + + /** + * Holds if data can flow from expression `exprFrom` to definition `defTo`, + * but only by following control flow successors (resp. predecessors, as + * specified by `isSuccesor`) inside the scope `scope`. The Bolean `exactScope` + * indicates whether a transitive child of `scope` is allowed (`exactScope = false`). + */ + predicate stepsToDefinition(Expr exprFrom, AssignableDefinition defTo, ControlFlowElement scope, boolean exactScope, boolean isSuccessor) { none() } + + private predicate reachesBasicBlockExprRec(Expr exprFrom, Expr exprTo, ControlFlowElement scope, boolean exactScope, boolean isSuccessor, ControlFlow::Nodes::ElementNode cfnFrom, ControlFlow::BasicBlock bb) { + exists(ControlFlow::BasicBlock mid | + this.reachesBasicBlockExpr(exprFrom, exprTo, scope, exactScope, isSuccessor, cfnFrom, mid) | + isSuccessor = true and + bb = mid.getASuccessor() + or + isSuccessor = false and + bb = mid.getAPredecessor() + ) + } + + pragma[nomagic] + private predicate reachesBasicBlockExpr(Expr exprFrom, Expr exprTo, ControlFlowElement scope, boolean exactScope, boolean isSuccessor, ControlFlow::Nodes::ElementNode cfnFrom, ControlFlow::BasicBlock bb) { + this.stepsToExpr(exprFrom, exprTo, scope, exactScope, isSuccessor) and + cfnFrom = exprFrom.getAControlFlowNode() and + bb = cfnFrom.getBasicBlock() + or + exists(ControlFlowElement scope0, boolean exactScope0 | + this.reachesBasicBlockExprRec(exprFrom, exprTo, scope0, exactScope0, isSuccessor, cfnFrom, bb) and + this.stepsToExpr(exprFrom, exprTo, scope, exactScope, isSuccessor) + | + exactScope0 = false and + bb.getANode().getElement() = scope0.getAChild*() + or + exactScope0 = true and + bb.getANode().getElement() = scope0 + ) + } + + private predicate reachesBasicBlockDefinitionRec(Expr exprFrom, AssignableDefinition defTo, ControlFlowElement scope, boolean exactScope, boolean isSuccessor, ControlFlow::Nodes::ElementNode cfnFrom, ControlFlow::BasicBlock bb) { + exists(ControlFlow::BasicBlock mid | + this.reachesBasicBlockDefinition(exprFrom, defTo, scope, exactScope, isSuccessor, cfnFrom, mid) | + isSuccessor = true and + bb = mid.getASuccessor() + or + isSuccessor = false and + bb = mid.getAPredecessor() + ) + } + + + pragma[nomagic] + private predicate reachesBasicBlockDefinition(Expr exprFrom, AssignableDefinition defTo, ControlFlowElement scope, boolean exactScope, boolean isSuccessor, ControlFlow::Nodes::ElementNode cfnFrom, ControlFlow::BasicBlock bb) { + this.stepsToDefinition(exprFrom, defTo, scope, exactScope, isSuccessor) and + cfnFrom = exprFrom.getAControlFlowNode() and + bb = cfnFrom.getBasicBlock() + or + exists(ControlFlowElement scope0, boolean exactScope0 | + this.reachesBasicBlockDefinitionRec(exprFrom, defTo, scope0, exactScope0, isSuccessor, cfnFrom, bb) and + this.stepsToDefinition(exprFrom, defTo, scope, exactScope, isSuccessor) + | + exactScope0 = false and + bb.getANode().getElement() = scope0.getAChild*() + or + exactScope0 = true and + bb.getANode().getElement() = scope0 + ) + } + + private predicate hasExprStep(ExprNode nodeFrom, ExprNode nodeTo) { + exists(Expr exprFrom, Expr exprTo, ControlFlow::Nodes::ElementNode cfnFrom, ControlFlow::BasicBlock bb | + this.reachesBasicBlockExpr(exprFrom, exprTo, _, _, _, cfnFrom, bb) | + exprFrom = nodeFrom.asExprAtNode(cfnFrom) and + exprTo = nodeTo.asExprAtNode(bb.getANode()) + ) + } + + private predicate hasSsaDefinitionStep(ExprNode nodeFrom, SsaDefinitionNode nodeTo) { + exists(Expr exprFrom, AssignableDefinition defTo, Ssa::ExplicitDefinition ssaDef, ControlFlow::Nodes::ElementNode cfnFrom, ControlFlow::BasicBlock bb | + this.reachesBasicBlockDefinition(exprFrom, defTo, _, _, _, cfnFrom, bb) | + exprFrom = nodeFrom.asExprAtNode(cfnFrom) and + ssaDef.getADefinition() = defTo and + ssaDef.getBasicBlock() = bb and + nodeTo.getDefinition() = ssaDef + ) + } + + /** + * Holds if `stepsTo(Expr|SsaDefintion)()` induce a data flow step from + * `nodeFrom` to `nodeTo`. + */ + predicate hasStep(ExprNode nodeFrom, Node nodeTo) { + this.hasExprStep(nodeFrom, nodeTo) or + this.hasSsaDefinitionStep(nodeFrom, nodeTo) + } + } + + /** Provides predicates related to local data flow. */ module LocalFlow { + private class LocalExprStep extends ExprStep { + LocalExprStep() { this = "LocalExprStep" } + + override predicate stepsToExpr(Expr exprFrom, Expr exprTo, ControlFlowElement scope, boolean exactScope, boolean isSuccessor) { + exactScope = false and + ( + // Flow using library code + libraryFlow(exprFrom, exprTo, scope, true) and + (isSuccessor = false or isSuccessor = true) + or + exprFrom = exprTo.(ParenthesizedExpr).getExpr() and + scope = exprTo and + isSuccessor = true + or + exprTo = any(ConditionalExpr ce | + exprFrom = ce.getThen() or + exprFrom = ce.getElse() + ) and + scope = exprTo and + isSuccessor = false + or + exprFrom = exprTo.(Cast).getExpr() and + scope = exprTo and + isSuccessor = true + or + exprFrom = exprTo.(AwaitExpr).getExpr() and + scope = exprTo and + isSuccessor = true + or + // An `=` expression, where the result of the expression is used + exprTo = any(AssignExpr ae | + ae.getParent() instanceof Expr and + exprFrom = ae.getRValue() + ) and + scope = exprTo and + isSuccessor = true + ) + } + + override predicate stepsToDefinition(Expr exprFrom, AssignableDefinition def, ControlFlowElement scope, boolean exactScope, boolean isSuccessor) { + // Flow from source to definition + exactScope = false and + def.getSource() = exprFrom and + ( + scope = def.getExpr() and + isSuccessor = true + or + scope = def.(AssignableDefinitions::IsPatternDefinition).getIsPatternExpr() and + isSuccessor = false + or + exists(SwitchStmt ss | + ss = def.(AssignableDefinitions::TypeCasePatternDefinition).getTypeCase().getSwitchStmt() and + isSuccessor = true + | + scope = ss.getCondition() + or + scope = ss.getACase() + ) + ) + } + } + /** * Holds if data flows from `nodeFrom` to `nodeTo` in exactly one local * (intra-procedural) step. @@ -709,18 +910,20 @@ module DataFlow { cached predicate step(Node nodeFrom, Node nodeTo) { forceCachingInSameStage() and - localFlowStepExpr(nodeFrom.asExpr(), nodeTo.asExpr()) - or - // Flow from source to SSA definition - exists(Ssa::ExplicitDefinition def | - def.getADefinition().getSource() = nodeFrom.asExpr() | - nodeTo.(SsaDefinitionNode).getDefinition() = def - ) + TaintTracking::Internal::Cached::forceCachingInSameStage() and + any(LocalExprStep x).hasStep(nodeFrom, nodeTo) or // Flow from SSA definition to first read - exists(Ssa::Definition def | + exists(Ssa::Definition def, ControlFlow::Node cfn | def = nodeFrom.(SsaDefinitionNode).getDefinition() | - nodeTo.asExpr() = def.getAFirstRead() + nodeTo.asExprAtNode(cfn) = def.getAFirstReadAtNode(cfn) + ) + or + // Flow from read to next read + exists(ControlFlow::Node cfnFrom, ControlFlow::Node cfnTo | + Ssa::Internal::adjacentReadPairSameVar(cfnFrom, cfnTo) | + nodeFrom = TExprNode(cfnFrom) and + nodeTo = TExprNode(cfnTo) ) or // Flow into SSA pseudo definition @@ -779,9 +982,9 @@ module DataFlow { def = nodeFrom.(SsaDefinitionNode).getDefinition() and not exists(def.getARead()) or - exists(AssignableRead read | - read = nodeFrom.asExpr() | - def.getALastRead() = read + exists(AssignableRead read, ControlFlow::Node cfn | + read = nodeFrom.asExprAtNode(cfn) | + def.getALastReadAtNode(cfn) = read ) } @@ -794,34 +997,25 @@ module DataFlow { ) } - private predicate localFlowStepExpr(Expr exprFrom, Expr exprTo) { - // Flow using library code - libraryFlow(exprFrom, exprTo, true) + private Expr getALibraryFlowParent(Expr exprFrom, Expr exprTo, boolean preservesValue) { + libraryFlow(exprFrom, exprTo, preservesValue) and + result = exprFrom or - // Flow from read to next read - exprTo = exprFrom.(AssignableRead).getANextRead() - or - exprFrom = exprTo.(ParenthesizedExpr).getExpr() - or - exprTo = any(ConditionalExpr ce | - exprFrom = ce.getThen() or - exprFrom = ce.getElse() - ) - or - exprFrom = exprTo.(Cast).getExpr() - or - exprFrom = exprTo.(AwaitExpr).getExpr() - or - // An `=` expression, where the result of the expression is used - exprTo = any(AssignExpr ae | - ae.getParent() instanceof Expr and - exprFrom = ae.getRValue() + exists(Expr mid | + mid = getALibraryFlowParent(exprFrom, exprTo, preservesValue) | + result.getAChildExpr() = mid and + not mid.getAChildExpr*() = exprTo ) } + predicate libraryFlow(Expr exprFrom, Expr exprTo, Expr scope, boolean preservesValue) { + scope = getALibraryFlowParent(exprFrom, exprTo, preservesValue) and + scope.getAChildExpr*() = exprTo + } + predicate localFlowStepNoConfig(Node pred, Node succ) { localFlowStep(pred, succ) or - flowThroughCallableLibraryOutRef(_, pred.asExpr(), succ, true) + flowThroughCallableLibraryOutRef(_, pred, succ, true) } /** @@ -1135,7 +1329,9 @@ module DataFlow { cached predicate forceCachingInSameStage() { any() } cached newtype TNode = - TExprNode(DotNet::Expr e) + TExprNode(ControlFlow::Nodes::ElementNode cfn) { + cfn.getElement() instanceof Expr + } or TSsaDefinitionNode(Ssa::Definition def) or @@ -1143,6 +1339,8 @@ module DataFlow { p.getMethod().hasBody() } or + TCilExprNode(CIL::Expr e) + or TImplicitDelegateCallNode(DelegateArgumentToLibraryCallable arg) or TImplicitCapturedArgumentNode(Call c, LocalScopeVariable v) { @@ -1554,8 +1752,8 @@ module DataFlow { * Holds if data may flow from argument `mid` of a call, back out from the * call to `out`. The context after the call is `ctx`. */ - pragma [noinline] - private predicate flowThroughCallable(FlowGraphNode mid, OutNode out, Context ctx) { + pragma[nomagic] + private predicate flowThroughCallable0(FlowGraphNode mid, OutNode out, Context ctx) { exists(CallNode call, ParameterNode p, ArgumentContext innerctx, CallContext cc | flowIntoCallable(mid, p, innerctx) and paramFlowsThrough(call, p, out, innerctx, cc) | @@ -1579,6 +1777,44 @@ module DataFlow { ) } + private predicate flowThroughCallable1Scope(OutNode out, Expr e) { + flowThroughCallable0(_, out, _) and + e = out.asExpr().(Expr).getAChildExpr*() + } + + pragma[nomagic] + private predicate flowThroughCallable1(FlowGraphNode mid, OutNode out, ControlFlow::Nodes::ElementNode cfn, Context ctx) { + flowThroughCallable0(mid, out, ctx) and + exists(mid.getNode().asExprAtNode(cfn)) + or + exists(ControlFlow::Nodes::ElementNode cfnMid | + flowThroughCallable1(mid, out, cfnMid, ctx) | + cfn = cfnMid.getASuccessor() and + flowThroughCallable1Scope(out, cfn.getElement()) + ) + } + + /** + * Holds if data may flow from argument `mid` of a call, back out from the + * call to `out`. The context after the call is `ctx`. + */ + pragma[nomagic] + private predicate flowThroughCallable(FlowGraphNode mid, OutNode out, Context ctx) { + // If both `mid` and `out` have associated control flow nodes, the latter + // must be reachable from the former + exists(ControlFlow::Node cfn | + flowThroughCallable1(mid, out, cfn, ctx) | + exists(out.asExprAtNode(cfn)) + ) + or + flowThroughCallable0(mid, out, ctx) and + ( + mid.getNode().(ArgumentNode).hasNoControlFlowNode() + or + not out.asExpr() instanceof Expr + ) + } + /** * Holds if data can flow (inter-procedurally) from `source` to `sink`. * @@ -1592,6 +1828,23 @@ module DataFlow { flowsink.getNode() = sink } + private class FlowThroughCallableLibraryOutRefStep extends ExprStep { + FlowThroughCallableLibraryOutRefStep() { + this = "FlowThroughCallableLibraryOutRefStep" + } + + override predicate stepsToDefinition(Expr exprFrom, AssignableDefinition defTo, ControlFlowElement scope, boolean exactScope, boolean isSuccessor) { + exists(MethodCall mc, Parameter outRef | + libraryFlowOutRef(mc, exprFrom, outRef, _) | + defTo.getTargetAccess() = mc.getArgumentForParameter(outRef) and + defTo instanceof AssignableDefinitions::OutRefDefinition and + scope = mc and + isSuccessor = true and + exactScope = false + ) + } + } + /** * Holds if `arg` is an argument of the method call `mc`, where the target * of `mc` is a library callable that forwards `arg` to an `out`/`ref` argument @@ -1605,12 +1858,9 @@ module DataFlow { * `mc = Int32.TryParse("42", out i)`, `arg = "42"`, and `node` is the access * to `i` in `out i`. */ - predicate flowThroughCallableLibraryOutRef(MethodCall mc, Expr arg, SsaDefinitionNode node, boolean preservesValue) { - exists(Parameter outRef, AssignableDefinitions::OutRefDefinition def | - libraryFlowOutRef(mc, arg, outRef, preservesValue) | - def = node.getDefinition().(Ssa::ExplicitDefinition).getADefinition() and - def.getTargetAccess() = mc.getArgumentForParameter(outRef) - ) + predicate flowThroughCallableLibraryOutRef(MethodCall mc, ExprNode arg, SsaDefinitionNode node, boolean preservesValue) { + libraryFlowOutRef(mc, arg.getExpr(), _, preservesValue) and + any(FlowThroughCallableLibraryOutRefStep x).hasStep(arg, node) } /** diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/TaintTracking.qll b/csharp/ql/src/semmle/code/csharp/dataflow/TaintTracking.qll index 53bf0189b0c..7229b49ab1d 100755 --- a/csharp/ql/src/semmle/code/csharp/dataflow/TaintTracking.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/TaintTracking.qll @@ -31,87 +31,6 @@ module TaintTracking { localAdditionalTaintStep(nodeFrom, nodeTo) } - private CIL::DataFlowNode asCilDataFlowNode(DataFlow::Node node) { - result = node.asParameter() or - result = node.asExpr() - } - - private predicate localTaintStepCil(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { - asCilDataFlowNode(nodeFrom).getALocalFlowSucc(asCilDataFlowNode(nodeTo), any(CIL::Tainted t)) - } - - private cached predicate localAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { - localAdditionalTaintStepExpr(nodeFrom.asExpr(), nodeTo.asExpr()) - or - DataFlow::Internal::flowOutOfDelegateLibraryCall(nodeFrom, nodeTo, false) - or - // Taint from `foreach` expression - exists(ForeachStmt fs, AssignableDefinitions::LocalVariableDefinition def, Ssa::ExplicitDefinition ssaDef | - nodeFrom.asExpr() = fs.getIterableExpr() and - def.getTarget() = fs.getVariable() and - ssaDef.getADefinition() = def and - nodeTo.(DataFlow::Internal::SsaDefinitionNode).getDefinition() = ssaDef - ) - or - localTaintStepCil(nodeFrom, nodeTo) - } - - private predicate localAdditionalTaintStepExpr(Expr exprFrom, Expr exprTo) { - // Taint propagation using library code - libraryFlow(exprFrom, exprTo, false) - or - // Taint from assigned value to element qualifier (`x[i] = 0`) - exists(AssignExpr ae | - exprFrom = ae.getRValue() and - exprTo.(AssignableRead) = getElementAccessQualifier+(ae.getLValue()) - ) - or - // Taint from array initializer - exprFrom = exprTo.(ArrayCreation).getInitializer().getAnElement() - or - // Taint from object initializer - exists(ElementInitializer ei | - ei = exprTo.(ObjectCreation).getInitializer().(CollectionInitializer).getAnElementInitializer() and - exprFrom = ei.getArgument(ei.getNumberOfArguments() - 1) // assume the last argument is the value (i.e., not a key) - ) - or - // Taint from element qualifier - exprFrom = exprTo.(ElementAccess).getQualifier() - or - exprFrom = exprTo.(AddExpr).getAnOperand() - or - // A comparison expression where taint can flow from one of the - // operands if the other operand is a constant value. - exists(ComparisonTest ct, Expr other | - ct.getExpr() = exprTo and - exprFrom = ct.getAnArgument() and - other = ct.getAnArgument() and - other.stripCasts().hasValue() and - exprFrom != other - ) - or - exprFrom = exprTo.(LogicalOperation).getAnOperand() - or - // Taint from tuple argument - exprTo = any(TupleExpr te | - exprFrom = te.getAnArgument() and - te.isReadAccess() - ) - or - exprFrom = exprTo.(InterpolatedStringExpr).getAChild() - or - // Taint from tuple expression - exprTo = any(MemberAccess ma | - ma.getQualifier().getType() instanceof TupleType and - exprFrom = ma.getQualifier() - ) - } - - /** Gets the qualifier of element access `ea`. */ - private Expr getElementAccessQualifier(ElementAccess ea) { - result = ea.getQualifier() - } - /** * A taint tracking configuration. * @@ -163,7 +82,7 @@ module TaintTracking { override predicate isAdditionalFlowStep(DataFlow::Node pred, DataFlow::Node succ) { isAdditionalTaintStep(pred, succ) or localAdditionalTaintStep(pred, succ) or - DataFlow::Internal::flowThroughCallableLibraryOutRef(_, pred.asExpr(), succ, false) + DataFlow::Internal::flowThroughCallableLibraryOutRef(_, pred, succ, false) } final @@ -191,7 +110,136 @@ module TaintTracking { } } - private predicate canYieldReturn(Callable c, Expr e) { - c.getSourceDeclaration().canYieldReturn(e) + /** INTERNAL: Do not use. */ + module Internal { + predicate canYieldReturn(Callable c, Expr e) { + c.getSourceDeclaration().canYieldReturn(e) + } + + private CIL::DataFlowNode asCilDataFlowNode(DataFlow::Node node) { + result = node.asParameter() or + result = node.asExpr() + } + + private predicate localTaintStepCil(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { + asCilDataFlowNode(nodeFrom).getALocalFlowSucc(asCilDataFlowNode(nodeTo), any(CIL::Tainted t)) + } + + /** Gets the qualifier of element access `ea`. */ + private Expr getElementAccessQualifier(ElementAccess ea) { + result = ea.getQualifier() + } + + private class LocalTaintExprStep extends DataFlow::Internal::ExprStep { + LocalTaintExprStep() { this = "LocalTaintExprStep" } + + override predicate stepsToExpr(Expr exprFrom, Expr exprTo, ControlFlowElement scope, boolean exactScope, boolean isSuccessor) { + exactScope = false and + ( + // Taint propagation using library code + DataFlow::Internal::LocalFlow::libraryFlow(exprFrom, exprTo, scope, false) and + (isSuccessor = false or isSuccessor = true) + or + // Taint from assigned value to element qualifier (`x[i] = 0`) + exists(AssignExpr ae | + exprFrom = ae.getRValue() and + exprTo.(AssignableRead) = getElementAccessQualifier+(ae.getLValue()) and + scope = ae and + isSuccessor = false + ) + or + // Taint from array initializer + exprFrom = exprTo.(ArrayCreation).getInitializer().getAnElement() and + scope = exprTo and + isSuccessor = false + or + // Taint from object initializer + exists(ElementInitializer ei | + ei = exprTo.(ObjectCreation).getInitializer().(CollectionInitializer).getAnElementInitializer() and + exprFrom = ei.getArgument(ei.getNumberOfArguments() - 1) and // assume the last argument is the value (i.e., not a key) + scope = exprTo and + isSuccessor = false + ) + or + // Taint from element qualifier + exprFrom = exprTo.(ElementAccess).getQualifier() and + scope = exprTo and + isSuccessor = true + or + exprFrom = exprTo.(AddExpr).getAnOperand() and + scope = exprTo and + isSuccessor = true + or + // A comparison expression where taint can flow from one of the + // operands if the other operand is a constant value. + exists(ComparisonTest ct, Expr other | + ct.getExpr() = exprTo and + exprFrom = ct.getAnArgument() and + other = ct.getAnArgument() and + other.stripCasts().hasValue() and + exprFrom != other and + scope = exprTo and + isSuccessor = true + ) + or + exprFrom = exprTo.(LogicalOperation).getAnOperand() and + scope = exprTo and + isSuccessor = false + or + // Taint from tuple argument + exprTo = any(TupleExpr te | + exprFrom = te.getAnArgument() and + te.isReadAccess() and + scope = exprTo and + isSuccessor = true + ) + or + exprFrom = exprTo.(InterpolatedStringExpr).getAChild() and + scope = exprTo and + isSuccessor = true + or + // Taint from tuple expression + exprTo = any(MemberAccess ma | + ma.getQualifier().getType() instanceof TupleType and + exprFrom = ma.getQualifier() and + scope = exprTo and + isSuccessor = true + ) + ) + } + + override predicate stepsToDefinition(Expr exprFrom, AssignableDefinition defTo, ControlFlowElement scope, boolean exactScope, boolean isSuccessor) { + // Taint from `foreach` expression + exists(ForeachStmt fs | + exprFrom = fs.getIterableExpr() and + defTo.(AssignableDefinitions::LocalVariableDefinition).getDeclaration() = fs.getVariableDeclExpr() and + isSuccessor = true + | + scope = fs and + exactScope = true + or + scope = fs.getIterableExpr() and + exactScope = false + or + scope = fs.getVariableDeclExpr() and + exactScope = false + ) + } + } + + cached module Cached { + cached predicate forceCachingInSameStage() { any() } + + cached predicate localAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { + DataFlow::Internal::Cached::forceCachingInSameStage() and + any(LocalTaintExprStep x).hasStep(nodeFrom, nodeTo) + or + DataFlow::Internal::flowOutOfDelegateLibraryCall(nodeFrom, nodeTo, false) + or + localTaintStepCil(nodeFrom, nodeTo) + } + } + import Cached } + private import Internal } diff --git a/csharp/ql/src/semmle/code/csharp/exprs/Call.qll b/csharp/ql/src/semmle/code/csharp/exprs/Call.qll index a51451b9eb4..5391ec21e52 100644 --- a/csharp/ql/src/semmle/code/csharp/exprs/Call.qll +++ b/csharp/ql/src/semmle/code/csharp/exprs/Call.qll @@ -506,7 +506,7 @@ class DelegateCall extends Call, @delegate_invocation_expr { ) or exists(AddEventSource aes, CallContext::CallContext cc2 | - aes = this.getAnAddEventSource() and + aes = this.getAnAddEventSource(_) and result = aes.getARuntimeTarget(cc2) | aes = this.getAnAddEventSourceSameEnclosingCallable() and @@ -518,18 +518,17 @@ class DelegateCall extends Call, @delegate_invocation_expr { ) } - private AddEventSource getAnAddEventSource() { - this.getDelegateExpr().(EventAccess).getTarget() = result.getEvent() + private AddEventSource getAnAddEventSource(Callable enclosingCallable) { + this.getDelegateExpr().(EventAccess).getTarget() = result.getEvent() and + enclosingCallable = result.getExpr().getEnclosingCallable() } private AddEventSource getAnAddEventSourceSameEnclosingCallable() { - result = getAnAddEventSource() and - result.getExpr().getEnclosingCallable() = this.getEnclosingCallable() + result = getAnAddEventSource(this.getEnclosingCallable()) } private AddEventSource getAnAddEventSourceDifferentEnclosingCallable() { - result = getAnAddEventSource() and - result.getExpr().getEnclosingCallable() != this.getEnclosingCallable() + exists(Callable c | result = getAnAddEventSource(c) | c != this.getEnclosingCallable()) } override Callable getARuntimeTarget() { result = getARuntimeTarget(_) } diff --git a/csharp/ql/src/semmle/code/csharp/exprs/Expr.qll b/csharp/ql/src/semmle/code/csharp/exprs/Expr.qll index 22e600513ed..25a4bf5761f 100644 --- a/csharp/ql/src/semmle/code/csharp/exprs/Expr.qll +++ b/csharp/ql/src/semmle/code/csharp/exprs/Expr.qll @@ -670,7 +670,10 @@ class TupleExpr extends Expr, @tuple_expr { Expr getAnArgument() { result = getArgument(_) } /** Holds if this tuple is a read access. */ - predicate isReadAccess() { not exists(AssignExpr e | this = e.getLValue().getAChildExpr*()) } + predicate isReadAccess() { + not exists(AssignExpr e | this = e.getLValue().getAChildExpr*()) and + not exists(ForeachStmt fs | this = fs.getVariableDeclTuple().getAChildExpr*()) + } } /** diff --git a/csharp/ql/src/semmle/code/csharp/security/dataflow/TaintedPath.qll b/csharp/ql/src/semmle/code/csharp/security/dataflow/TaintedPath.qll index bb1832c39ac..b99e5215592 100644 --- a/csharp/ql/src/semmle/code/csharp/security/dataflow/TaintedPath.qll +++ b/csharp/ql/src/semmle/code/csharp/security/dataflow/TaintedPath.qll @@ -123,9 +123,9 @@ module TaintedPath { */ class PathCheck extends Sanitizer { PathCheck() { - // This expression is structurally replicated in a dominating guard which is not a "weak" check. - exists(Expr e | - this.getExpr().(GuardedExpr).isGuardedBy(_, e, _) and + // This expression is structurally replicated in a dominating guard which is not a "weak" check + exists(Expr e, AbstractValues::BooleanValue v | + exists(this.(GuardedDataFlowNode).getAGuard(e, v)) and not inWeakCheck(e) ) } diff --git a/csharp/ql/src/semmle/code/csharp/security/dataflow/UrlRedirect.qll b/csharp/ql/src/semmle/code/csharp/security/dataflow/UrlRedirect.qll index a809ff7bc6c..dc34267ffaf 100644 --- a/csharp/ql/src/semmle/code/csharp/security/dataflow/UrlRedirect.qll +++ b/csharp/ql/src/semmle/code/csharp/security/dataflow/UrlRedirect.qll @@ -98,8 +98,9 @@ module UrlRedirect { */ class IsLocalUrlSanitizer extends Sanitizer { IsLocalUrlSanitizer() { - exists(MethodCall mc | mc.getTarget().hasName("IsLocalUrl") | - this.getExpr().(GuardedExpr).isGuardedBy(mc, mc.getArgument(0), true) + exists(MethodCall mc, AbstractValues::BooleanValue v | mc.getTarget().hasName("IsLocalUrl") | + mc = this.(GuardedDataFlowNode).getAGuard(mc.getArgument(0), v) and + v.getValue() = true ) } } diff --git a/csharp/ql/src/semmle/code/csharp/security/dataflow/ZipSlip.qll b/csharp/ql/src/semmle/code/csharp/security/dataflow/ZipSlip.qll index e5787a313f9..d5b9f24d0b1 100644 --- a/csharp/ql/src/semmle/code/csharp/security/dataflow/ZipSlip.qll +++ b/csharp/ql/src/semmle/code/csharp/security/dataflow/ZipSlip.qll @@ -127,10 +127,10 @@ module ZipSlip { */ class StringCheckSanitizer extends Sanitizer { StringCheckSanitizer() { - exists(GuardedExpr ge, MethodCall mc, Expr startsWithQualifier | - ge = this.asExpr() and - ge.isGuardedBy(mc, startsWithQualifier, true) + exists(MethodCall mc, Expr startsWithQualifier, AbstractValues::BooleanValue v | + mc = this.(GuardedDataFlowNode).getAGuard(startsWithQualifier, v) | + v.getValue() = true and mc.getTarget().hasQualifiedName("System.String", "StartsWith") and mc.getQualifier() = startsWithQualifier and // A StartsWith check against Path.Combine is not sufficient, because the ".." elements have diff --git a/csharp/ql/test/library-tests/csharp7/LocalTaintFlow.expected b/csharp/ql/test/library-tests/csharp7/LocalTaintFlow.expected index 32766ee67a3..753fcec4869 100644 --- a/csharp/ql/test/library-tests/csharp7/LocalTaintFlow.expected +++ b/csharp/ql/test/library-tests/csharp7/LocalTaintFlow.expected @@ -185,14 +185,8 @@ | CSharp7.cs:284:41:284:48 | access to property Key | CSharp7.cs:284:40:284:61 | (..., ...) | | CSharp7.cs:284:51:284:54 | access to parameter item | CSharp7.cs:284:51:284:60 | access to property Value | | CSharp7.cs:284:51:284:60 | access to property Value | CSharp7.cs:284:40:284:61 | (..., ...) | -| CSharp7.cs:286:23:286:23 | Int32 a | CSharp7.cs:286:18:286:34 | (..., ...) | -| CSharp7.cs:286:33:286:33 | String b | CSharp7.cs:286:18:286:34 | (..., ...) | | CSharp7.cs:286:39:286:42 | access to local variable list | CSharp7.cs:288:36:288:39 | access to local variable list | -| CSharp7.cs:288:23:288:23 | Int32 a | CSharp7.cs:288:18:288:31 | (..., ...) | -| CSharp7.cs:288:30:288:30 | String b | CSharp7.cs:288:18:288:31 | (..., ...) | | CSharp7.cs:288:36:288:39 | access to local variable list | CSharp7.cs:290:32:290:35 | access to local variable list | -| CSharp7.cs:290:23:290:23 | Int32 a | CSharp7.cs:290:18:290:27 | (..., ...) | -| CSharp7.cs:290:26:290:26 | String b | CSharp7.cs:290:18:290:27 | (..., ...) | | CSharp7.cs:298:17:298:19 | SSA def(x) | CSharp7.cs:298:22:298:39 | SSA phi(x) | | CSharp7.cs:298:19:298:19 | 0 | CSharp7.cs:298:17:298:19 | SSA def(x) | | CSharp7.cs:298:22:298:22 | access to local variable x | CSharp7.cs:298:22:298:25 | ... < ... | diff --git a/csharp/ql/test/library-tests/csharp7/TupleAccess.expected b/csharp/ql/test/library-tests/csharp7/TupleAccess.expected index c825aadfb74..437ee46820d 100644 --- a/csharp/ql/test/library-tests/csharp7/TupleAccess.expected +++ b/csharp/ql/test/library-tests/csharp7/TupleAccess.expected @@ -40,6 +40,6 @@ | CSharp7.cs:224:9:224:18 | (..., ...) | write | | CSharp7.cs:225:9:225:18 | (..., ...) | write | | CSharp7.cs:284:40:284:61 | (..., ...) | read | -| CSharp7.cs:286:18:286:34 | (..., ...) | read | -| CSharp7.cs:288:18:288:31 | (..., ...) | read | -| CSharp7.cs:290:18:290:27 | (..., ...) | read | +| CSharp7.cs:286:18:286:34 | (..., ...) | write | +| CSharp7.cs:288:18:288:31 | (..., ...) | write | +| CSharp7.cs:290:18:290:27 | (..., ...) | write | diff --git a/csharp/ql/test/library-tests/dataflow/callablereturnsarg/Common.qll b/csharp/ql/test/library-tests/dataflow/callablereturnsarg/Common.qll index 92d128462dc..2690f558847 100644 --- a/csharp/ql/test/library-tests/dataflow/callablereturnsarg/Common.qll +++ b/csharp/ql/test/library-tests/dataflow/callablereturnsarg/Common.qll @@ -9,8 +9,9 @@ class Configuration extends DataFlow::Configuration { override predicate isSink(DataFlow::Node sink) { any() } override predicate isBarrier(DataFlow::Node node) { - exists(EQExpr eq, Expr e | - node.asExpr().(GuardedExpr).isGuardedBy(eq, e, true) and + exists(EQExpr eq, Expr e, AbstractValues::BooleanValue v | + eq = node.(GuardedDataFlowNode).getAGuard(e, v) | + v.getValue() = true and eq.getAnOperand() = e and eq.getAnOperand() instanceof NullLiteral ) diff --git a/csharp/ql/test/library-tests/dataflow/global/DataFlow.expected b/csharp/ql/test/library-tests/dataflow/global/DataFlow.expected index 13d0656a168..2f41d7030f5 100644 --- a/csharp/ql/test/library-tests/dataflow/global/DataFlow.expected +++ b/csharp/ql/test/library-tests/dataflow/global/DataFlow.expected @@ -35,5 +35,6 @@ | GlobalDataFlow.cs:263:15:263:24 | access to parameter sinkParam7 | | GlobalDataFlow.cs:376:15:376:20 | access to local variable sink11 | | GlobalDataFlow.cs:399:41:399:46 | access to local variable sink20 | -| Splitting.cs:9:15:9:15 | access to local variable x | +| Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x | +| Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x | | Splitting.cs:11:19:11:19 | access to local variable x | diff --git a/csharp/ql/test/library-tests/dataflow/global/DataFlowPath.expected b/csharp/ql/test/library-tests/dataflow/global/DataFlowPath.expected index 0b0c2deb051..e4a65d2dd2c 100644 --- a/csharp/ql/test/library-tests/dataflow/global/DataFlowPath.expected +++ b/csharp/ql/test/library-tests/dataflow/global/DataFlowPath.expected @@ -172,10 +172,18 @@ edges | GlobalDataFlow.cs:377:16:377:21 | access to local variable sink11 | GlobalDataFlow.cs:159:22:159:43 | call to method TaintedParam | | GlobalDataFlow.cs:399:9:399:11 | value | GlobalDataFlow.cs:399:41:399:46 | access to local variable sink20 | | GlobalDataFlow.cs:410:22:410:35 | "taint source" | GlobalDataFlow.cs:193:22:193:32 | access to property OutProperty | -| Splitting.cs:3:28:3:34 | tainted | Splitting.cs:8:24:8:30 | access to parameter tainted | -| Splitting.cs:8:17:8:31 | call to method Return | Splitting.cs:9:15:9:15 | access to local variable x | -| Splitting.cs:8:17:8:31 | call to method Return | Splitting.cs:11:19:11:19 | access to local variable x | -| Splitting.cs:8:24:8:30 | access to parameter tainted | Splitting.cs:8:17:8:31 | call to method Return | +| Splitting.cs:3:28:3:34 | tainted | Splitting.cs:8:24:8:30 | [b (line 3): false] access to parameter tainted | +| Splitting.cs:3:28:3:34 | tainted | Splitting.cs:8:24:8:30 | [b (line 3): true] access to parameter tainted | +| Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return | Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x | +| Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return | Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x | +| Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return | Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x | +| Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return | Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x | +| Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return | Splitting.cs:11:19:11:19 | access to local variable x | +| Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return | Splitting.cs:11:19:11:19 | access to local variable x | +| Splitting.cs:8:24:8:30 | [b (line 3): false] access to parameter tainted | Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return | +| Splitting.cs:8:24:8:30 | [b (line 3): false] access to parameter tainted | Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return | +| Splitting.cs:8:24:8:30 | [b (line 3): true] access to parameter tainted | Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return | +| Splitting.cs:8:24:8:30 | [b (line 3): true] access to parameter tainted | Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return | nodes | Capture.cs:7:20:7:26 | tainted | | Capture.cs:9:9:13:9 | SSA capture def(tainted) | @@ -307,11 +315,23 @@ nodes | GlobalDataFlow.cs:399:41:399:46 | access to local variable sink20 | | GlobalDataFlow.cs:410:22:410:35 | "taint source" | | Splitting.cs:3:28:3:34 | tainted | -| Splitting.cs:8:17:8:31 | call to method Return | -| Splitting.cs:8:24:8:30 | access to parameter tainted | -| Splitting.cs:9:15:9:15 | access to local variable x | +| Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return | +| Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return | +| Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return | +| Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return | +| Splitting.cs:8:24:8:30 | [b (line 3): false] access to parameter tainted | +| Splitting.cs:8:24:8:30 | [b (line 3): true] access to parameter tainted | +| Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x | +| Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x | +| Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x | +| Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x | +| Splitting.cs:11:19:11:19 | access to local variable x | | Splitting.cs:11:19:11:19 | access to local variable x | #select +| Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x | Splitting.cs:3:28:3:34 | tainted | Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x | [b (line 3): false] access to local variable x | +| Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x | Splitting.cs:3:28:3:34 | tainted | Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x | [b (line 3): false] access to local variable x | +| Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x | Splitting.cs:3:28:3:34 | tainted | Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x | [b (line 3): true] access to local variable x | +| Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x | Splitting.cs:3:28:3:34 | tainted | Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x | [b (line 3): true] access to local variable x | | GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 | access to field SinkField0 | | GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 | access to local variable sink0 | | GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 | access to local variable sink1 | @@ -340,7 +360,7 @@ nodes | GlobalDataFlow.cs:153:15:153:19 | access to local variable sink7 | GlobalDataFlow.cs:318:13:318:26 | "taint source" | GlobalDataFlow.cs:153:15:153:19 | access to local variable sink7 | access to local variable sink7 | | GlobalDataFlow.cs:156:15:156:19 | access to local variable sink8 | GlobalDataFlow.cs:323:13:323:26 | "taint source" | GlobalDataFlow.cs:156:15:156:19 | access to local variable sink8 | access to local variable sink8 | | GlobalDataFlow.cs:177:15:177:19 | access to local variable sink9 | GlobalDataFlow.cs:175:35:175:48 | "taint source" | GlobalDataFlow.cs:177:15:177:19 | access to local variable sink9 | access to local variable sink9 | -| Splitting.cs:9:15:9:15 | access to local variable x | Splitting.cs:3:28:3:34 | tainted | Splitting.cs:9:15:9:15 | access to local variable x | access to local variable x | +| Splitting.cs:11:19:11:19 | access to local variable x | Splitting.cs:3:28:3:34 | tainted | Splitting.cs:11:19:11:19 | access to local variable x | access to local variable x | | Splitting.cs:11:19:11:19 | access to local variable x | Splitting.cs:3:28:3:34 | tainted | Splitting.cs:11:19:11:19 | access to local variable x | access to local variable x | | GlobalDataFlow.cs:233:15:233:24 | access to parameter sinkParam0 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:233:15:233:24 | access to parameter sinkParam0 | access to parameter sinkParam0 | | GlobalDataFlow.cs:233:15:233:24 | access to parameter sinkParam0 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:233:15:233:24 | access to parameter sinkParam0 | access to parameter sinkParam0 | diff --git a/csharp/ql/test/library-tests/dataflow/global/TaintTracking.expected b/csharp/ql/test/library-tests/dataflow/global/TaintTracking.expected index 404e468b421..1a9a69643c0 100644 --- a/csharp/ql/test/library-tests/dataflow/global/TaintTracking.expected +++ b/csharp/ql/test/library-tests/dataflow/global/TaintTracking.expected @@ -51,5 +51,6 @@ | GlobalDataFlow.cs:301:15:301:25 | access to parameter sinkParam11 | | GlobalDataFlow.cs:376:15:376:20 | access to local variable sink11 | | GlobalDataFlow.cs:399:41:399:46 | access to local variable sink20 | -| Splitting.cs:9:15:9:15 | access to local variable x | +| Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x | +| Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x | | Splitting.cs:11:19:11:19 | access to local variable x | diff --git a/csharp/ql/test/library-tests/dataflow/global/TaintTrackingPath.expected b/csharp/ql/test/library-tests/dataflow/global/TaintTrackingPath.expected index e6dafba170b..d46b2550bff 100644 --- a/csharp/ql/test/library-tests/dataflow/global/TaintTrackingPath.expected +++ b/csharp/ql/test/library-tests/dataflow/global/TaintTrackingPath.expected @@ -215,10 +215,18 @@ edges | GlobalDataFlow.cs:377:16:377:21 | access to local variable sink11 | GlobalDataFlow.cs:159:22:159:43 | call to method TaintedParam | | GlobalDataFlow.cs:399:9:399:11 | value | GlobalDataFlow.cs:399:41:399:46 | access to local variable sink20 | | GlobalDataFlow.cs:410:22:410:35 | "taint source" | GlobalDataFlow.cs:193:22:193:32 | access to property OutProperty | -| Splitting.cs:3:28:3:34 | tainted | Splitting.cs:8:24:8:30 | access to parameter tainted | -| Splitting.cs:8:17:8:31 | call to method Return | Splitting.cs:9:15:9:15 | access to local variable x | -| Splitting.cs:8:17:8:31 | call to method Return | Splitting.cs:11:19:11:19 | access to local variable x | -| Splitting.cs:8:24:8:30 | access to parameter tainted | Splitting.cs:8:17:8:31 | call to method Return | +| Splitting.cs:3:28:3:34 | tainted | Splitting.cs:8:24:8:30 | [b (line 3): false] access to parameter tainted | +| Splitting.cs:3:28:3:34 | tainted | Splitting.cs:8:24:8:30 | [b (line 3): true] access to parameter tainted | +| Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return | Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x | +| Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return | Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x | +| Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return | Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x | +| Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return | Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x | +| Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return | Splitting.cs:11:19:11:19 | access to local variable x | +| Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return | Splitting.cs:11:19:11:19 | access to local variable x | +| Splitting.cs:8:24:8:30 | [b (line 3): false] access to parameter tainted | Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return | +| Splitting.cs:8:24:8:30 | [b (line 3): false] access to parameter tainted | Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return | +| Splitting.cs:8:24:8:30 | [b (line 3): true] access to parameter tainted | Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return | +| Splitting.cs:8:24:8:30 | [b (line 3): true] access to parameter tainted | Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return | nodes | Capture.cs:7:20:7:26 | tainted | | Capture.cs:9:9:13:9 | SSA capture def(tainted) | @@ -395,9 +403,17 @@ nodes | GlobalDataFlow.cs:399:41:399:46 | access to local variable sink20 | | GlobalDataFlow.cs:410:22:410:35 | "taint source" | | Splitting.cs:3:28:3:34 | tainted | -| Splitting.cs:8:17:8:31 | call to method Return | -| Splitting.cs:8:24:8:30 | access to parameter tainted | -| Splitting.cs:9:15:9:15 | access to local variable x | +| Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return | +| Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return | +| Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return | +| Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return | +| Splitting.cs:8:24:8:30 | [b (line 3): false] access to parameter tainted | +| Splitting.cs:8:24:8:30 | [b (line 3): true] access to parameter tainted | +| Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x | +| Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x | +| Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x | +| Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x | +| Splitting.cs:11:19:11:19 | access to local variable x | | Splitting.cs:11:19:11:19 | access to local variable x | #select | Capture.cs:12:19:12:24 | access to local variable sink27 | Capture.cs:7:20:7:26 | tainted | Capture.cs:12:19:12:24 | access to local variable sink27 | access to local variable sink27 | @@ -454,5 +470,9 @@ nodes | GlobalDataFlow.cs:301:15:301:25 | access to parameter sinkParam11 | GlobalDataFlow.cs:201:39:201:45 | tainted | GlobalDataFlow.cs:301:15:301:25 | access to parameter sinkParam11 | access to parameter sinkParam11 | | GlobalDataFlow.cs:376:15:376:20 | access to local variable sink11 | GlobalDataFlow.cs:373:39:373:45 | tainted | GlobalDataFlow.cs:376:15:376:20 | access to local variable sink11 | access to local variable sink11 | | GlobalDataFlow.cs:399:41:399:46 | access to local variable sink20 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:399:41:399:46 | access to local variable sink20 | access to local variable sink20 | -| Splitting.cs:9:15:9:15 | access to local variable x | Splitting.cs:3:28:3:34 | tainted | Splitting.cs:9:15:9:15 | access to local variable x | access to local variable x | +| Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x | Splitting.cs:3:28:3:34 | tainted | Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x | [b (line 3): false] access to local variable x | +| Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x | Splitting.cs:3:28:3:34 | tainted | Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x | [b (line 3): false] access to local variable x | +| Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x | Splitting.cs:3:28:3:34 | tainted | Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x | [b (line 3): true] access to local variable x | +| Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x | Splitting.cs:3:28:3:34 | tainted | Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x | [b (line 3): true] access to local variable x | +| Splitting.cs:11:19:11:19 | access to local variable x | Splitting.cs:3:28:3:34 | tainted | Splitting.cs:11:19:11:19 | access to local variable x | access to local variable x | | Splitting.cs:11:19:11:19 | access to local variable x | Splitting.cs:3:28:3:34 | tainted | Splitting.cs:11:19:11:19 | access to local variable x | access to local variable x | diff --git a/csharp/ql/test/library-tests/dataflow/local/DataFlow.expected b/csharp/ql/test/library-tests/dataflow/local/DataFlow.expected index ab16c42f2cb..63462bbad86 100644 --- a/csharp/ql/test/library-tests/dataflow/local/DataFlow.expected +++ b/csharp/ql/test/library-tests/dataflow/local/DataFlow.expected @@ -17,8 +17,7 @@ | SSA.cs:98:15:98:22 | access to local variable ssaSink4 | | SSA.cs:124:15:124:34 | access to field SsaFieldSink1 | | SSA.cs:180:15:180:22 | access to local variable ssaSink5 | -| Splitting.cs:8:19:8:19 | access to local variable x | -| Splitting.cs:12:15:12:15 | access to local variable x | -| Splitting.cs:25:15:25:15 | access to local variable x | +| Splitting.cs:8:19:8:19 | [b (line 3): true] access to local variable x | +| Splitting.cs:12:15:12:15 | [b (line 3): false] access to local variable x | +| Splitting.cs:25:15:25:15 | [b (line 17): true] access to local variable x | | Splitting.cs:27:19:27:19 | access to local variable x | -| Splitting.cs:29:19:29:19 | access to local variable x | diff --git a/csharp/ql/test/library-tests/dataflow/local/DataFlow.ql b/csharp/ql/test/library-tests/dataflow/local/DataFlow.ql index 918de64c60f..4fec5b6c67a 100644 --- a/csharp/ql/test/library-tests/dataflow/local/DataFlow.ql +++ b/csharp/ql/test/library-tests/dataflow/local/DataFlow.ql @@ -4,7 +4,7 @@ import semmle.code.csharp.controlflow.Guards predicate step(DataFlow::Node pred, DataFlow::Node succ) { DataFlow::localFlowStep(pred, succ) and - not succ.asExpr() instanceof NullGuardedExpr + not succ instanceof NullGuardedDataFlowNode } from MyFlowSource source, DataFlow::Node sink, Access target diff --git a/csharp/ql/test/library-tests/dataflow/local/DataFlowStep.expected b/csharp/ql/test/library-tests/dataflow/local/DataFlowStep.expected index 5f2b280d79a..1abc65684c6 100644 --- a/csharp/ql/test/library-tests/dataflow/local/DataFlowStep.expected +++ b/csharp/ql/test/library-tests/dataflow/local/DataFlowStep.expected @@ -49,22 +49,25 @@ | LocalDataFlow.cs:85:15:85:22 | access to local variable nonSink0 | LocalDataFlow.cs:92:21:92:28 | access to local variable nonSink0 | | LocalDataFlow.cs:88:13:88:27 | SSA def(sink6) | LocalDataFlow.cs:89:15:89:19 | access to local variable sink6 | | LocalDataFlow.cs:88:22:88:26 | access to local variable sink5 | LocalDataFlow.cs:88:13:88:27 | SSA def(sink6) | -| LocalDataFlow.cs:89:15:89:19 | access to local variable sink6 | LocalDataFlow.cs:96:31:96:35 | access to local variable sink6 | +| LocalDataFlow.cs:89:15:89:19 | access to local variable sink6 | LocalDataFlow.cs:96:31:96:35 | [b (line 49): false] access to local variable sink6 | | LocalDataFlow.cs:92:9:92:29 | SSA def(nonSink0) | LocalDataFlow.cs:93:15:93:22 | access to local variable nonSink0 | | LocalDataFlow.cs:92:21:92:28 | access to local variable nonSink0 | LocalDataFlow.cs:92:9:92:29 | SSA def(nonSink0) | -| LocalDataFlow.cs:96:13:96:35 | [b (line 49): false] SSA def(sink7) | LocalDataFlow.cs:97:15:97:19 | access to local variable sink7 | -| LocalDataFlow.cs:96:13:96:35 | [b (line 49): true] SSA def(sink7) | LocalDataFlow.cs:97:15:97:19 | access to local variable sink7 | -| LocalDataFlow.cs:96:21:96:21 | access to parameter b | LocalDataFlow.cs:100:20:100:20 | access to parameter b | +| LocalDataFlow.cs:96:13:96:35 | [b (line 49): false] SSA def(sink7) | LocalDataFlow.cs:97:15:97:19 | [b (line 49): false] access to local variable sink7 | +| LocalDataFlow.cs:96:13:96:35 | [b (line 49): true] SSA def(sink7) | LocalDataFlow.cs:97:15:97:19 | [b (line 49): true] access to local variable sink7 | +| LocalDataFlow.cs:96:21:96:21 | access to parameter b | LocalDataFlow.cs:100:20:100:20 | [b (line 49): false] access to parameter b | +| LocalDataFlow.cs:96:21:96:21 | access to parameter b | LocalDataFlow.cs:100:20:100:20 | [b (line 49): true] access to parameter b | | LocalDataFlow.cs:96:21:96:35 | ... ? ... : ... | LocalDataFlow.cs:96:13:96:35 | [b (line 49): false] SSA def(sink7) | | LocalDataFlow.cs:96:21:96:35 | ... ? ... : ... | LocalDataFlow.cs:96:13:96:35 | [b (line 49): true] SSA def(sink7) | -| LocalDataFlow.cs:96:25:96:27 | "a" | LocalDataFlow.cs:96:21:96:35 | ... ? ... : ... | -| LocalDataFlow.cs:96:31:96:35 | access to local variable sink6 | LocalDataFlow.cs:96:21:96:35 | ... ? ... : ... | -| LocalDataFlow.cs:97:15:97:19 | access to local variable sink7 | LocalDataFlow.cs:100:9:100:36 | SSA phi(sink7) | +| LocalDataFlow.cs:96:25:96:27 | [b (line 49): true] "a" | LocalDataFlow.cs:96:21:96:35 | ... ? ... : ... | +| LocalDataFlow.cs:96:31:96:35 | [b (line 49): false] access to local variable sink6 | LocalDataFlow.cs:96:21:96:35 | ... ? ... : ... | +| LocalDataFlow.cs:97:15:97:19 | [b (line 49): false] access to local variable sink7 | LocalDataFlow.cs:100:9:100:36 | SSA phi(sink7) | +| LocalDataFlow.cs:97:15:97:19 | [b (line 49): true] access to local variable sink7 | LocalDataFlow.cs:100:9:100:36 | SSA phi(sink7) | | LocalDataFlow.cs:100:9:100:36 | SSA def(nonSink0) | LocalDataFlow.cs:101:15:101:22 | access to local variable nonSink0 | | LocalDataFlow.cs:100:9:100:36 | SSA phi(sink7) | LocalDataFlow.cs:104:29:104:33 | access to local variable sink7 | -| LocalDataFlow.cs:100:20:100:36 | ... ? ... : ... | LocalDataFlow.cs:100:9:100:36 | SSA def(nonSink0) | -| LocalDataFlow.cs:100:24:100:28 | "abc" | LocalDataFlow.cs:100:20:100:36 | ... ? ... : ... | -| LocalDataFlow.cs:100:32:100:36 | "def" | LocalDataFlow.cs:100:20:100:36 | ... ? ... : ... | +| LocalDataFlow.cs:100:20:100:36 | [b (line 49): false] ... ? ... : ... | LocalDataFlow.cs:100:9:100:36 | SSA def(nonSink0) | +| LocalDataFlow.cs:100:20:100:36 | [b (line 49): true] ... ? ... : ... | LocalDataFlow.cs:100:9:100:36 | SSA def(nonSink0) | +| LocalDataFlow.cs:100:24:100:28 | "abc" | LocalDataFlow.cs:100:20:100:36 | [b (line 49): true] ... ? ... : ... | +| LocalDataFlow.cs:100:32:100:36 | "def" | LocalDataFlow.cs:100:20:100:36 | [b (line 49): false] ... ? ... : ... | | LocalDataFlow.cs:101:15:101:22 | access to local variable nonSink0 | LocalDataFlow.cs:108:32:108:39 | access to local variable nonSink0 | | LocalDataFlow.cs:104:13:104:33 | SSA def(sink8) | LocalDataFlow.cs:105:15:105:19 | access to local variable sink8 | | LocalDataFlow.cs:104:21:104:33 | (...) ... | LocalDataFlow.cs:104:13:104:33 | SSA def(sink8) | @@ -645,58 +648,72 @@ | SSA.cs:180:9:180:24 | SSA phi(ssaSink5) | SSA.cs:180:15:180:22 | access to local variable ssaSink5 | | Splitting.cs:3:18:3:18 | b | Splitting.cs:6:13:6:13 | access to parameter b | | Splitting.cs:3:28:3:34 | tainted | Splitting.cs:5:17:5:23 | access to parameter tainted | -| Splitting.cs:5:13:5:23 | SSA def(x) | Splitting.cs:8:19:8:19 | access to local variable x | -| Splitting.cs:5:13:5:23 | SSA def(x) | Splitting.cs:12:15:12:15 | access to local variable x | +| Splitting.cs:5:13:5:23 | SSA def(x) | Splitting.cs:8:19:8:19 | [b (line 3): true] access to local variable x | +| Splitting.cs:5:13:5:23 | SSA def(x) | Splitting.cs:12:15:12:15 | [b (line 3): false] access to local variable x | | Splitting.cs:5:17:5:23 | access to parameter tainted | Splitting.cs:5:13:5:23 | SSA def(x) | -| Splitting.cs:6:13:6:13 | access to parameter b | Splitting.cs:13:13:13:13 | access to parameter b | -| Splitting.cs:8:19:8:19 | access to local variable x | Splitting.cs:9:17:9:17 | access to local variable x | -| Splitting.cs:12:15:12:15 | access to local variable x | Splitting.cs:14:19:14:19 | access to local variable x | +| Splitting.cs:6:13:6:13 | access to parameter b | Splitting.cs:13:13:13:13 | [b (line 3): false] access to parameter b | +| Splitting.cs:6:13:6:13 | access to parameter b | Splitting.cs:13:13:13:13 | [b (line 3): true] access to parameter b | +| Splitting.cs:8:19:8:19 | [b (line 3): true] access to local variable x | Splitting.cs:9:17:9:17 | [b (line 3): true] access to local variable x | +| Splitting.cs:9:17:9:17 | [b (line 3): true] access to local variable x | Splitting.cs:12:15:12:15 | [b (line 3): true] access to local variable x | +| Splitting.cs:12:15:12:15 | [b (line 3): true] access to local variable x | Splitting.cs:14:19:14:19 | access to local variable x | | Splitting.cs:17:18:17:18 | b | Splitting.cs:20:13:20:13 | access to parameter b | -| Splitting.cs:19:13:19:18 | SSA def(x) | Splitting.cs:22:19:22:19 | access to local variable x | -| Splitting.cs:19:13:19:18 | SSA def(x) | Splitting.cs:25:15:25:15 | access to local variable x | +| Splitting.cs:19:13:19:18 | SSA def(x) | Splitting.cs:22:19:22:19 | [b (line 17): true] access to local variable x | +| Splitting.cs:19:13:19:18 | SSA def(x) | Splitting.cs:25:15:25:15 | [b (line 17): false] access to local variable x | | Splitting.cs:19:17:19:18 | "" | Splitting.cs:19:13:19:18 | SSA def(x) | -| Splitting.cs:20:13:20:13 | access to parameter b | Splitting.cs:26:13:26:13 | access to parameter b | -| Splitting.cs:23:13:23:30 | [b (line 17): true] SSA def(x) | Splitting.cs:25:15:25:15 | access to local variable x | -| Splitting.cs:23:17:23:30 | "taint source" | Splitting.cs:23:13:23:30 | [b (line 17): true] SSA def(x) | -| Splitting.cs:25:15:25:15 | access to local variable x | Splitting.cs:27:19:27:19 | access to local variable x | -| Splitting.cs:25:15:25:15 | access to local variable x | Splitting.cs:29:19:29:19 | access to local variable x | +| Splitting.cs:20:13:20:13 | access to parameter b | Splitting.cs:26:13:26:13 | [b (line 17): false] access to parameter b | +| Splitting.cs:20:13:20:13 | access to parameter b | Splitting.cs:26:13:26:13 | [b (line 17): true] access to parameter b | +| Splitting.cs:23:13:23:30 | [b (line 17): true] SSA def(x) | Splitting.cs:25:15:25:15 | [b (line 17): true] access to local variable x | +| Splitting.cs:23:17:23:30 | [b (line 17): true] "taint source" | Splitting.cs:23:13:23:30 | [b (line 17): true] SSA def(x) | +| Splitting.cs:25:15:25:15 | [b (line 17): false] access to local variable x | Splitting.cs:29:19:29:19 | access to local variable x | +| Splitting.cs:25:15:25:15 | [b (line 17): true] access to local variable x | Splitting.cs:27:19:27:19 | access to local variable x | | Splitting.cs:32:18:32:18 | b | Splitting.cs:35:13:35:13 | access to parameter b | -| Splitting.cs:35:13:35:13 | access to parameter b | Splitting.cs:39:15:39:15 | access to parameter b | -| Splitting.cs:37:9:37:15 | [b (line 32): false] SSA def(x) | Splitting.cs:38:15:38:15 | access to local variable x | -| Splitting.cs:37:9:37:15 | [b (line 32): true] SSA def(x) | Splitting.cs:38:15:38:15 | access to local variable x | -| Splitting.cs:37:13:37:15 | "b" | Splitting.cs:37:9:37:15 | [b (line 32): false] SSA def(x) | -| Splitting.cs:37:13:37:15 | "b" | Splitting.cs:37:9:37:15 | [b (line 32): true] SSA def(x) | -| Splitting.cs:38:15:38:15 | access to local variable x | Splitting.cs:39:19:39:19 | access to local variable x | -| Splitting.cs:39:15:39:15 | access to parameter b | Splitting.cs:42:13:42:13 | access to parameter b | -| Splitting.cs:39:19:39:19 | access to local variable x | Splitting.cs:39:15:39:25 | ... ? ... : ... | -| Splitting.cs:39:23:39:25 | "c" | Splitting.cs:39:15:39:25 | ... ? ... : ... | -| Splitting.cs:40:23:40:23 | access to local variable x | Splitting.cs:40:15:40:23 | (...) ... | -| Splitting.cs:41:19:41:21 | "d" | Splitting.cs:41:15:41:21 | ... = ... | +| Splitting.cs:35:13:35:13 | access to parameter b | Splitting.cs:39:15:39:15 | [b (line 32): false] access to parameter b | +| Splitting.cs:35:13:35:13 | access to parameter b | Splitting.cs:39:15:39:15 | [b (line 32): true] access to parameter b | +| Splitting.cs:37:9:37:15 | [b (line 32): false] SSA def(x) | Splitting.cs:38:15:38:15 | [b (line 32): false] access to local variable x | +| Splitting.cs:37:9:37:15 | [b (line 32): true] SSA def(x) | Splitting.cs:38:15:38:15 | [b (line 32): true] access to local variable x | +| Splitting.cs:37:13:37:15 | [b (line 32): false] "b" | Splitting.cs:37:9:37:15 | [b (line 32): false] SSA def(x) | +| Splitting.cs:37:13:37:15 | [b (line 32): true] "b" | Splitting.cs:37:9:37:15 | [b (line 32): true] SSA def(x) | +| Splitting.cs:38:15:38:15 | [b (line 32): false] access to local variable x | Splitting.cs:40:23:40:23 | [b (line 32): false] access to local variable x | +| Splitting.cs:38:15:38:15 | [b (line 32): true] access to local variable x | Splitting.cs:39:19:39:19 | [b (line 32): true] access to local variable x | +| Splitting.cs:39:15:39:15 | [b (line 32): false] access to parameter b | Splitting.cs:42:13:42:13 | [b (line 32): false] access to parameter b | +| Splitting.cs:39:15:39:15 | [b (line 32): true] access to parameter b | Splitting.cs:42:13:42:13 | [b (line 32): true] access to parameter b | +| Splitting.cs:39:19:39:19 | [b (line 32): true] access to local variable x | Splitting.cs:39:15:39:25 | [b (line 32): true] ... ? ... : ... | +| Splitting.cs:39:19:39:19 | [b (line 32): true] access to local variable x | Splitting.cs:40:23:40:23 | [b (line 32): true] access to local variable x | +| Splitting.cs:39:23:39:25 | [b (line 32): false] "c" | Splitting.cs:39:15:39:25 | [b (line 32): false] ... ? ... : ... | +| Splitting.cs:40:23:40:23 | [b (line 32): false] access to local variable x | Splitting.cs:40:15:40:23 | [b (line 32): false] (...) ... | +| Splitting.cs:40:23:40:23 | [b (line 32): true] access to local variable x | Splitting.cs:40:15:40:23 | [b (line 32): true] (...) ... | +| Splitting.cs:41:19:41:21 | [b (line 32): false] "d" | Splitting.cs:41:15:41:21 | [b (line 32): false] ... = ... | +| Splitting.cs:41:19:41:21 | [b (line 32): true] "d" | Splitting.cs:41:15:41:21 | [b (line 32): true] ... = ... | | Splitting.cs:46:18:46:18 | b | Splitting.cs:49:13:49:13 | access to parameter b | -| Splitting.cs:48:13:48:18 | SSA def(x) | Splitting.cs:53:13:53:13 | access to local variable x | +| Splitting.cs:48:13:48:18 | SSA def(x) | Splitting.cs:53:13:53:13 | [b (line 46): false] access to local variable x | | Splitting.cs:48:17:48:18 | "" | Splitting.cs:48:13:48:18 | SSA def(x) | -| Splitting.cs:49:13:49:13 | access to parameter b | Splitting.cs:60:13:60:13 | access to parameter b | -| Splitting.cs:50:13:50:21 | [b (line 46): true] SSA def(x) | Splitting.cs:53:13:53:13 | access to local variable x | -| Splitting.cs:50:17:50:21 | "abc" | Splitting.cs:50:13:50:21 | [b (line 46): true] SSA def(x) | -| Splitting.cs:51:13:51:36 | [b (line 46): false] SSA def(y) | Splitting.cs:52:9:52:9 | access to local variable y | -| Splitting.cs:51:13:51:36 | [b (line 46): true] SSA def(y) | Splitting.cs:52:9:52:9 | access to local variable y | -| Splitting.cs:51:17:51:36 | array creation of type String[] | Splitting.cs:51:13:51:36 | [b (line 46): false] SSA def(y) | -| Splitting.cs:51:17:51:36 | array creation of type String[] | Splitting.cs:51:13:51:36 | [b (line 46): true] SSA def(y) | -| Splitting.cs:52:9:52:9 | access to local variable y | Splitting.cs:53:17:53:17 | access to local variable y | -| Splitting.cs:53:9:53:20 | [b (line 46): false] SSA def(x) | Splitting.cs:54:17:54:17 | access to local variable x | -| Splitting.cs:53:9:53:20 | [b (line 46): true] SSA def(x) | Splitting.cs:54:17:54:17 | access to local variable x | -| Splitting.cs:53:13:53:20 | ... + ... | Splitting.cs:53:9:53:20 | [b (line 46): false] SSA def(x) | -| Splitting.cs:53:13:53:20 | ... + ... | Splitting.cs:53:9:53:20 | [b (line 46): true] SSA def(x) | -| Splitting.cs:53:17:53:17 | access to local variable y | Splitting.cs:57:17:57:17 | access to local variable y | -| Splitting.cs:54:13:54:23 | [b (line 46): false] SSA def(z) | Splitting.cs:55:14:55:14 | access to local variable z | -| Splitting.cs:54:13:54:23 | [b (line 46): true] SSA def(z) | Splitting.cs:55:14:55:14 | access to local variable z | -| Splitting.cs:54:17:54:17 | access to local variable x | Splitting.cs:56:17:56:17 | access to local variable x | -| Splitting.cs:54:17:54:23 | ... == ... | Splitting.cs:54:13:54:23 | [b (line 46): false] SSA def(z) | -| Splitting.cs:54:17:54:23 | ... == ... | Splitting.cs:54:13:54:23 | [b (line 46): true] SSA def(z) | -| Splitting.cs:56:9:56:19 | [b (line 46): false] SSA def(x) | Splitting.cs:57:14:57:14 | access to local variable x | -| Splitting.cs:56:9:56:19 | [b (line 46): true] SSA def(x) | Splitting.cs:57:14:57:14 | access to local variable x | -| Splitting.cs:56:13:56:19 | $"..." | Splitting.cs:56:9:56:19 | [b (line 46): false] SSA def(x) | -| Splitting.cs:56:13:56:19 | $"..." | Splitting.cs:56:9:56:19 | [b (line 46): true] SSA def(x) | -| Splitting.cs:57:17:57:17 | access to local variable y | Splitting.cs:58:27:58:27 | access to local variable y | -| Splitting.cs:58:22:58:22 | [b (line 46): false] SSA def(s) | Splitting.cs:59:19:59:19 | access to local variable s | -| Splitting.cs:58:22:58:22 | [b (line 46): true] SSA def(s) | Splitting.cs:59:19:59:19 | access to local variable s | +| Splitting.cs:49:13:49:13 | access to parameter b | Splitting.cs:60:13:60:13 | [b (line 46): false] access to parameter b | +| Splitting.cs:49:13:49:13 | access to parameter b | Splitting.cs:60:13:60:13 | [b (line 46): true] access to parameter b | +| Splitting.cs:50:13:50:21 | [b (line 46): true] SSA def(x) | Splitting.cs:53:13:53:13 | [b (line 46): true] access to local variable x | +| Splitting.cs:50:17:50:21 | [b (line 46): true] "abc" | Splitting.cs:50:13:50:21 | [b (line 46): true] SSA def(x) | +| Splitting.cs:51:13:51:36 | [b (line 46): false] SSA def(y) | Splitting.cs:52:9:52:9 | [b (line 46): false] access to local variable y | +| Splitting.cs:51:13:51:36 | [b (line 46): true] SSA def(y) | Splitting.cs:52:9:52:9 | [b (line 46): true] access to local variable y | +| Splitting.cs:51:17:51:36 | [b (line 46): false] array creation of type String[] | Splitting.cs:51:13:51:36 | [b (line 46): false] SSA def(y) | +| Splitting.cs:51:17:51:36 | [b (line 46): true] array creation of type String[] | Splitting.cs:51:13:51:36 | [b (line 46): true] SSA def(y) | +| Splitting.cs:52:9:52:9 | [b (line 46): false] access to local variable y | Splitting.cs:53:17:53:17 | [b (line 46): false] access to local variable y | +| Splitting.cs:52:9:52:9 | [b (line 46): true] access to local variable y | Splitting.cs:53:17:53:17 | [b (line 46): true] access to local variable y | +| Splitting.cs:53:9:53:20 | [b (line 46): false] SSA def(x) | Splitting.cs:54:17:54:17 | [b (line 46): false] access to local variable x | +| Splitting.cs:53:9:53:20 | [b (line 46): true] SSA def(x) | Splitting.cs:54:17:54:17 | [b (line 46): true] access to local variable x | +| Splitting.cs:53:13:53:20 | [b (line 46): false] ... + ... | Splitting.cs:53:9:53:20 | [b (line 46): false] SSA def(x) | +| Splitting.cs:53:13:53:20 | [b (line 46): true] ... + ... | Splitting.cs:53:9:53:20 | [b (line 46): true] SSA def(x) | +| Splitting.cs:53:17:53:17 | [b (line 46): false] access to local variable y | Splitting.cs:57:17:57:17 | [b (line 46): false] access to local variable y | +| Splitting.cs:53:17:53:17 | [b (line 46): true] access to local variable y | Splitting.cs:57:17:57:17 | [b (line 46): true] access to local variable y | +| Splitting.cs:54:13:54:23 | [b (line 46): false] SSA def(z) | Splitting.cs:55:14:55:14 | [b (line 46): false] access to local variable z | +| Splitting.cs:54:13:54:23 | [b (line 46): true] SSA def(z) | Splitting.cs:55:14:55:14 | [b (line 46): true] access to local variable z | +| Splitting.cs:54:17:54:17 | [b (line 46): false] access to local variable x | Splitting.cs:56:17:56:17 | [b (line 46): false] access to local variable x | +| Splitting.cs:54:17:54:17 | [b (line 46): true] access to local variable x | Splitting.cs:56:17:56:17 | [b (line 46): true] access to local variable x | +| Splitting.cs:54:17:54:23 | [b (line 46): false] ... == ... | Splitting.cs:54:13:54:23 | [b (line 46): false] SSA def(z) | +| Splitting.cs:54:17:54:23 | [b (line 46): true] ... == ... | Splitting.cs:54:13:54:23 | [b (line 46): true] SSA def(z) | +| Splitting.cs:56:9:56:19 | [b (line 46): false] SSA def(x) | Splitting.cs:57:14:57:14 | [b (line 46): false] access to local variable x | +| Splitting.cs:56:9:56:19 | [b (line 46): true] SSA def(x) | Splitting.cs:57:14:57:14 | [b (line 46): true] access to local variable x | +| Splitting.cs:56:13:56:19 | [b (line 46): false] $"..." | Splitting.cs:56:9:56:19 | [b (line 46): false] SSA def(x) | +| Splitting.cs:56:13:56:19 | [b (line 46): true] $"..." | Splitting.cs:56:9:56:19 | [b (line 46): true] SSA def(x) | +| Splitting.cs:57:17:57:17 | [b (line 46): false] access to local variable y | Splitting.cs:58:27:58:27 | [b (line 46): false] access to local variable y | +| Splitting.cs:57:17:57:17 | [b (line 46): true] access to local variable y | Splitting.cs:58:27:58:27 | [b (line 46): true] access to local variable y | +| Splitting.cs:58:22:58:22 | [b (line 46): false] SSA def(s) | Splitting.cs:59:19:59:19 | [b (line 46): false] access to local variable s | +| Splitting.cs:58:22:58:22 | [b (line 46): true] SSA def(s) | Splitting.cs:59:19:59:19 | [b (line 46): true] access to local variable s | diff --git a/csharp/ql/test/library-tests/dataflow/local/TaintTracking.expected b/csharp/ql/test/library-tests/dataflow/local/TaintTracking.expected index 71dc4a1b7c7..ba3d91130f2 100644 --- a/csharp/ql/test/library-tests/dataflow/local/TaintTracking.expected +++ b/csharp/ql/test/library-tests/dataflow/local/TaintTracking.expected @@ -3,7 +3,8 @@ | LocalDataFlow.cs:71:15:71:19 | access to local variable sink2 | | LocalDataFlow.cs:81:15:81:19 | access to local variable sink5 | | LocalDataFlow.cs:89:15:89:19 | access to local variable sink6 | -| LocalDataFlow.cs:97:15:97:19 | access to local variable sink7 | +| LocalDataFlow.cs:97:15:97:19 | [b (line 49): false] access to local variable sink7 | +| LocalDataFlow.cs:97:15:97:19 | [b (line 49): true] access to local variable sink7 | | LocalDataFlow.cs:105:15:105:19 | access to local variable sink8 | | LocalDataFlow.cs:113:15:113:19 | access to local variable sink9 | | LocalDataFlow.cs:121:15:121:20 | access to local variable sink10 | @@ -70,8 +71,7 @@ | SSA.cs:98:15:98:22 | access to local variable ssaSink4 | | SSA.cs:124:15:124:34 | access to field SsaFieldSink1 | | SSA.cs:180:15:180:22 | access to local variable ssaSink5 | -| Splitting.cs:8:19:8:19 | access to local variable x | -| Splitting.cs:12:15:12:15 | access to local variable x | -| Splitting.cs:25:15:25:15 | access to local variable x | +| Splitting.cs:8:19:8:19 | [b (line 3): true] access to local variable x | +| Splitting.cs:12:15:12:15 | [b (line 3): false] access to local variable x | +| Splitting.cs:25:15:25:15 | [b (line 17): true] access to local variable x | | Splitting.cs:27:19:27:19 | access to local variable x | -| Splitting.cs:29:19:29:19 | access to local variable x | diff --git a/csharp/ql/test/library-tests/dataflow/local/TaintTracking.ql b/csharp/ql/test/library-tests/dataflow/local/TaintTracking.ql index 32b3e84d476..faf328c17ea 100644 --- a/csharp/ql/test/library-tests/dataflow/local/TaintTracking.ql +++ b/csharp/ql/test/library-tests/dataflow/local/TaintTracking.ql @@ -4,7 +4,7 @@ import semmle.code.csharp.controlflow.Guards predicate step(DataFlow::Node pred, DataFlow::Node succ) { TaintTracking::localTaintStep(pred, succ) and - not succ.asExpr() instanceof NullGuardedExpr + not succ instanceof NullGuardedDataFlowNode } from MyFlowSource source, DataFlow::Node sink, Access target diff --git a/csharp/ql/test/library-tests/dataflow/local/TaintTrackingStep.expected b/csharp/ql/test/library-tests/dataflow/local/TaintTrackingStep.expected index 355893339a1..0db00060530 100644 --- a/csharp/ql/test/library-tests/dataflow/local/TaintTrackingStep.expected +++ b/csharp/ql/test/library-tests/dataflow/local/TaintTrackingStep.expected @@ -65,24 +65,28 @@ | LocalDataFlow.cs:85:15:85:22 | access to local variable nonSink0 | LocalDataFlow.cs:92:21:92:28 | access to local variable nonSink0 | | LocalDataFlow.cs:88:13:88:27 | SSA def(sink6) | LocalDataFlow.cs:89:15:89:19 | access to local variable sink6 | | LocalDataFlow.cs:88:22:88:26 | access to local variable sink5 | LocalDataFlow.cs:88:13:88:27 | SSA def(sink6) | -| LocalDataFlow.cs:89:15:89:19 | access to local variable sink6 | LocalDataFlow.cs:96:31:96:35 | access to local variable sink6 | +| LocalDataFlow.cs:89:15:89:19 | access to local variable sink6 | LocalDataFlow.cs:96:31:96:35 | [b (line 49): false] access to local variable sink6 | | LocalDataFlow.cs:92:9:92:29 | SSA def(nonSink0) | LocalDataFlow.cs:93:15:93:22 | access to local variable nonSink0 | | LocalDataFlow.cs:92:21:92:28 | access to local variable nonSink0 | LocalDataFlow.cs:92:9:92:29 | SSA def(nonSink0) | -| LocalDataFlow.cs:96:13:96:35 | [b (line 49): false] SSA def(sink7) | LocalDataFlow.cs:97:15:97:19 | access to local variable sink7 | -| LocalDataFlow.cs:96:13:96:35 | [b (line 49): true] SSA def(sink7) | LocalDataFlow.cs:97:15:97:19 | access to local variable sink7 | +| LocalDataFlow.cs:96:13:96:35 | [b (line 49): false] SSA def(sink7) | LocalDataFlow.cs:97:15:97:19 | [b (line 49): false] access to local variable sink7 | +| LocalDataFlow.cs:96:13:96:35 | [b (line 49): true] SSA def(sink7) | LocalDataFlow.cs:97:15:97:19 | [b (line 49): true] access to local variable sink7 | | LocalDataFlow.cs:96:21:96:21 | access to parameter b | LocalDataFlow.cs:96:21:96:35 | ... ? ... : ... | -| LocalDataFlow.cs:96:21:96:21 | access to parameter b | LocalDataFlow.cs:100:20:100:20 | access to parameter b | +| LocalDataFlow.cs:96:21:96:21 | access to parameter b | LocalDataFlow.cs:100:20:100:20 | [b (line 49): false] access to parameter b | +| LocalDataFlow.cs:96:21:96:21 | access to parameter b | LocalDataFlow.cs:100:20:100:20 | [b (line 49): true] access to parameter b | | LocalDataFlow.cs:96:21:96:35 | ... ? ... : ... | LocalDataFlow.cs:96:13:96:35 | [b (line 49): false] SSA def(sink7) | | LocalDataFlow.cs:96:21:96:35 | ... ? ... : ... | LocalDataFlow.cs:96:13:96:35 | [b (line 49): true] SSA def(sink7) | -| LocalDataFlow.cs:96:25:96:27 | "a" | LocalDataFlow.cs:96:21:96:35 | ... ? ... : ... | -| LocalDataFlow.cs:96:31:96:35 | access to local variable sink6 | LocalDataFlow.cs:96:21:96:35 | ... ? ... : ... | -| LocalDataFlow.cs:97:15:97:19 | access to local variable sink7 | LocalDataFlow.cs:100:9:100:36 | SSA phi(sink7) | +| LocalDataFlow.cs:96:25:96:27 | [b (line 49): true] "a" | LocalDataFlow.cs:96:21:96:35 | ... ? ... : ... | +| LocalDataFlow.cs:96:31:96:35 | [b (line 49): false] access to local variable sink6 | LocalDataFlow.cs:96:21:96:35 | ... ? ... : ... | +| LocalDataFlow.cs:97:15:97:19 | [b (line 49): false] access to local variable sink7 | LocalDataFlow.cs:100:9:100:36 | SSA phi(sink7) | +| LocalDataFlow.cs:97:15:97:19 | [b (line 49): true] access to local variable sink7 | LocalDataFlow.cs:100:9:100:36 | SSA phi(sink7) | | LocalDataFlow.cs:100:9:100:36 | SSA def(nonSink0) | LocalDataFlow.cs:101:15:101:22 | access to local variable nonSink0 | | LocalDataFlow.cs:100:9:100:36 | SSA phi(sink7) | LocalDataFlow.cs:104:29:104:33 | access to local variable sink7 | -| LocalDataFlow.cs:100:20:100:20 | access to parameter b | LocalDataFlow.cs:100:20:100:36 | ... ? ... : ... | -| LocalDataFlow.cs:100:20:100:36 | ... ? ... : ... | LocalDataFlow.cs:100:9:100:36 | SSA def(nonSink0) | -| LocalDataFlow.cs:100:24:100:28 | "abc" | LocalDataFlow.cs:100:20:100:36 | ... ? ... : ... | -| LocalDataFlow.cs:100:32:100:36 | "def" | LocalDataFlow.cs:100:20:100:36 | ... ? ... : ... | +| LocalDataFlow.cs:100:20:100:20 | [b (line 49): false] access to parameter b | LocalDataFlow.cs:100:20:100:36 | [b (line 49): false] ... ? ... : ... | +| LocalDataFlow.cs:100:20:100:20 | [b (line 49): true] access to parameter b | LocalDataFlow.cs:100:20:100:36 | [b (line 49): true] ... ? ... : ... | +| LocalDataFlow.cs:100:20:100:36 | [b (line 49): false] ... ? ... : ... | LocalDataFlow.cs:100:9:100:36 | SSA def(nonSink0) | +| LocalDataFlow.cs:100:20:100:36 | [b (line 49): true] ... ? ... : ... | LocalDataFlow.cs:100:9:100:36 | SSA def(nonSink0) | +| LocalDataFlow.cs:100:24:100:28 | "abc" | LocalDataFlow.cs:100:20:100:36 | [b (line 49): true] ... ? ... : ... | +| LocalDataFlow.cs:100:32:100:36 | "def" | LocalDataFlow.cs:100:20:100:36 | [b (line 49): false] ... ? ... : ... | | LocalDataFlow.cs:101:15:101:22 | access to local variable nonSink0 | LocalDataFlow.cs:108:32:108:39 | access to local variable nonSink0 | | LocalDataFlow.cs:104:13:104:33 | SSA def(sink8) | LocalDataFlow.cs:105:15:105:19 | access to local variable sink8 | | LocalDataFlow.cs:104:21:104:33 | (...) ... | LocalDataFlow.cs:104:13:104:33 | SSA def(sink8) | @@ -805,75 +809,103 @@ | SSA.cs:180:9:180:24 | SSA phi(ssaSink5) | SSA.cs:180:15:180:22 | access to local variable ssaSink5 | | Splitting.cs:3:18:3:18 | b | Splitting.cs:6:13:6:13 | access to parameter b | | Splitting.cs:3:28:3:34 | tainted | Splitting.cs:5:17:5:23 | access to parameter tainted | -| Splitting.cs:5:13:5:23 | SSA def(x) | Splitting.cs:8:19:8:19 | access to local variable x | -| Splitting.cs:5:13:5:23 | SSA def(x) | Splitting.cs:12:15:12:15 | access to local variable x | +| Splitting.cs:5:13:5:23 | SSA def(x) | Splitting.cs:8:19:8:19 | [b (line 3): true] access to local variable x | +| Splitting.cs:5:13:5:23 | SSA def(x) | Splitting.cs:12:15:12:15 | [b (line 3): false] access to local variable x | | Splitting.cs:5:17:5:23 | access to parameter tainted | Splitting.cs:5:13:5:23 | SSA def(x) | -| Splitting.cs:6:13:6:13 | access to parameter b | Splitting.cs:13:13:13:13 | access to parameter b | -| Splitting.cs:8:19:8:19 | access to local variable x | Splitting.cs:9:17:9:17 | access to local variable x | -| Splitting.cs:9:17:9:17 | access to local variable x | Splitting.cs:9:17:9:25 | ... == ... | -| Splitting.cs:12:15:12:15 | access to local variable x | Splitting.cs:14:19:14:19 | access to local variable x | +| Splitting.cs:6:13:6:13 | access to parameter b | Splitting.cs:13:13:13:13 | [b (line 3): false] access to parameter b | +| Splitting.cs:6:13:6:13 | access to parameter b | Splitting.cs:13:13:13:13 | [b (line 3): true] access to parameter b | +| Splitting.cs:8:19:8:19 | [b (line 3): true] access to local variable x | Splitting.cs:9:17:9:17 | [b (line 3): true] access to local variable x | +| Splitting.cs:9:17:9:17 | [b (line 3): true] access to local variable x | Splitting.cs:9:17:9:25 | [b (line 3): true] ... == ... | +| Splitting.cs:9:17:9:17 | [b (line 3): true] access to local variable x | Splitting.cs:12:15:12:15 | [b (line 3): true] access to local variable x | +| Splitting.cs:12:15:12:15 | [b (line 3): true] access to local variable x | Splitting.cs:14:19:14:19 | access to local variable x | | Splitting.cs:17:18:17:18 | b | Splitting.cs:20:13:20:13 | access to parameter b | -| Splitting.cs:19:13:19:18 | SSA def(x) | Splitting.cs:22:19:22:19 | access to local variable x | -| Splitting.cs:19:13:19:18 | SSA def(x) | Splitting.cs:25:15:25:15 | access to local variable x | +| Splitting.cs:19:13:19:18 | SSA def(x) | Splitting.cs:22:19:22:19 | [b (line 17): true] access to local variable x | +| Splitting.cs:19:13:19:18 | SSA def(x) | Splitting.cs:25:15:25:15 | [b (line 17): false] access to local variable x | | Splitting.cs:19:17:19:18 | "" | Splitting.cs:19:13:19:18 | SSA def(x) | -| Splitting.cs:20:13:20:13 | access to parameter b | Splitting.cs:26:13:26:13 | access to parameter b | -| Splitting.cs:23:13:23:30 | [b (line 17): true] SSA def(x) | Splitting.cs:25:15:25:15 | access to local variable x | -| Splitting.cs:23:17:23:30 | "taint source" | Splitting.cs:23:13:23:30 | [b (line 17): true] SSA def(x) | -| Splitting.cs:25:15:25:15 | access to local variable x | Splitting.cs:27:19:27:19 | access to local variable x | -| Splitting.cs:25:15:25:15 | access to local variable x | Splitting.cs:29:19:29:19 | access to local variable x | +| Splitting.cs:20:13:20:13 | access to parameter b | Splitting.cs:26:13:26:13 | [b (line 17): false] access to parameter b | +| Splitting.cs:20:13:20:13 | access to parameter b | Splitting.cs:26:13:26:13 | [b (line 17): true] access to parameter b | +| Splitting.cs:23:13:23:30 | [b (line 17): true] SSA def(x) | Splitting.cs:25:15:25:15 | [b (line 17): true] access to local variable x | +| Splitting.cs:23:17:23:30 | [b (line 17): true] "taint source" | Splitting.cs:23:13:23:30 | [b (line 17): true] SSA def(x) | +| Splitting.cs:25:15:25:15 | [b (line 17): false] access to local variable x | Splitting.cs:29:19:29:19 | access to local variable x | +| Splitting.cs:25:15:25:15 | [b (line 17): true] access to local variable x | Splitting.cs:27:19:27:19 | access to local variable x | | Splitting.cs:32:18:32:18 | b | Splitting.cs:35:13:35:13 | access to parameter b | -| Splitting.cs:35:13:35:13 | access to parameter b | Splitting.cs:39:15:39:15 | access to parameter b | -| Splitting.cs:37:9:37:15 | [b (line 32): false] SSA def(x) | Splitting.cs:38:15:38:15 | access to local variable x | -| Splitting.cs:37:9:37:15 | [b (line 32): true] SSA def(x) | Splitting.cs:38:15:38:15 | access to local variable x | -| Splitting.cs:37:13:37:15 | "b" | Splitting.cs:37:9:37:15 | [b (line 32): false] SSA def(x) | -| Splitting.cs:37:13:37:15 | "b" | Splitting.cs:37:9:37:15 | [b (line 32): true] SSA def(x) | -| Splitting.cs:38:15:38:15 | access to local variable x | Splitting.cs:39:19:39:19 | access to local variable x | -| Splitting.cs:39:15:39:15 | access to parameter b | Splitting.cs:39:15:39:25 | ... ? ... : ... | -| Splitting.cs:39:15:39:15 | access to parameter b | Splitting.cs:42:13:42:13 | access to parameter b | -| Splitting.cs:39:19:39:19 | access to local variable x | Splitting.cs:39:15:39:25 | ... ? ... : ... | -| Splitting.cs:39:23:39:25 | "c" | Splitting.cs:39:15:39:25 | ... ? ... : ... | -| Splitting.cs:40:23:40:23 | access to local variable x | Splitting.cs:40:15:40:23 | (...) ... | -| Splitting.cs:41:19:41:21 | "d" | Splitting.cs:41:15:41:21 | ... = ... | +| Splitting.cs:35:13:35:13 | access to parameter b | Splitting.cs:39:15:39:15 | [b (line 32): false] access to parameter b | +| Splitting.cs:35:13:35:13 | access to parameter b | Splitting.cs:39:15:39:15 | [b (line 32): true] access to parameter b | +| Splitting.cs:37:9:37:15 | [b (line 32): false] SSA def(x) | Splitting.cs:38:15:38:15 | [b (line 32): false] access to local variable x | +| Splitting.cs:37:9:37:15 | [b (line 32): true] SSA def(x) | Splitting.cs:38:15:38:15 | [b (line 32): true] access to local variable x | +| Splitting.cs:37:13:37:15 | [b (line 32): false] "b" | Splitting.cs:37:9:37:15 | [b (line 32): false] SSA def(x) | +| Splitting.cs:37:13:37:15 | [b (line 32): true] "b" | Splitting.cs:37:9:37:15 | [b (line 32): true] SSA def(x) | +| Splitting.cs:38:15:38:15 | [b (line 32): false] access to local variable x | Splitting.cs:40:23:40:23 | [b (line 32): false] access to local variable x | +| Splitting.cs:38:15:38:15 | [b (line 32): true] access to local variable x | Splitting.cs:39:19:39:19 | [b (line 32): true] access to local variable x | +| Splitting.cs:39:15:39:15 | [b (line 32): false] access to parameter b | Splitting.cs:39:15:39:25 | [b (line 32): false] ... ? ... : ... | +| Splitting.cs:39:15:39:15 | [b (line 32): false] access to parameter b | Splitting.cs:42:13:42:13 | [b (line 32): false] access to parameter b | +| Splitting.cs:39:15:39:15 | [b (line 32): true] access to parameter b | Splitting.cs:39:15:39:25 | [b (line 32): true] ... ? ... : ... | +| Splitting.cs:39:15:39:15 | [b (line 32): true] access to parameter b | Splitting.cs:42:13:42:13 | [b (line 32): true] access to parameter b | +| Splitting.cs:39:19:39:19 | [b (line 32): true] access to local variable x | Splitting.cs:39:15:39:25 | [b (line 32): true] ... ? ... : ... | +| Splitting.cs:39:19:39:19 | [b (line 32): true] access to local variable x | Splitting.cs:40:23:40:23 | [b (line 32): true] access to local variable x | +| Splitting.cs:39:23:39:25 | [b (line 32): false] "c" | Splitting.cs:39:15:39:25 | [b (line 32): false] ... ? ... : ... | +| Splitting.cs:40:23:40:23 | [b (line 32): false] access to local variable x | Splitting.cs:40:15:40:23 | [b (line 32): false] (...) ... | +| Splitting.cs:40:23:40:23 | [b (line 32): true] access to local variable x | Splitting.cs:40:15:40:23 | [b (line 32): true] (...) ... | +| Splitting.cs:41:19:41:21 | [b (line 32): false] "d" | Splitting.cs:41:15:41:21 | [b (line 32): false] ... = ... | +| Splitting.cs:41:19:41:21 | [b (line 32): true] "d" | Splitting.cs:41:15:41:21 | [b (line 32): true] ... = ... | | Splitting.cs:46:18:46:18 | b | Splitting.cs:49:13:49:13 | access to parameter b | -| Splitting.cs:48:13:48:18 | SSA def(x) | Splitting.cs:53:13:53:13 | access to local variable x | +| Splitting.cs:48:13:48:18 | SSA def(x) | Splitting.cs:53:13:53:13 | [b (line 46): false] access to local variable x | | Splitting.cs:48:17:48:18 | "" | Splitting.cs:48:13:48:18 | SSA def(x) | -| Splitting.cs:49:13:49:13 | access to parameter b | Splitting.cs:60:13:60:13 | access to parameter b | -| Splitting.cs:50:13:50:21 | [b (line 46): true] SSA def(x) | Splitting.cs:53:13:53:13 | access to local variable x | -| Splitting.cs:50:17:50:21 | "abc" | Splitting.cs:50:13:50:21 | [b (line 46): true] SSA def(x) | -| Splitting.cs:51:13:51:36 | [b (line 46): false] SSA def(y) | Splitting.cs:52:9:52:9 | access to local variable y | -| Splitting.cs:51:13:51:36 | [b (line 46): true] SSA def(y) | Splitting.cs:52:9:52:9 | access to local variable y | -| Splitting.cs:51:17:51:36 | array creation of type String[] | Splitting.cs:51:13:51:36 | [b (line 46): false] SSA def(y) | -| Splitting.cs:51:17:51:36 | array creation of type String[] | Splitting.cs:51:13:51:36 | [b (line 46): true] SSA def(y) | -| Splitting.cs:51:32:51:34 | "a" | Splitting.cs:51:17:51:36 | array creation of type String[] | -| Splitting.cs:52:9:52:9 | access to local variable y | Splitting.cs:52:9:52:12 | access to array element | -| Splitting.cs:52:9:52:9 | access to local variable y | Splitting.cs:53:17:53:17 | access to local variable y | -| Splitting.cs:52:16:52:18 | "b" | Splitting.cs:52:9:52:9 | access to local variable y | -| Splitting.cs:53:9:53:20 | [b (line 46): false] SSA def(x) | Splitting.cs:54:17:54:17 | access to local variable x | -| Splitting.cs:53:9:53:20 | [b (line 46): true] SSA def(x) | Splitting.cs:54:17:54:17 | access to local variable x | -| Splitting.cs:53:13:53:13 | access to local variable x | Splitting.cs:53:13:53:20 | ... + ... | -| Splitting.cs:53:13:53:20 | ... + ... | Splitting.cs:53:9:53:20 | [b (line 46): false] SSA def(x) | -| Splitting.cs:53:13:53:20 | ... + ... | Splitting.cs:53:9:53:20 | [b (line 46): true] SSA def(x) | -| Splitting.cs:53:17:53:17 | access to local variable y | Splitting.cs:53:17:53:20 | access to array element | -| Splitting.cs:53:17:53:17 | access to local variable y | Splitting.cs:57:17:57:17 | access to local variable y | -| Splitting.cs:53:17:53:20 | access to array element | Splitting.cs:53:13:53:20 | ... + ... | -| Splitting.cs:54:13:54:23 | [b (line 46): false] SSA def(z) | Splitting.cs:55:14:55:14 | access to local variable z | -| Splitting.cs:54:13:54:23 | [b (line 46): true] SSA def(z) | Splitting.cs:55:14:55:14 | access to local variable z | -| Splitting.cs:54:17:54:17 | access to local variable x | Splitting.cs:54:17:54:23 | ... == ... | -| Splitting.cs:54:17:54:17 | access to local variable x | Splitting.cs:56:17:56:17 | access to local variable x | -| Splitting.cs:54:17:54:23 | ... == ... | Splitting.cs:54:13:54:23 | [b (line 46): false] SSA def(z) | -| Splitting.cs:54:17:54:23 | ... == ... | Splitting.cs:54:13:54:23 | [b (line 46): true] SSA def(z) | -| Splitting.cs:55:14:55:14 | access to local variable z | Splitting.cs:55:13:55:14 | !... | -| Splitting.cs:56:9:56:19 | [b (line 46): false] SSA def(x) | Splitting.cs:57:14:57:14 | access to local variable x | -| Splitting.cs:56:9:56:19 | [b (line 46): true] SSA def(x) | Splitting.cs:57:14:57:14 | access to local variable x | -| Splitting.cs:56:13:56:19 | $"..." | Splitting.cs:56:9:56:19 | [b (line 46): false] SSA def(x) | -| Splitting.cs:56:13:56:19 | $"..." | Splitting.cs:56:9:56:19 | [b (line 46): true] SSA def(x) | -| Splitting.cs:56:15:56:15 | "c" | Splitting.cs:56:13:56:19 | $"..." | -| Splitting.cs:56:17:56:17 | access to local variable x | Splitting.cs:56:13:56:19 | $"..." | -| Splitting.cs:57:13:57:18 | (..., ...) | Splitting.cs:57:13:57:24 | access to field Item1 | -| Splitting.cs:57:14:57:14 | access to local variable x | Splitting.cs:57:13:57:18 | (..., ...) | -| Splitting.cs:57:17:57:17 | access to local variable y | Splitting.cs:57:13:57:18 | (..., ...) | -| Splitting.cs:57:17:57:17 | access to local variable y | Splitting.cs:58:27:58:27 | access to local variable y | -| Splitting.cs:58:22:58:22 | [b (line 46): false] SSA def(s) | Splitting.cs:59:19:59:19 | access to local variable s | -| Splitting.cs:58:22:58:22 | [b (line 46): true] SSA def(s) | Splitting.cs:59:19:59:19 | access to local variable s | -| Splitting.cs:58:27:58:27 | access to local variable y | Splitting.cs:58:22:58:22 | [b (line 46): false] SSA def(s) | -| Splitting.cs:58:27:58:27 | access to local variable y | Splitting.cs:58:22:58:22 | [b (line 46): true] SSA def(s) | +| Splitting.cs:49:13:49:13 | access to parameter b | Splitting.cs:60:13:60:13 | [b (line 46): false] access to parameter b | +| Splitting.cs:49:13:49:13 | access to parameter b | Splitting.cs:60:13:60:13 | [b (line 46): true] access to parameter b | +| Splitting.cs:50:13:50:21 | [b (line 46): true] SSA def(x) | Splitting.cs:53:13:53:13 | [b (line 46): true] access to local variable x | +| Splitting.cs:50:17:50:21 | [b (line 46): true] "abc" | Splitting.cs:50:13:50:21 | [b (line 46): true] SSA def(x) | +| Splitting.cs:51:13:51:36 | [b (line 46): false] SSA def(y) | Splitting.cs:52:9:52:9 | [b (line 46): false] access to local variable y | +| Splitting.cs:51:13:51:36 | [b (line 46): true] SSA def(y) | Splitting.cs:52:9:52:9 | [b (line 46): true] access to local variable y | +| Splitting.cs:51:17:51:36 | [b (line 46): false] array creation of type String[] | Splitting.cs:51:13:51:36 | [b (line 46): false] SSA def(y) | +| Splitting.cs:51:17:51:36 | [b (line 46): true] array creation of type String[] | Splitting.cs:51:13:51:36 | [b (line 46): true] SSA def(y) | +| Splitting.cs:51:32:51:34 | [b (line 46): false] "a" | Splitting.cs:51:17:51:36 | [b (line 46): false] array creation of type String[] | +| Splitting.cs:51:32:51:34 | [b (line 46): true] "a" | Splitting.cs:51:17:51:36 | [b (line 46): true] array creation of type String[] | +| Splitting.cs:52:9:52:9 | [b (line 46): false] access to local variable y | Splitting.cs:52:9:52:12 | [b (line 46): false] access to array element | +| Splitting.cs:52:9:52:9 | [b (line 46): false] access to local variable y | Splitting.cs:53:17:53:17 | [b (line 46): false] access to local variable y | +| Splitting.cs:52:9:52:9 | [b (line 46): true] access to local variable y | Splitting.cs:52:9:52:12 | [b (line 46): true] access to array element | +| Splitting.cs:52:9:52:9 | [b (line 46): true] access to local variable y | Splitting.cs:53:17:53:17 | [b (line 46): true] access to local variable y | +| Splitting.cs:52:16:52:18 | [b (line 46): false] "b" | Splitting.cs:52:9:52:9 | [b (line 46): false] access to local variable y | +| Splitting.cs:52:16:52:18 | [b (line 46): true] "b" | Splitting.cs:52:9:52:9 | [b (line 46): true] access to local variable y | +| Splitting.cs:53:9:53:20 | [b (line 46): false] SSA def(x) | Splitting.cs:54:17:54:17 | [b (line 46): false] access to local variable x | +| Splitting.cs:53:9:53:20 | [b (line 46): true] SSA def(x) | Splitting.cs:54:17:54:17 | [b (line 46): true] access to local variable x | +| Splitting.cs:53:13:53:13 | [b (line 46): false] access to local variable x | Splitting.cs:53:13:53:20 | [b (line 46): false] ... + ... | +| Splitting.cs:53:13:53:13 | [b (line 46): true] access to local variable x | Splitting.cs:53:13:53:20 | [b (line 46): true] ... + ... | +| Splitting.cs:53:13:53:20 | [b (line 46): false] ... + ... | Splitting.cs:53:9:53:20 | [b (line 46): false] SSA def(x) | +| Splitting.cs:53:13:53:20 | [b (line 46): true] ... + ... | Splitting.cs:53:9:53:20 | [b (line 46): true] SSA def(x) | +| Splitting.cs:53:17:53:17 | [b (line 46): false] access to local variable y | Splitting.cs:53:17:53:20 | [b (line 46): false] access to array element | +| Splitting.cs:53:17:53:17 | [b (line 46): false] access to local variable y | Splitting.cs:57:17:57:17 | [b (line 46): false] access to local variable y | +| Splitting.cs:53:17:53:17 | [b (line 46): true] access to local variable y | Splitting.cs:53:17:53:20 | [b (line 46): true] access to array element | +| Splitting.cs:53:17:53:17 | [b (line 46): true] access to local variable y | Splitting.cs:57:17:57:17 | [b (line 46): true] access to local variable y | +| Splitting.cs:53:17:53:20 | [b (line 46): false] access to array element | Splitting.cs:53:13:53:20 | [b (line 46): false] ... + ... | +| Splitting.cs:53:17:53:20 | [b (line 46): true] access to array element | Splitting.cs:53:13:53:20 | [b (line 46): true] ... + ... | +| Splitting.cs:54:13:54:23 | [b (line 46): false] SSA def(z) | Splitting.cs:55:14:55:14 | [b (line 46): false] access to local variable z | +| Splitting.cs:54:13:54:23 | [b (line 46): true] SSA def(z) | Splitting.cs:55:14:55:14 | [b (line 46): true] access to local variable z | +| Splitting.cs:54:17:54:17 | [b (line 46): false] access to local variable x | Splitting.cs:54:17:54:23 | [b (line 46): false] ... == ... | +| Splitting.cs:54:17:54:17 | [b (line 46): false] access to local variable x | Splitting.cs:56:17:56:17 | [b (line 46): false] access to local variable x | +| Splitting.cs:54:17:54:17 | [b (line 46): true] access to local variable x | Splitting.cs:54:17:54:23 | [b (line 46): true] ... == ... | +| Splitting.cs:54:17:54:17 | [b (line 46): true] access to local variable x | Splitting.cs:56:17:56:17 | [b (line 46): true] access to local variable x | +| Splitting.cs:54:17:54:23 | [b (line 46): false] ... == ... | Splitting.cs:54:13:54:23 | [b (line 46): false] SSA def(z) | +| Splitting.cs:54:17:54:23 | [b (line 46): true] ... == ... | Splitting.cs:54:13:54:23 | [b (line 46): true] SSA def(z) | +| Splitting.cs:55:14:55:14 | [b (line 46): false] access to local variable z | Splitting.cs:55:13:55:14 | [b (line 46): false] !... | +| Splitting.cs:55:14:55:14 | [b (line 46): true] access to local variable z | Splitting.cs:55:13:55:14 | [b (line 46): true] !... | +| Splitting.cs:56:9:56:19 | [b (line 46): false] SSA def(x) | Splitting.cs:57:14:57:14 | [b (line 46): false] access to local variable x | +| Splitting.cs:56:9:56:19 | [b (line 46): true] SSA def(x) | Splitting.cs:57:14:57:14 | [b (line 46): true] access to local variable x | +| Splitting.cs:56:13:56:19 | [b (line 46): false] $"..." | Splitting.cs:56:9:56:19 | [b (line 46): false] SSA def(x) | +| Splitting.cs:56:13:56:19 | [b (line 46): true] $"..." | Splitting.cs:56:9:56:19 | [b (line 46): true] SSA def(x) | +| Splitting.cs:56:15:56:15 | [b (line 46): false] "c" | Splitting.cs:56:13:56:19 | [b (line 46): false] $"..." | +| Splitting.cs:56:15:56:15 | [b (line 46): true] "c" | Splitting.cs:56:13:56:19 | [b (line 46): true] $"..." | +| Splitting.cs:56:17:56:17 | [b (line 46): false] access to local variable x | Splitting.cs:56:13:56:19 | [b (line 46): false] $"..." | +| Splitting.cs:56:17:56:17 | [b (line 46): true] access to local variable x | Splitting.cs:56:13:56:19 | [b (line 46): true] $"..." | +| Splitting.cs:57:13:57:18 | [b (line 46): false] (..., ...) | Splitting.cs:57:13:57:24 | [b (line 46): false] access to field Item1 | +| Splitting.cs:57:13:57:18 | [b (line 46): true] (..., ...) | Splitting.cs:57:13:57:24 | [b (line 46): true] access to field Item1 | +| Splitting.cs:57:14:57:14 | [b (line 46): false] access to local variable x | Splitting.cs:57:13:57:18 | [b (line 46): false] (..., ...) | +| Splitting.cs:57:14:57:14 | [b (line 46): true] access to local variable x | Splitting.cs:57:13:57:18 | [b (line 46): true] (..., ...) | +| Splitting.cs:57:17:57:17 | [b (line 46): false] access to local variable y | Splitting.cs:57:13:57:18 | [b (line 46): false] (..., ...) | +| Splitting.cs:57:17:57:17 | [b (line 46): false] access to local variable y | Splitting.cs:58:27:58:27 | [b (line 46): false] access to local variable y | +| Splitting.cs:57:17:57:17 | [b (line 46): true] access to local variable y | Splitting.cs:57:13:57:18 | [b (line 46): true] (..., ...) | +| Splitting.cs:57:17:57:17 | [b (line 46): true] access to local variable y | Splitting.cs:58:27:58:27 | [b (line 46): true] access to local variable y | +| Splitting.cs:58:22:58:22 | [b (line 46): false] SSA def(s) | Splitting.cs:59:19:59:19 | [b (line 46): false] access to local variable s | +| Splitting.cs:58:22:58:22 | [b (line 46): true] SSA def(s) | Splitting.cs:59:19:59:19 | [b (line 46): true] access to local variable s | +| Splitting.cs:58:27:58:27 | [b (line 46): false] access to local variable y | Splitting.cs:58:22:58:22 | [b (line 46): false] SSA def(s) | +| Splitting.cs:58:27:58:27 | [b (line 46): true] access to local variable y | Splitting.cs:58:22:58:22 | [b (line 46): true] SSA def(s) | diff --git a/csharp/ql/test/library-tests/dispatch/CallGraph.expected b/csharp/ql/test/library-tests/dispatch/CallGraph.expected index ba6b3211313..a0c105c1c78 100644 --- a/csharp/ql/test/library-tests/dispatch/CallGraph.expected +++ b/csharp/ql/test/library-tests/dispatch/CallGraph.expected @@ -175,4 +175,5 @@ | ViableCallable.cs:409:10:409:12 | Run | ViableCallable.cs:403:53:403:57 | M | | ViableCallable.cs:409:10:409:12 | Run | ViableCallable.cs:405:42:405:46 | M | | ViableCallable.cs:431:25:431:29 | M2 | ViableCallable.cs:442:17:442:23 | (...) => ... | -| ViableCallable.cs:436:9:436:9 | M | ViableCallable.cs:430:23:430:24 | M1 | +| ViableCallable.cs:436:10:436:10 | M | ViableCallable.cs:430:23:430:24 | M1 | +| ViableCallable.cs:436:10:436:10 | M | ViableCallable.cs:431:25:431:29 | M2 | diff --git a/csharp/ql/test/library-tests/dispatch/GetADynamicTarget.expected b/csharp/ql/test/library-tests/dispatch/GetADynamicTarget.expected index 79635595706..c481da2b77d 100644 --- a/csharp/ql/test/library-tests/dispatch/GetADynamicTarget.expected +++ b/csharp/ql/test/library-tests/dispatch/GetADynamicTarget.expected @@ -399,5 +399,5 @@ | ViableCallable.cs:422:13:422:37 | call to method Mock | ViableCallable.Mock() | | ViableCallable.cs:424:9:424:21 | call to method M | C15.A4.M() | | ViableCallable.cs:424:9:424:21 | call to method M | C15.A5.M() | -| ViableCallable.cs:439:16:439:26 | call to method M1 | C16.M1(string) | +| ViableCallable.cs:439:9:439:19 | call to method M1 | C16.M1(string) | | ViableCallable.cs:442:9:442:24 | call to method M2 | C16.M2(Func) | diff --git a/csharp/ql/test/library-tests/dispatch/ViableCallable.cs b/csharp/ql/test/library-tests/dispatch/ViableCallable.cs index fe32511ac19..e51c9c4b625 100644 --- a/csharp/ql/test/library-tests/dispatch/ViableCallable.cs +++ b/csharp/ql/test/library-tests/dispatch/ViableCallable.cs @@ -433,10 +433,10 @@ abstract class C16 class C17 : C16 { - int M(int i) + void M(int i) { // Viable callables: C16.M1() - return this.M1(""); + this.M1(""); // Viable callables: C16.M2() this.M2(() => i); diff --git a/csharp/ql/test/query-tests/Security Features/CWE-209/ExceptionInformationExposure.cs b/csharp/ql/test/query-tests/Security Features/CWE-209/ExceptionInformationExposure.cs index 9b8e37a7402..2a7cc3ae232 100644 --- a/csharp/ql/test/query-tests/Security Features/CWE-209/ExceptionInformationExposure.cs +++ b/csharp/ql/test/query-tests/Security Features/CWE-209/ExceptionInformationExposure.cs @@ -5,7 +5,7 @@ using System.Web; public class StackTraceHandler : IHttpHandler { - + bool b; public void ProcessRequest(HttpContext ctx) { try @@ -54,7 +54,8 @@ public class StackTraceHandler : IHttpHandler // Method that may throw an exception public void doSomeWork() { - throw new Exception(); + if (b) + throw new Exception(); } public void log(string s, Exception e) From 64ed9305d39a470406e1bcb699bd6ddbd4687434 Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Thu, 17 Jan 2019 10:45:10 -0800 Subject: [PATCH 06/33] C++: new query for futile arguments to C functions --- .../Likely Bugs/Likely Typos/FutileParams.c | 11 +++++++++ .../Likely Typos/FutileParams.qhelp | 24 +++++++++++++++++++ .../Likely Bugs/Likely Typos/FutileParams.ql | 18 ++++++++++++++ .../FutileParams/FutileParams.expected | 3 +++ .../FutileParams/FutileParams.qlref | 1 + .../Likely Typos/FutileParams/test.c | 18 ++++++++++++++ .../Likely Typos/FutileParams/test.cpp | 8 +++++++ 7 files changed, 83 insertions(+) create mode 100644 cpp/ql/src/Likely Bugs/Likely Typos/FutileParams.c create mode 100644 cpp/ql/src/Likely Bugs/Likely Typos/FutileParams.qhelp create mode 100644 cpp/ql/src/Likely Bugs/Likely Typos/FutileParams.ql create mode 100644 cpp/ql/test/query-tests/Likely Bugs/Likely Typos/FutileParams/FutileParams.expected create mode 100644 cpp/ql/test/query-tests/Likely Bugs/Likely Typos/FutileParams/FutileParams.qlref create mode 100644 cpp/ql/test/query-tests/Likely Bugs/Likely Typos/FutileParams/test.c create mode 100644 cpp/ql/test/query-tests/Likely Bugs/Likely Typos/FutileParams/test.cpp diff --git a/cpp/ql/src/Likely Bugs/Likely Typos/FutileParams.c b/cpp/ql/src/Likely Bugs/Likely Typos/FutileParams.c new file mode 100644 index 00000000000..1a827a6c90a --- /dev/null +++ b/cpp/ql/src/Likely Bugs/Likely Typos/FutileParams.c @@ -0,0 +1,11 @@ +void no_argument(); + +void one_argument(int x); + +void calls() { + no_argument(1) // BAD: `no_argument` will accept and ignore the argument + + one_argument(1); // GOOD: `one_argument` will accept and use the argument + + no_argument(); // GOOD: `no_argument` has not been passed an argument +} \ No newline at end of file diff --git a/cpp/ql/src/Likely Bugs/Likely Typos/FutileParams.qhelp b/cpp/ql/src/Likely Bugs/Likely Typos/FutileParams.qhelp new file mode 100644 index 00000000000..b5fdeeb7f31 --- /dev/null +++ b/cpp/ql/src/Likely Bugs/Likely Typos/FutileParams.qhelp @@ -0,0 +1,24 @@ + + + + + +

A function is called with arguments despite having an empty parameter list. This may indicate +that the incorrect function is being called, or that the author misunderstood the function.

+ +
+ +

Call the function without arguments, or call a different function that expects the arguments +being passed.

+ +
+ + + + + +
  • SEI CERT C++ Coding Standard: DCL20-C. Explicitly specify void when a function accepts no arguments
  • +
    +
    diff --git a/cpp/ql/src/Likely Bugs/Likely Typos/FutileParams.ql b/cpp/ql/src/Likely Bugs/Likely Typos/FutileParams.ql new file mode 100644 index 00000000000..ec7260d5d7f --- /dev/null +++ b/cpp/ql/src/Likely Bugs/Likely Typos/FutileParams.ql @@ -0,0 +1,18 @@ +/** + * @name Non-empty call to function declared without parameters + * @description A call to a function declared without parameters has arguments, which may indicate + * that the code does not follow the author's intent. + * @kind problem + * @problem.severity warning + */ + +import cpp + +from Function f, FunctionCall fc +where fc.getTarget() = f + and f.getNumberOfParameters() = 0 + and not f.isVarargs() + and fc.getNumberOfArguments() != 0 + and not f instanceof BuiltInFunction + and exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() | not fde.isImplicit()) +select fc, "This call has arguments, but $@ is not declared with any parameters.", f, f.toString() diff --git a/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/FutileParams/FutileParams.expected b/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/FutileParams/FutileParams.expected new file mode 100644 index 00000000000..7ba6f06b2e4 --- /dev/null +++ b/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/FutileParams/FutileParams.expected @@ -0,0 +1,3 @@ +| test.c:7:3:7:5 | call to foo | This call has arguments, but $@ is not declared with any parameters. | test.c:1:6:1:8 | foo | foo | +| test.c:13:3:13:19 | call to not_yet_declared1 | This call has arguments, but $@ is not declared with any parameters. | test.c:13:3:13:3 | not_yet_declared1 | not_yet_declared1 | +| test.c:13:3:13:19 | call to not_yet_declared1 | This call has arguments, but $@ is not declared with any parameters. | test.c:17:6:17:22 | not_yet_declared1 | not_yet_declared1 | diff --git a/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/FutileParams/FutileParams.qlref b/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/FutileParams/FutileParams.qlref new file mode 100644 index 00000000000..f6dbe907dc5 --- /dev/null +++ b/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/FutileParams/FutileParams.qlref @@ -0,0 +1 @@ +Likely Bugs/Likely Typos/FutileParams.ql diff --git a/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/FutileParams/test.c b/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/FutileParams/test.c new file mode 100644 index 00000000000..67bb7726693 --- /dev/null +++ b/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/FutileParams/test.c @@ -0,0 +1,18 @@ +void foo(); +void bar(void); +void baz(int); + +void test() { + foo(); // GOOD + foo(1); // BAD + bar(); // GOOD + baz(1); // GOOD + + undeclared(1); // GOOD + + not_yet_declared1(1); // BAD + not_yet_declared2(1); // GOOD +} + +void not_yet_declared1(); +void not_yet_declared2(int); \ No newline at end of file diff --git a/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/FutileParams/test.cpp b/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/FutileParams/test.cpp new file mode 100644 index 00000000000..855fdaea3fd --- /dev/null +++ b/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/FutileParams/test.cpp @@ -0,0 +1,8 @@ +void cpp_varargs(...); +void bar(); + +void test() { + cpp_varargs(); // GOOD + cpp_varargs(1); // GOOD + __builtin_constant_p("something"); // GOOD: builtin +} \ No newline at end of file From 6bbbb85a7358f582bbd00d313973c868c5562afe Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Mon, 21 Jan 2019 11:56:39 +0000 Subject: [PATCH 07/33] Python: Remove some negation from points-to, in preparation for ADT Objects. --- .../src/semmle/python/pointsto/PointsTo.qll | 116 +++++++++++------- .../src/semmle/python/types/ClassObject.qll | 4 + .../src/semmle/python/types/ModuleObject.qll | 8 ++ python/ql/src/semmle/python/types/Object.qll | 8 ++ 4 files changed, 89 insertions(+), 47 deletions(-) diff --git a/python/ql/src/semmle/python/pointsto/PointsTo.qll b/python/ql/src/semmle/python/pointsto/PointsTo.qll index 06c7b8c2d85..90155f60708 100644 --- a/python/ql/src/semmle/python/pointsto/PointsTo.qll +++ b/python/ql/src/semmle/python/pointsto/PointsTo.qll @@ -139,7 +139,7 @@ module PointsTo { var.getSourceVariable().getName() = name and ssa_variable_points_to(var, imp, obj, cls, orig) and imp.isImport() and - not obj = undefinedVariable() | + obj != undefinedVariable() | origin = origin_from_object_or_here(orig, exit) ) or @@ -147,7 +147,7 @@ module PointsTo { exists(EssaVariable var, PointsToContext imp | var.getAUse() = m.getANormalExit() and var.getSourceVariable().getName() = "*" | SSA::ssa_variable_named_attribute_points_to(var, imp, name, obj, cls, origin) and - imp.isImport() and not obj = undefinedVariable() + imp.isImport() and obj != undefinedVariable() ) } @@ -257,7 +257,7 @@ module PointsTo { /** Holds if `f` is the instantiation of an object, `cls(...)`. */ cached predicate instantiation(CallNode f, PointsToContext context, ClassObject cls) { points_to(f.getFunction(), context, cls, _, _) and - not cls = theTypeType() and + cls != theTypeType() and Types::callToClassWillReturnInstance(cls) } @@ -313,7 +313,7 @@ module PointsTo { ) or exists(Object obj | - not obj = undefinedVariable() and + obj != undefinedVariable() and py_module_attributes(mod.getModule(), name, obj, _, _) ) and result = true or @@ -346,7 +346,7 @@ module PointsTo { private boolean package_exports_boolean(PackageObject pack, string name) { explicitly_imported(pack.submodule(name)) and ( - not exists(pack.getInitModule()) + pack.hasNoInitModule() or exists(ModuleObject init | pack.getInitModule() = init | @@ -382,9 +382,11 @@ module PointsTo { exists(Object value | points_to(guard.getLastNode(), context, value, _, _) | - guard.controls(b, true) and not value.booleanValue() = false + guard.controls(b, _) and value.maybe() or - guard.controls(b, false) and not value.booleanValue() = true + guard.controls(b, true) and value.booleanValue() = true + or + guard.controls(b, false) and value.booleanValue() = false ) or /* Assume the true edge of an assert is reachable (except for assert 0/False) */ @@ -403,9 +405,11 @@ module PointsTo { exists(ConditionBlock guard, Object value | points_to(guard.getLastNode(), context, value, _, _) | - guard.controlsEdge(pred, succ, true) and not value.booleanValue() = false + guard.controlsEdge(pred, succ, _) and value.maybe() or - guard.controlsEdge(pred, succ, false) and not value.booleanValue() = true + guard.controlsEdge(pred, succ, true) and value.booleanValue() = true + or + guard.controlsEdge(pred, succ, false) and value.booleanValue() = false ) } @@ -554,7 +558,7 @@ module PointsTo { /** Gets an object pointed to by a use (of a variable). */ private predicate use_points_to(NameNode f, PointsToContext context, Object value, ClassObject cls, ControlFlowNode origin) { exists(ObjectOrCfg origin_or_obj | - not value = undefinedVariable() and + value != undefinedVariable() and use_points_to_maybe_origin(f, context, value, cls, origin_or_obj) | origin = origin_from_object_or_here(origin_or_obj, f) ) @@ -578,7 +582,7 @@ module PointsTo { pragma [noinline] private predicate class_or_module_attribute(Object obj, string name, Object value, ClassObject cls, ObjectOrCfg orig) { /* Normal class attributes */ - Types::class_attribute_lookup(obj, name, value, cls, orig) and not cls = theStaticMethodType() and not cls = theClassMethodType() + Types::class_attribute_lookup(obj, name, value, cls, orig) and cls != theStaticMethodType() and cls != theClassMethodType() or /* Static methods of the class */ exists(CallNode sm | Types::class_attribute_lookup(obj, name, sm, theStaticMethodType(), _) and sm.getArg(0) = value and cls = thePyFunctionType() and orig = value) @@ -849,9 +853,13 @@ module PointsTo { exists(Object operand | points_to(f.getOperand(), context, operand, _, _) | - not operand.booleanValue() = true and value = theTrueObject() + operand.maybe() and value = theTrueObject() or - not operand.booleanValue() = false and value = theFalseObject() + operand.maybe() and value = theFalseObject() + or + operand.booleanValue() = false and value = theTrueObject() + or + operand.booleanValue() = true and value = theFalseObject() ) } @@ -999,17 +1007,18 @@ module PointsTo { pragma [noinline] predicate call_points_to_builtin_function(CallNode f, PointsToContext context, Object value, ClassObject cls, ControlFlowNode origin) { exists(BuiltinCallable b | - not b = builtin_object("isinstance") and - not b = builtin_object("issubclass") and - not b = builtin_object("callable") and + b != builtin_object("isinstance") and + b != builtin_object("issubclass") and + b != builtin_object("callable") and f = get_a_call(b, context) and cls = b.getAReturnType() ) and f = origin and - if cls = theNoneType() then - value = theNoneObject() - else - value = f + ( + cls = theNoneType() and value = theNoneObject() + or + cls != theNoneType() and value = f + ) } /** Holds if call is to an object that always returns its first argument. @@ -1156,7 +1165,7 @@ module PointsTo { cls != theSuperType() and exists(Object o | /* list.__init__() is not a call to type.__init__() */ - not o instanceof ClassObject | + o.notClass() | points_to(n.(AttrNode).getObject(name), context, o, cls, _) ) or @@ -1199,12 +1208,14 @@ module PointsTo { /** Holds if `func` implicitly returns the `None` object */ predicate implicitly_returns(PyFunctionObject func, Object none_, ClassObject noneType) { - noneType = theNoneType() and not func.getFunction().isGenerator() and none_ = theNoneObject() and - ( - not exists(func.getAReturnedNode()) and exists(func.getFunction().getANormalExit()) - or - exists(Return ret | ret.getScope() = func.getFunction() and not exists(ret.getValue())) - ) + noneType = theNoneType() and none_ = theNoneObject() and + exists(Function f | + f = func.getFunction() and not f.isGenerator() + | + not exists(Return ret | ret.getScope() = f) and exists(f.getANormalExit()) + or + exists(Return ret | ret.getScope() = f and not exists(ret.getValue())) + ) } } @@ -1240,7 +1251,10 @@ module PointsTo { * is available to all functions. Although not strictly true, this gives less surprising * results in practice. */ pred_context.isMain() and pred_scope instanceof Module and succ_context.fromRuntime() and - not strictcount(pred_var.getSourceVariable().(Variable).getAStore()) > 1 + exists(Variable v | + v = pred_var.getSourceVariable() and + not strictcount(v.getAStore()) > 1 + ) ) or exists(NonEscapingGlobalVariable var | @@ -1567,8 +1581,8 @@ module PointsTo { deco = f.getADecorator().getAFlowNode() | exists(Object o | points_to(deco, _, o, _, _) | - not o = theStaticMethodType() and - not o = theClassMethodType() + o != theStaticMethodType() and + o != theClassMethodType() ) or not deco instanceof NameNode ) @@ -1585,7 +1599,7 @@ module PointsTo { | obj instanceof ClassObject and value = obj and cls = objcls or - not obj instanceof ClassObject and value = objcls and cls = Types::class_get_meta_class(objcls) + obj.notClass() and value = objcls and cls = Types::class_get_meta_class(objcls) ) } @@ -1703,16 +1717,17 @@ module PointsTo { call = def.getCall() and var = def.getSourceVariable() and context.untrackableCall(call) and - exists(PyFunctionObject modifier | + exists(PyFunctionObject modifier, Function f | + f = modifier.getFunction() and call = get_a_call(modifier, context) and - not modifies_escaping_variable(modifier, var) + not modifies_escaping_variable(f, var) ) ) } - private predicate modifies_escaping_variable(FunctionObject modifier, PythonSsaSourceVariable var) { + private predicate modifies_escaping_variable(Function modifier, PythonSsaSourceVariable var) { exists(var.redefinedAtCallSite()) and - modifier.getFunction().getBody().contains(var.(Variable).getAStore()) + modifier.getBody().contains(var.(Variable).getAStore()) } pragma [noinline] @@ -2316,7 +2331,7 @@ module PointsTo { or cls = theObjectType() and result = 0 or - exists(builtin_base_type(cls)) and not cls = theObjectType() and result = 1 + exists(builtin_base_type(cls)) and cls != theObjectType() and result = 1 or cls = theUnknownType() and result = 1 } @@ -2472,7 +2487,7 @@ module PointsTo { /** INTERNAL -- Use `ClassObject.declaredAttribute(name). instead. */ cached predicate class_declared_attribute(ClassObject owner, string name, Object value, ClassObject vcls, ObjectOrCfg origin) { /* Note that src_var must be a local variable, we aren't interested in the value that any global variable may hold */ - not value = undefinedVariable() and + value != undefinedVariable() and exists(EssaVariable var, LocalVariable src_var | var.getSourceVariable() = src_var and src_var.getId() = name and @@ -2557,7 +2572,12 @@ module PointsTo { or exists(int i | failed_inference(class_base_type(cls, i), _) and reason = "Failed inference for base class at position " + i) or - exists(int i | strictcount(class_base_type(cls, i)) > 1 and reason = "Multiple bases at position " + i) + exists(int i, Object base1, Object base2 | + base1 = class_base_type(cls, i) and + base2 = class_base_type(cls, i) and + base1 != base2 and + reason = "Multiple bases at position " + i + ) or exists(int i, int j | class_base_type(cls, i) = class_base_type(cls, j) and i != j and reason = "Duplicate bases classes") or @@ -2577,7 +2597,7 @@ module PointsTo { private ClassObject declared_meta_class(ClassObject cls) { exists(Object obj | - ssa_variable_points_to(metaclass_var(cls), _, obj, _, _) | + ssa_variable_points_to(metaclass_var(cls.getPyClass()), _, obj, _, _) | result = obj or obj = unknownValue() and result = theUnknownType() @@ -2593,28 +2613,30 @@ module PointsTo { private boolean has_metaclass_var_metaclass(ClassObject cls) { exists(Object obj | - ssa_variable_points_to(metaclass_var(cls), _, obj, _, _) | + ssa_variable_points_to(metaclass_var(cls.getPyClass()), _, obj, _, _) | obj = undefinedVariable() and result = false or obj != undefinedVariable() and result = true ) or - not exists(metaclass_var(cls)) and result = false + exists(Class pycls | + pycls = cls.getPyClass() and + not exists(metaclass_var(pycls)) and result = false + ) } private boolean has_declared_metaclass(ClassObject cls) { py_cobjecttypes(cls, _) and result = true or - not cls.isBuiltin() and result = has_six_add_metaclass(cls).booleanOr(has_metaclass_var_metaclass(cls)) } - private EssaVariable metaclass_var(ClassObject cls) { - result.getASourceUse() = cls.getPyClass().getMetaClass().getAFlowNode() + private EssaVariable metaclass_var(Class cls) { + result.getASourceUse() = cls.getMetaClass().getAFlowNode() or - major_version() = 2 and not exists(cls.getPyClass().getMetaClass()) and + major_version() = 2 and not exists(cls.getMetaClass()) and result.getName() = "__metaclass__" and - cls.getPyClass().(ImportTimeScope).entryEdge(result.getAUse(), _) + cls.(ImportTimeScope).entryEdge(result.getAUse(), _) } private ClassObject get_inherited_metaclass(ClassObject cls) { @@ -2624,7 +2646,7 @@ module PointsTo { exists(Object base | base = class_base_type(cls, _) and result = theUnknownType() | - not base instanceof ClassObject + base.notClass() or base = theUnknownType() ) diff --git a/python/ql/src/semmle/python/types/ClassObject.qll b/python/ql/src/semmle/python/types/ClassObject.qll index 2aa5e9f4a92..255e5c7d99c 100644 --- a/python/ql/src/semmle/python/types/ClassObject.qll +++ b/python/ql/src/semmle/python/types/ClassObject.qll @@ -392,6 +392,10 @@ class ClassObject extends Object { result.getFunction().refersTo(this) } + predicate notClass() { + none() + } + } /** The 'str' class. This is the same as the 'bytes' class for diff --git a/python/ql/src/semmle/python/types/ModuleObject.qll b/python/ql/src/semmle/python/types/ModuleObject.qll index 0bfa5037488..f323bd3cff3 100644 --- a/python/ql/src/semmle/python/types/ModuleObject.qll +++ b/python/ql/src/semmle/python/types/ModuleObject.qll @@ -226,6 +226,14 @@ class PackageObject extends ModuleObject { result.getModule() = this.getModule().getInitModule() } + /** Holds if this package has no `__init__.py` file. */ + predicate hasNoInitModule() { + not exists(Module m | + m.isPackageInit() and + m.getFile().getParent() = this.getPath() + ) + } + override predicate exportsComplete() { not exists(this.getInitModule()) or diff --git a/python/ql/src/semmle/python/types/Object.qll b/python/ql/src/semmle/python/types/Object.qll index 10b569ed076..d4e9b2b7811 100644 --- a/python/ql/src/semmle/python/types/Object.qll +++ b/python/ql/src/semmle/python/types/Object.qll @@ -151,6 +151,14 @@ class Object extends @py_object { ) } + final predicate maybe() { + not exists(this.booleanValue()) + } + + predicate notClass() { + any() + } + /** Holds if this object can be referred to by `longName` * For example, the modules `dict` in the `sys` module * has the long name `sys.modules` and the name `os.path.join` From 28bea69882af6c656556e70c2e558f2027a2147e Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Mon, 21 Jan 2019 17:08:10 +0000 Subject: [PATCH 08/33] Python: ESSA definitions; make '*' special variable into its own class. --- python/ql/src/semmle/python/Variables.qll | 7 +++ .../semmle/python/dataflow/SsaDefinitions.qll | 59 ++++++++++++------- .../src/semmle/python/pointsto/PointsTo.qll | 4 +- 3 files changed, 47 insertions(+), 23 deletions(-) diff --git a/python/ql/src/semmle/python/Variables.qll b/python/ql/src/semmle/python/Variables.qll index 21ccc43b545..49f0f1aa4f1 100644 --- a/python/ql/src/semmle/python/Variables.qll +++ b/python/ql/src/semmle/python/Variables.qll @@ -4,6 +4,13 @@ import python /** A variable, either a global or local variable (including parameters) */ class Variable extends @py_variable { + Variable() { + exists(string name | + variable(this, _, name) and + not name = "*" and not name = "$" + ) + } + /** Gets the identifier (name) of this variable */ string getId() { variable(this, _, result) diff --git a/python/ql/src/semmle/python/dataflow/SsaDefinitions.qll b/python/ql/src/semmle/python/dataflow/SsaDefinitions.qll index ce80d74db3d..5210c9974bb 100644 --- a/python/ql/src/semmle/python/dataflow/SsaDefinitions.qll +++ b/python/ql/src/semmle/python/dataflow/SsaDefinitions.qll @@ -26,7 +26,11 @@ abstract class PythonSsaSourceVariable extends SsaSourceVariable { } override string getName() { - result = this.(Variable).getId() + variable(this, _, result) + } + + Scope getScope() { + variable(this, result, _) } abstract ControlFlowNode getAnImplicitUse(); @@ -46,7 +50,7 @@ abstract class PythonSsaSourceVariable extends SsaSourceVariable { /* Add a use at the end of scope for all variables to keep them live * This is necessary for taint-tracking. */ - result = this.(Variable).getScope().getANormalExit() + result = this.getScope().getANormalExit() } override predicate hasDefiningNode(ControlFlowNode def) { @@ -107,7 +111,6 @@ class FunctionLocalVariable extends PythonSsaSourceVariable { } override ControlFlowNode getScopeEntryDefinition() { - not this.(LocalVariable).getId() = "*" and exists(Scope s | s.getEntryNode() = result | s = this.(LocalVariable).getScope() and @@ -146,7 +149,6 @@ class NonLocalVariable extends PythonSsaSourceVariable { } override CallNode redefinedAtCallSite() { - not this.(LocalVariable).getId() = "*" and result.getScope().getScope*() = this.(LocalVariable).getScope() } @@ -163,7 +165,6 @@ class ClassLocalVariable extends PythonSsaSourceVariable { } override ControlFlowNode getScopeEntryDefinition() { - not this.(LocalVariable).getId() = "*" and result = this.(LocalVariable).getScope().getEntryNode() } @@ -235,7 +236,6 @@ class ModuleVariable extends PythonSsaSourceVariable { } override ControlFlowNode getScopeEntryDefinition() { - not this.(GlobalVariable).getId() = "*" and exists(Scope s | s.getEntryNode() = result | /* Module entry point */ @@ -253,13 +253,6 @@ class ModuleVariable extends PythonSsaSourceVariable { this = scope.getOuterVariable(_) or this.(Variable).getAUse().getScope() = scope ) - or - this.(GlobalVariable).getId() = "*" and - exists(Scope s | - s.getEntryNode() = result and - this.(Variable).getScope() = s and - exists(ImportStar is | is.getScope() = s) - ) } override CallNode redefinedAtCallSite() { none() } @@ -307,6 +300,29 @@ class EscapingGlobalVariable extends ModuleVariable { } +class SpecialSsaSourceVariable extends PythonSsaSourceVariable { + + SpecialSsaSourceVariable() { + variable(this, _, "*") or variable(this, _, "$") + } + + override ControlFlowNode getAnImplicitUse() { + exists(ImportTimeScope s | + result = s.getANormalExit() and this.getScope() = s + ) + } + + override ControlFlowNode getScopeEntryDefinition() { + /* Module entry point */ + this.getScope().getEntryNode() = result + } + + override CallNode redefinedAtCallSite() { + result.(CallNode).getScope().getScope*() = this.(GlobalVariable).getScope() + } + +} + private predicate variable_or_attribute_defined_out_of_scope(Variable v) { exists(NameNode n | n.defines(v) and not n.getScope() = v.getScope()) or @@ -330,7 +346,7 @@ cached module SsaSource { /** Holds if `v` is used as the receiver in a method call. */ cached predicate method_call_refinement(Variable v, ControlFlowNode use, CallNode call) { - use = v.getAUse() and + use = v.getAUse() and call.getFunction().(AttrNode).getObject() = use } @@ -387,16 +403,17 @@ cached module SsaSource { /** Holds if the name of `var` refers to a submodule of a package and `f` is the entry point * to the __init__ module of that package. */ - cached predicate init_module_submodule_defn(Variable var, ControlFlowNode f) { + cached predicate init_module_submodule_defn(PythonSsaSourceVariable var, ControlFlowNode f) { exists(Module init | - init.isPackageInit() and exists(init.getPackage().getSubModule(var.getId())) and - var instanceof GlobalVariable and init.getEntryNode() = f and - var.getScope() = init + init.isPackageInit() and exists(init.getPackage().getSubModule(var.getName())) and + init.getEntryNode() = f and + var.getScope() = init and + var instanceof GlobalVariable ) } /** Holds if the `v` is in scope at a `from import ... *` and may thus be redefined by that statement */ - cached predicate import_star_refinement(Variable v, ControlFlowNode use, ControlFlowNode def) { + cached predicate import_star_refinement(PythonSsaSourceVariable v, ControlFlowNode use, ControlFlowNode def) { use = def and def instanceof ImportStarNode and ( @@ -443,7 +460,7 @@ cached module SsaSource { } -private predicate refinement(Variable v, ControlFlowNode use, ControlFlowNode def) { +private predicate refinement(PythonSsaSourceVariable v, ControlFlowNode use, ControlFlowNode def) { SsaSource::import_star_refinement(v, use, def) or SsaSource::attribute_assignment_refinement(v, use, def) @@ -456,5 +473,5 @@ private predicate refinement(Variable v, ControlFlowNode use, ControlFlowNode de or SsaSource::method_call_refinement(v, use, def) or - def = v.(PythonSsaSourceVariable).redefinedAtCallSite() and def = use + def = v.redefinedAtCallSite() and def = use } diff --git a/python/ql/src/semmle/python/pointsto/PointsTo.qll b/python/ql/src/semmle/python/pointsto/PointsTo.qll index 06c7b8c2d85..365f061af30 100644 --- a/python/ql/src/semmle/python/pointsto/PointsTo.qll +++ b/python/ql/src/semmle/python/pointsto/PointsTo.qll @@ -119,7 +119,7 @@ module PointsTo { or exists(Module init | init = package.getInitModule().getModule() | - not exists(Variable v | v.getScope() = init | v.getId() = name or v.getId() = "*") + not exists(PythonSsaSourceVariable v | v.getScope() = init | v.getName() = name or v.getName() = "*") or exists(EssaVariable v, PointsToContext imp | v.getScope() = init and v.getName() = "*" and v.getAUse() = init.getANormalExit() | @@ -145,7 +145,7 @@ module PointsTo { or not exists(EssaVariable var | var.getAUse() = m.getANormalExit() and var.getSourceVariable().getName() = name) and exists(EssaVariable var, PointsToContext imp | - var.getAUse() = m.getANormalExit() and var.getSourceVariable().getName() = "*" | + var.getAUse() = m.getANormalExit() and var.getName() = "*" | SSA::ssa_variable_named_attribute_points_to(var, imp, name, obj, cls, origin) and imp.isImport() and not obj = undefinedVariable() ) From 21299493c964b4aaeff0caf423f9b9c2acd99c75 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Tue, 22 Jan 2019 11:02:36 +0000 Subject: [PATCH 09/33] Python tests: Hide special ESSA variables in tests, to ease transition from '*' to '$' variable. --- .../test/library-tests/PointsTo/new/Dataflow.expected | 6 ------ python/ql/test/library-tests/PointsTo/new/Dataflow.ql | 2 +- .../test/library-tests/PointsTo/new/SsaAttr.expected | 10 ---------- python/ql/test/library-tests/PointsTo/new/SsaAttr.ql | 2 +- .../test/library-tests/PointsTo/new/SsaUses.expected | 3 --- python/ql/test/library-tests/PointsTo/new/SsaUses.ql | 2 +- 6 files changed, 3 insertions(+), 22 deletions(-) diff --git a/python/ql/test/library-tests/PointsTo/new/Dataflow.expected b/python/ql/test/library-tests/PointsTo/new/Dataflow.expected index 502f88424c0..e0a751c4748 100644 --- a/python/ql/test/library-tests/PointsTo/new/Dataflow.expected +++ b/python/ql/test/library-tests/PointsTo/new/Dataflow.expected @@ -1,14 +1,11 @@ -| __init__.py:0 | *_0 = ScopeEntryDefinition | | __init__.py:0 | __name___0 = ScopeEntryDefinition | | __init__.py:0 | __package___0 = ScopeEntryDefinition | | __init__.py:0 | module2_0 = ImplicitSubModuleDefinition | | __init__.py:0 | moduleX_0 = ImplicitSubModuleDefinition | | __init__.py:0 | sys_0 = ScopeEntryDefinition | -| __init__.py:1 | *_1 = ImportStarRefinement(*_0) | | __init__.py:1 | __name___1 = ImportStarRefinement(__name___0) | | __init__.py:1 | __package___1 = ImportStarRefinement(__package___0) | | __init__.py:1 | sys_1 = ImportStarRefinement(sys_0) | -| __init__.py:2 | *_2 = ImportStarRefinement(*_1) | | __init__.py:2 | __name___2 = ImportStarRefinement(__name___1) | | __init__.py:2 | __package___2 = ImportStarRefinement(__package___1) | | __init__.py:2 | module_0 = ImportMember | @@ -498,7 +495,6 @@ | h_classes.py:52 | arg1_0 = ParameterDefinition | | h_classes.py:52 | n_0 = FunctionExpr | | h_classes.py:52 | self_0 = ParameterDefinition | -| i_imports.py:0 | *_0 = ScopeEntryDefinition | | i_imports.py:0 | BytesIO_0 = ScopeEntryDefinition | | i_imports.py:0 | StringIO_0 = ScopeEntryDefinition | | i_imports.py:0 | __name___0 = ScopeEntryDefinition | @@ -513,7 +509,6 @@ | i_imports.py:3 | a_0 = IntegerLiteral | | i_imports.py:4 | b_0 = IntegerLiteral | | i_imports.py:5 | c_0 = IntegerLiteral | -| i_imports.py:7 | *_1 = ImportStarRefinement(*_0) | | i_imports.py:7 | BytesIO_1 = ImportStarRefinement(BytesIO_0) | | i_imports.py:7 | StringIO_1 = ImportStarRefinement(StringIO_0) | | i_imports.py:7 | __name___1 = ImportStarRefinement(__name___0) | @@ -528,7 +523,6 @@ | i_imports.py:13 | argv_1 = ImportMember | | i_imports.py:17 | sys_1 = ImportExpr | | i_imports.py:23 | code_1 = ImportExpr | -| i_imports.py:27 | *_2 = ImportStarRefinement(*_1) | | i_imports.py:27 | __name___2 = ImportStarRefinement(__name___1) | | i_imports.py:27 | __package___2 = ImportStarRefinement(__package___1) | | i_imports.py:27 | a_2 = ImportStarRefinement(a_1) | diff --git a/python/ql/test/library-tests/PointsTo/new/Dataflow.ql b/python/ql/test/library-tests/PointsTo/new/Dataflow.ql index 1761c3bc4ab..c2ed05aa9dc 100755 --- a/python/ql/test/library-tests/PointsTo/new/Dataflow.ql +++ b/python/ql/test/library-tests/PointsTo/new/Dataflow.ql @@ -4,5 +4,5 @@ import python import Util from EssaVariable v, EssaDefinition def -where def = v.getDefinition() +where def = v.getDefinition() and not v.getSourceVariable() instanceof SpecialSsaSourceVariable select locate(def.getLocation(), "abdefghijknrs_"), v.getRepresentation() + " = " + def.getRepresentation() diff --git a/python/ql/test/library-tests/PointsTo/new/SsaAttr.expected b/python/ql/test/library-tests/PointsTo/new/SsaAttr.expected index f518b462be1..212abaab73d 100644 --- a/python/ql/test/library-tests/PointsTo/new/SsaAttr.expected +++ b/python/ql/test/library-tests/PointsTo/new/SsaAttr.expected @@ -37,16 +37,6 @@ | g_class_init.py:52 | self_3 | version | phi(self_1, self_2) | 'v2' | runtime | | g_class_init.py:52 | self_3 | version | phi(self_1, self_2) | 'v3' | runtime | | g_class_init.py:54 | self_1 | version | Pi(self_0) [true] | 'v2' | runtime | -| i_imports.py:7 | *_1 | x | ImportStarRefinement(*_0) | float 1.0 | import | -| i_imports.py:7 | *_1 | y | ImportStarRefinement(*_0) | float 2.0 | import | -| i_imports.py:27 | *_2 | module1 | ImportStarRefinement(*_1) | Module code.test_package.module1 | import | -| i_imports.py:27 | *_2 | module2 | ImportStarRefinement(*_1) | Module code.test_package.module2 | import | -| i_imports.py:27 | *_2 | p | ImportStarRefinement(*_1) | int 1 | import | -| i_imports.py:27 | *_2 | q | ImportStarRefinement(*_1) | int 2 | import | -| i_imports.py:27 | *_2 | r | ImportStarRefinement(*_1) | Dict | import | -| i_imports.py:27 | *_2 | s | ImportStarRefinement(*_1) | NoneType None | import | -| i_imports.py:27 | *_2 | x | ImportStarRefinement(*_1) | float 1.0 | import | -| i_imports.py:27 | *_2 | y | ImportStarRefinement(*_1) | float 2.0 | import | | k_getsetattr.py:6 | self_0 | a | ParameterDefinition | float 7.0 | code/k_getsetattr.py:15 from runtime | | k_getsetattr.py:6 | self_0 | c | ParameterDefinition | int 2 | code/k_getsetattr.py:15 from runtime | | k_getsetattr.py:7 | self_1 | a | ArgumentRefinement(self_0) | int 0 | code/k_getsetattr.py:15 from runtime | diff --git a/python/ql/test/library-tests/PointsTo/new/SsaAttr.ql b/python/ql/test/library-tests/PointsTo/new/SsaAttr.ql index 4a2fac535cf..2a44c56ab1f 100644 --- a/python/ql/test/library-tests/PointsTo/new/SsaAttr.ql +++ b/python/ql/test/library-tests/PointsTo/new/SsaAttr.ql @@ -5,7 +5,7 @@ private import semmle.python.pointsto.PointsToContext import Util from EssaVariable var, string name, Object o, PointsToContext ctx -where PointsTo::Test::ssa_variable_named_attribute_points_to(var, ctx, name, o, _, _) +where PointsTo::Test::ssa_variable_named_attribute_points_to(var, ctx, name, o, _, _) and not var.getSourceVariable() instanceof SpecialSsaSourceVariable select locate(var.getDefinition().getLocation(), "abdfgikm"), var.getRepresentation(), name, var.getDefinition().getRepresentation(), repr(o), ctx diff --git a/python/ql/test/library-tests/PointsTo/new/SsaUses.expected b/python/ql/test/library-tests/PointsTo/new/SsaUses.expected index aff87febe79..f8f4ad3a98b 100644 --- a/python/ql/test/library-tests/PointsTo/new/SsaUses.expected +++ b/python/ql/test/library-tests/PointsTo/new/SsaUses.expected @@ -1,4 +1,3 @@ -| __init__.py:0 | *_2 | Exit node for Module code.test_package.__init__ | | __init__.py:0 | __name___0 | Exit node for Module code.__init__ | | __init__.py:0 | __name___0 | Exit node for Module code.package.__init__ | | __init__.py:0 | __name___2 | Exit node for Module code.test_package.__init__ | @@ -12,11 +11,9 @@ | __init__.py:0 | moduleX_1 | Exit node for Module code.package.__init__ | | __init__.py:0 | module_0 | Exit node for Module code.package.__init__ | | __init__.py:0 | sys_2 | Exit node for Module code.test_package.__init__ | -| __init__.py:1 | *_0 | ControlFlowNode for from module1 import * | | __init__.py:1 | __name___0 | ControlFlowNode for from module1 import * | | __init__.py:1 | __package___0 | ControlFlowNode for from module1 import * | | __init__.py:1 | sys_0 | ControlFlowNode for from module1 import * | -| __init__.py:2 | *_1 | ControlFlowNode for from module2 import * | | __init__.py:2 | __name___1 | ControlFlowNode for from module2 import * | | __init__.py:2 | __package___1 | ControlFlowNode for from module2 import * | | __init__.py:2 | sys_1 | ControlFlowNode for from module2 import * | diff --git a/python/ql/test/library-tests/PointsTo/new/SsaUses.ql b/python/ql/test/library-tests/PointsTo/new/SsaUses.ql index 681ac79bc78..53d48cc36e1 100644 --- a/python/ql/test/library-tests/PointsTo/new/SsaUses.ql +++ b/python/ql/test/library-tests/PointsTo/new/SsaUses.ql @@ -5,5 +5,5 @@ import semmle.python.pointsto.PointsTo import Util from EssaVariable var, ControlFlowNode use -where use = var.getAUse() +where use = var.getAUse() and not var.getSourceVariable() instanceof SpecialSsaSourceVariable select locate(use.getLocation(), "abdeghjks_"), var.getRepresentation(), use.toString() From a3b5769c2ce5df07b03c87d37f4c9fa3e5804018 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Tue, 27 Nov 2018 16:41:39 +0000 Subject: [PATCH 10/33] Python: Weak file permissions query. --- change-notes/1.20/analysis-python.md | 1 + .../CWE-732/WeakFilePermissions.qhelp | 26 ++++++++++++ .../Security/CWE-732/WeakFilePermissions.ql | 42 +++++++++++++++++++ .../CWE-732/WeakFilePermissions.expected | 6 +++ .../CWE-732/WeakFilePermissions.qlref | 1 + .../test/query-tests/Security/CWE-732/options | 2 + .../test/query-tests/Security/CWE-732/test.py | 14 +++++++ .../query-tests/Security/lib/os/__init__.py | 3 ++ 8 files changed, 95 insertions(+) create mode 100644 python/ql/src/Security/CWE-732/WeakFilePermissions.qhelp create mode 100644 python/ql/src/Security/CWE-732/WeakFilePermissions.ql create mode 100644 python/ql/test/query-tests/Security/CWE-732/WeakFilePermissions.expected create mode 100644 python/ql/test/query-tests/Security/CWE-732/WeakFilePermissions.qlref create mode 100644 python/ql/test/query-tests/Security/CWE-732/options create mode 100644 python/ql/test/query-tests/Security/CWE-732/test.py diff --git a/change-notes/1.20/analysis-python.md b/change-notes/1.20/analysis-python.md index ca94dabe5da..415b2daf7c2 100644 --- a/change-notes/1.20/analysis-python.md +++ b/change-notes/1.20/analysis-python.md @@ -10,6 +10,7 @@ | **Query** | **Tags** | **Purpose** | |-----------------------------|-----------|--------------------------------------------------------------------| | Default version of SSL/TLS may be insecure (`py/insecure-default-protocol`) | security, external/cwe/cwe-327 | Finds instances where an insecure default protocol may be used. Results are shown on LGTM by default. | +| Overly permissive file permissions (`py/overly-permissive-file`) | security, external/cwe/cwe-732 | Finds instances where a file is created with overly permissive permissions. Results are not shown on LGTM by default. | | Use of insecure SSL/TLS version (`py/insecure-protocol`) | security, external/cwe/cwe-327 | Finds instances where a known insecure protocol has been specified. Results are shown on LGTM by default. | ## Changes to existing queries diff --git a/python/ql/src/Security/CWE-732/WeakFilePermissions.qhelp b/python/ql/src/Security/CWE-732/WeakFilePermissions.qhelp new file mode 100644 index 00000000000..92e3a57acbf --- /dev/null +++ b/python/ql/src/Security/CWE-732/WeakFilePermissions.qhelp @@ -0,0 +1,26 @@ + + + + +

    +When creating a file POSIX systems allow permissions to be specified +for owner, group and others separately. Permissions should be kept as +strict as possible, preventing access to the files contents by other users. +

    + +
    + + +

    +Restrict the file permissions of files to prevent any but the owner being able to read or write to that file +

    +
    + + +
  • +Wikipedia: +File system permissions. +
  • +
    + +
    diff --git a/python/ql/src/Security/CWE-732/WeakFilePermissions.ql b/python/ql/src/Security/CWE-732/WeakFilePermissions.ql new file mode 100644 index 00000000000..f02fc29df76 --- /dev/null +++ b/python/ql/src/Security/CWE-732/WeakFilePermissions.ql @@ -0,0 +1,42 @@ +/** + * @name Overly permissive file permissions + * @description Allowing files to be readable or writable by users other than the owner may allow sensitive information to be accessed. + * @kind problem + * @id py/overly-permissive-file + * @problem.severity warning + * @sub-severity high + * @precision medium + * @tags external/cwe/cwe-732 + * security + */ +import python + +bindingset[p] +int world_permission(int p) { + result = p % 8 +} + +bindingset[p] +int group_permission(int p) { + result = (p/8) % 8 +} + +bindingset[p] +string access(int p) { + p%4 >= 2 and result = "writable" or + p%4 < 2 and p != 0 and result = "readable" +} + +bindingset[p] +string permissive_permission(int p) { + result = "world " + access(world_permission(p)) + or + world_permission(p) = 0 and result = "group " + access(group_permission(p)) +} + +from FunctionObject chmod, CallNode call, NumericObject num, string permission +where + any(ModuleObject os | os.getName() = "os").getAttribute("chmod") = chmod and + chmod.getACall() = call and call.getArg(1).refersTo(num) and + permission = permissive_permission(num.intValue()) +select call, "Overly permissive mask in chmod sets file to " + permission + "." diff --git a/python/ql/test/query-tests/Security/CWE-732/WeakFilePermissions.expected b/python/ql/test/query-tests/Security/CWE-732/WeakFilePermissions.expected new file mode 100644 index 00000000000..c805dfd3f84 --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-732/WeakFilePermissions.expected @@ -0,0 +1,6 @@ +| test.py:7:1:7:19 | ControlFlowNode for Attribute() | Overly permissive mask in chmod sets file to world writable. | +| test.py:8:1:8:20 | ControlFlowNode for Attribute() | Overly permissive mask in chmod sets file to world writable. | +| test.py:9:1:9:21 | ControlFlowNode for Attribute() | Overly permissive mask in chmod sets file to world writable. | +| test.py:11:1:11:21 | ControlFlowNode for Attribute() | Overly permissive mask in chmod sets file to group readable. | +| test.py:13:1:13:28 | ControlFlowNode for Attribute() | Overly permissive mask in chmod sets file to group writable. | +| test.py:14:1:14:19 | ControlFlowNode for Attribute() | Overly permissive mask in chmod sets file to group writable. | diff --git a/python/ql/test/query-tests/Security/CWE-732/WeakFilePermissions.qlref b/python/ql/test/query-tests/Security/CWE-732/WeakFilePermissions.qlref new file mode 100644 index 00000000000..9e177187c49 --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-732/WeakFilePermissions.qlref @@ -0,0 +1 @@ +Security/CWE-732/WeakFilePermissions.ql diff --git a/python/ql/test/query-tests/Security/CWE-732/options b/python/ql/test/query-tests/Security/CWE-732/options new file mode 100644 index 00000000000..b63c517ee29 --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-732/options @@ -0,0 +1,2 @@ +semmle-extractor-options: --max-import-depth=2 -p ../lib +optimize: true diff --git a/python/ql/test/query-tests/Security/CWE-732/test.py b/python/ql/test/query-tests/Security/CWE-732/test.py new file mode 100644 index 00000000000..bf551afad5e --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-732/test.py @@ -0,0 +1,14 @@ +import os +import stat + +file = 'semmle/important_secrets' + + +os.chmod(file, 0o7) # BAD +os.chmod(file, 0o77) # BAD +os.chmod(file, 0o777) # BAD +os.chmod(file, 0o600) # GOOD +os.chmod(file, 0o550) # BAD +os.chmod(file, stat.S_IRWXU) # GOOD +os.chmod(file, stat.S_IWGRP) # BAD +os.chmod(file, 400) # BAD -- Decimal format. diff --git a/python/ql/test/query-tests/Security/lib/os/__init__.py b/python/ql/test/query-tests/Security/lib/os/__init__.py index 9cbc1f15559..a882369a42d 100644 --- a/python/ql/test/query-tests/Security/lib/os/__init__.py +++ b/python/ql/test/query-tests/Security/lib/os/__init__.py @@ -3,3 +3,6 @@ def system(cmd, *args, **kwargs): def popen(cmd, *args, **kwargs): return None + +def chmod(path, mode): + pass From fa02042fdaab92628b39f6da7017e07020233793 Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Wed, 23 Jan 2019 11:42:44 -0800 Subject: [PATCH 11/33] C++: add more tests and rename test functions --- .../FutileParams/FutileParams.expected | 6 ++--- .../Likely Typos/FutileParams/test.c | 27 +++++++++++++------ 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/FutileParams/FutileParams.expected b/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/FutileParams/FutileParams.expected index 7ba6f06b2e4..d6dc2222be4 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/FutileParams/FutileParams.expected +++ b/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/FutileParams/FutileParams.expected @@ -1,3 +1,3 @@ -| test.c:7:3:7:5 | call to foo | This call has arguments, but $@ is not declared with any parameters. | test.c:1:6:1:8 | foo | foo | -| test.c:13:3:13:19 | call to not_yet_declared1 | This call has arguments, but $@ is not declared with any parameters. | test.c:13:3:13:3 | not_yet_declared1 | not_yet_declared1 | -| test.c:13:3:13:19 | call to not_yet_declared1 | This call has arguments, but $@ is not declared with any parameters. | test.c:17:6:17:22 | not_yet_declared1 | not_yet_declared1 | +| test.c:8:3:8:16 | call to declared_empty | This call has arguments, but $@ is not declared with any parameters. | test.c:1:6:1:19 | declared_empty | declared_empty | +| test.c:14:3:14:19 | call to not_yet_declared1 | This call has arguments, but $@ is not declared with any parameters. | test.c:14:3:14:3 | not_yet_declared1 | not_yet_declared1 | +| test.c:14:3:14:19 | call to not_yet_declared1 | This call has arguments, but $@ is not declared with any parameters. | test.c:25:6:25:22 | not_yet_declared1 | not_yet_declared1 | diff --git a/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/FutileParams/test.c b/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/FutileParams/test.c index 67bb7726693..0f40e571416 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/FutileParams/test.c +++ b/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/FutileParams/test.c @@ -1,18 +1,29 @@ -void foo(); -void bar(void); -void baz(int); +void declared_empty(); +void declared_void(void); +void declared_with(int); +void declared_empty_defined_with(); void test() { - foo(); // GOOD - foo(1); // BAD - bar(); // GOOD - baz(1); // GOOD + declared_empty(); // GOOD + declared_empty(1); // BAD + declared_void(); // GOOD + declared_with(1); // GOOD undeclared(1); // GOOD not_yet_declared1(1); // BAD not_yet_declared2(1); // GOOD + + declared_empty_defined_with(); // BAD + declared_empty_defined_with(1); // GOOD + + int x; + declared_empty_defined_with(&x); // BAD + declared_empty_defined_with(x, x); // BAD } void not_yet_declared1(); -void not_yet_declared2(int); \ No newline at end of file +void not_yet_declared2(int); +void declared_empty_defined_with(int x) { + // do nothing +} From e1d31bf117463cf685ed9064b354e79b0a5970da Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri, 18 Jan 2019 13:16:34 +0000 Subject: [PATCH 12/33] CPP: Add a test of ArrayArgSizeMismatch.ql. --- .../ArrayArgSizeMismatch.expected | 2 + .../ArrayArgSizeMismatch.qlref | 1 + .../Conversion/ArrayArgSizeMismatch/test.cpp | 49 +++++++++++++++++++ 3 files changed, 52 insertions(+) create mode 100644 cpp/ql/test/query-tests/Likely Bugs/Conversion/ArrayArgSizeMismatch/ArrayArgSizeMismatch.expected create mode 100644 cpp/ql/test/query-tests/Likely Bugs/Conversion/ArrayArgSizeMismatch/ArrayArgSizeMismatch.qlref create mode 100644 cpp/ql/test/query-tests/Likely Bugs/Conversion/ArrayArgSizeMismatch/test.cpp diff --git a/cpp/ql/test/query-tests/Likely Bugs/Conversion/ArrayArgSizeMismatch/ArrayArgSizeMismatch.expected b/cpp/ql/test/query-tests/Likely Bugs/Conversion/ArrayArgSizeMismatch/ArrayArgSizeMismatch.expected new file mode 100644 index 00000000000..791527a7e56 --- /dev/null +++ b/cpp/ql/test/query-tests/Likely Bugs/Conversion/ArrayArgSizeMismatch/ArrayArgSizeMismatch.expected @@ -0,0 +1,2 @@ +| test.cpp:24:4:24:7 | arr3 | Array of size 3 passed to $@ which expects an array of size 4. | test.cpp:8:6:8:6 | g | g | +| test.cpp:40:9:40:12 | data | Array of size 0 passed to $@ which expects an array of size 4. | test.cpp:9:6:9:6 | h | h | diff --git a/cpp/ql/test/query-tests/Likely Bugs/Conversion/ArrayArgSizeMismatch/ArrayArgSizeMismatch.qlref b/cpp/ql/test/query-tests/Likely Bugs/Conversion/ArrayArgSizeMismatch/ArrayArgSizeMismatch.qlref new file mode 100644 index 00000000000..2e2747737a9 --- /dev/null +++ b/cpp/ql/test/query-tests/Likely Bugs/Conversion/ArrayArgSizeMismatch/ArrayArgSizeMismatch.qlref @@ -0,0 +1 @@ +Likely Bugs/Conversion/ArrayArgSizeMismatch.ql diff --git a/cpp/ql/test/query-tests/Likely Bugs/Conversion/ArrayArgSizeMismatch/test.cpp b/cpp/ql/test/query-tests/Likely Bugs/Conversion/ArrayArgSizeMismatch/test.cpp new file mode 100644 index 00000000000..10a355c490f --- /dev/null +++ b/cpp/ql/test/query-tests/Likely Bugs/Conversion/ArrayArgSizeMismatch/test.cpp @@ -0,0 +1,49 @@ + +typedef unsigned long size_t; +void *malloc(size_t size); + +#define NUM (4) + +void f(int *vs); +void g(int vs[4]); +void h(float fs[NUM]); + +struct myStruct +{ + unsigned int num; + float data[0]; +}; + +void test(float f3[3], float f4[4], float f5[5], float *fp) +{ + int arr3[3], arr4[4], arr5[5]; + + f(arr3); // GOOD + f(arr4); // GOOD + f(arr5); // GOOD + g(arr3); // BAD + g(arr4); // GOOD + g(arr5); // GOOD + + h(f3); // BAD [NOT DETECTED] + h(f4); // GOOD + h(f5); // GOOD + h(fp); // GOOD + + { + // variable size struct + myStruct *ms; + + ms = (myStruct *)malloc(sizeof(myStruct) + (4 * sizeof(float))); + ms->num = 4; + ms->data[0] = ms->data[1] = ms->data[2] = ms->data[3] = 0; + h(ms->data); // GOOD [FALSE POSITIVE] + } + + { + // char array + char ca[4 * sizeof(int)]; + + g((int *)ca); // GOOD + } +}; From 02c69a744fbacc13a2964fa1f9a37d8e2defa865 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 24 Jan 2019 11:33:50 +0000 Subject: [PATCH 13/33] CPP: Fix false positive. --- cpp/ql/src/Likely Bugs/Conversion/ArrayArgSizeMismatch.ql | 1 + .../ArrayArgSizeMismatch/ArrayArgSizeMismatch.expected | 1 - .../Likely Bugs/Conversion/ArrayArgSizeMismatch/test.cpp | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cpp/ql/src/Likely Bugs/Conversion/ArrayArgSizeMismatch.ql b/cpp/ql/src/Likely Bugs/Conversion/ArrayArgSizeMismatch.ql index 9cfa9315486..8b8aa74413d 100644 --- a/cpp/ql/src/Likely Bugs/Conversion/ArrayArgSizeMismatch.ql +++ b/cpp/ql/src/Likely Bugs/Conversion/ArrayArgSizeMismatch.ql @@ -17,6 +17,7 @@ where f = c.getTarget() and b = paramType.getArraySize() and argType.getBaseType().getSize() = paramType.getBaseType().getSize() and a < b and + a > 0 and // filter out results for inconsistent declarations strictcount(f.getParameter(i).getType().getSize()) = 1 select c.getArgument(i), "Array of size " + a + diff --git a/cpp/ql/test/query-tests/Likely Bugs/Conversion/ArrayArgSizeMismatch/ArrayArgSizeMismatch.expected b/cpp/ql/test/query-tests/Likely Bugs/Conversion/ArrayArgSizeMismatch/ArrayArgSizeMismatch.expected index 791527a7e56..d3e6062f627 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Conversion/ArrayArgSizeMismatch/ArrayArgSizeMismatch.expected +++ b/cpp/ql/test/query-tests/Likely Bugs/Conversion/ArrayArgSizeMismatch/ArrayArgSizeMismatch.expected @@ -1,2 +1 @@ | test.cpp:24:4:24:7 | arr3 | Array of size 3 passed to $@ which expects an array of size 4. | test.cpp:8:6:8:6 | g | g | -| test.cpp:40:9:40:12 | data | Array of size 0 passed to $@ which expects an array of size 4. | test.cpp:9:6:9:6 | h | h | diff --git a/cpp/ql/test/query-tests/Likely Bugs/Conversion/ArrayArgSizeMismatch/test.cpp b/cpp/ql/test/query-tests/Likely Bugs/Conversion/ArrayArgSizeMismatch/test.cpp index 10a355c490f..52b8f41bf22 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Conversion/ArrayArgSizeMismatch/test.cpp +++ b/cpp/ql/test/query-tests/Likely Bugs/Conversion/ArrayArgSizeMismatch/test.cpp @@ -37,7 +37,7 @@ void test(float f3[3], float f4[4], float f5[5], float *fp) ms = (myStruct *)malloc(sizeof(myStruct) + (4 * sizeof(float))); ms->num = 4; ms->data[0] = ms->data[1] = ms->data[2] = ms->data[3] = 0; - h(ms->data); // GOOD [FALSE POSITIVE] + h(ms->data); // GOOD } { From d04289084288cfca9200e8a1bd989e4ee451003d Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 24 Jan 2019 15:13:23 +0000 Subject: [PATCH 14/33] CPP: Assign a query precision. --- cpp/ql/src/Likely Bugs/Conversion/ArrayArgSizeMismatch.ql | 1 + 1 file changed, 1 insertion(+) diff --git a/cpp/ql/src/Likely Bugs/Conversion/ArrayArgSizeMismatch.ql b/cpp/ql/src/Likely Bugs/Conversion/ArrayArgSizeMismatch.ql index 8b8aa74413d..a055d383d55 100644 --- a/cpp/ql/src/Likely Bugs/Conversion/ArrayArgSizeMismatch.ql +++ b/cpp/ql/src/Likely Bugs/Conversion/ArrayArgSizeMismatch.ql @@ -5,6 +5,7 @@ * @kind problem * @id cpp/array-arg-size-mismatch * @problem.severity warning + * @precision medium * @tags reliability */ import cpp From 9bf084377621d1739e85d479e6ac279b492299fe Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 24 Jan 2019 11:38:44 +0000 Subject: [PATCH 15/33] CPP: Change note. --- change-notes/1.20/analysis-cpp.md | 1 + 1 file changed, 1 insertion(+) diff --git a/change-notes/1.20/analysis-cpp.md b/change-notes/1.20/analysis-cpp.md index 192ec3eca1b..cecf22563e5 100644 --- a/change-notes/1.20/analysis-cpp.md +++ b/change-notes/1.20/analysis-cpp.md @@ -14,6 +14,7 @@ | **Query** | **Expected impact** | **Change** | |----------------------------|------------------------|------------------------------------------------------------------| +| Array argument size mismatch | Fewer false positives | An exception has been added to this query for variable sized arrays. | | Suspicious add with sizeof (`cpp/suspicious-add-sizeof`) | Fewer false positives | Pointer arithmetic on `char * const` expressions (and other variations of `char *`) are now correctly excluded from the results. | | Suspicious pointer scaling (`cpp/suspicious-pointer-scaling`) | Fewer false positives | False positives involving types that are not uniquely named in the snapshot have been fixed. | | Lossy function result cast (`cpp/lossy-function-result-cast`) | Fewer false positive results | The whitelist of rounding functions built into this query has been expanded. | From 44d8e6b6e28ab08497dbaffa43985f75e91f9b19 Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Thu, 24 Jan 2019 10:50:56 -0800 Subject: [PATCH 16/33] C++: respond to PR comments --- cpp/ql/src/Likely Bugs/Likely Typos/FutileParams.qhelp | 5 +++++ .../Likely Bugs/Likely Typos/FutileParams/test.c | 6 +++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/cpp/ql/src/Likely Bugs/Likely Typos/FutileParams.qhelp b/cpp/ql/src/Likely Bugs/Likely Typos/FutileParams.qhelp index b5fdeeb7f31..0316bfdfa36 100644 --- a/cpp/ql/src/Likely Bugs/Likely Typos/FutileParams.qhelp +++ b/cpp/ql/src/Likely Bugs/Likely Typos/FutileParams.qhelp @@ -8,6 +8,11 @@

    A function is called with arguments despite having an empty parameter list. This may indicate that the incorrect function is being called, or that the author misunderstood the function.

    +

    In C, a function declared with an empty parameter list `()` is considered to have an unknown +parameter list, and therefore can be called with any set of arguments. To declare a function +which takes no arguments, you must use `(void)` as the parameter list in any forward declarations. +In C++, either style of declaration will be considered to take no arguments.

    +

    Call the function without arguments, or call a different function that expects the arguments diff --git a/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/FutileParams/test.c b/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/FutileParams/test.c index 0f40e571416..9589d2a9ffc 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/FutileParams/test.c +++ b/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/FutileParams/test.c @@ -14,12 +14,12 @@ void test() { not_yet_declared1(1); // BAD not_yet_declared2(1); // GOOD - declared_empty_defined_with(); // BAD + declared_empty_defined_with(); // BAD [NOT DETECTED] declared_empty_defined_with(1); // GOOD int x; - declared_empty_defined_with(&x); // BAD - declared_empty_defined_with(x, x); // BAD + declared_empty_defined_with(&x); // BAD [NOT DETECTED] + declared_empty_defined_with(x, x); // BAD [NOT DETECTED] } void not_yet_declared1(); From 078becc57bb258fba3c87fd21cc4c781a3810d22 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Fri, 25 Jan 2019 12:06:34 +0100 Subject: [PATCH 17/33] C#: Address review comments --- .../semmle/code/csharp/dataflow/DataFlow.qll | 30 +++++++++++-------- .../code/csharp/dataflow/TaintTracking.qll | 9 +++--- 2 files changed, 21 insertions(+), 18 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/DataFlow.qll b/csharp/ql/src/semmle/code/csharp/dataflow/DataFlow.qll index 1d4cd002ebe..b8acdf28275 100755 --- a/csharp/ql/src/semmle/code/csharp/dataflow/DataFlow.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/DataFlow.qll @@ -731,9 +731,9 @@ module DataFlow { * A helper class for defining expression-based data flow steps, while properly * taking control flow into account. */ - abstract class ExprStep extends string { + abstract class ExprStepConfiguration extends string { bindingset[this] - ExprStep() { any() } + ExprStepConfiguration() { any() } /** * Holds if data can flow from expression `exprFrom` to expression `exprTo`, @@ -841,15 +841,14 @@ module DataFlow { /** Provides predicates related to local data flow. */ module LocalFlow { - private class LocalExprStep extends ExprStep { - LocalExprStep() { this = "LocalExprStep" } + private class LocalExprStepConfiguration extends ExprStepConfiguration { + LocalExprStepConfiguration() { this = "LocalExprStepConfiguration" } override predicate stepsToExpr(Expr exprFrom, Expr exprTo, ControlFlowElement scope, boolean exactScope, boolean isSuccessor) { exactScope = false and ( // Flow using library code - libraryFlow(exprFrom, exprTo, scope, true) and - (isSuccessor = false or isSuccessor = true) + libraryFlow(exprFrom, exprTo, scope, isSuccessor, true) or exprFrom = exprTo.(ParenthesizedExpr).getExpr() and scope = exprTo and @@ -911,7 +910,7 @@ module DataFlow { predicate step(Node nodeFrom, Node nodeTo) { forceCachingInSameStage() and TaintTracking::Internal::Cached::forceCachingInSameStage() and - any(LocalExprStep x).hasStep(nodeFrom, nodeTo) + any(LocalExprStepConfiguration x).hasStep(nodeFrom, nodeTo) or // Flow from SSA definition to first read exists(Ssa::Definition def, ControlFlow::Node cfn | @@ -1008,9 +1007,14 @@ module DataFlow { ) } - predicate libraryFlow(Expr exprFrom, Expr exprTo, Expr scope, boolean preservesValue) { + predicate libraryFlow(Expr exprFrom, Expr exprTo, Expr scope, boolean isSuccessor, boolean preservesValue) { + // To not pollute the definitions in `LibraryTypeDataFlow.qll` with syntactic scope, + // simply use the nearest common parent expression for `exprFrom` and `exprTo` scope = getALibraryFlowParent(exprFrom, exprTo, preservesValue) and - scope.getAChildExpr*() = exprTo + scope.getAChildExpr*() = exprTo and + // Similarly, for simplicity allow following both forwards and backwards edges from + // `exprFrom` to `exprTo` + (isSuccessor = true or isSuccessor = false) } predicate localFlowStepNoConfig(Node pred, Node succ) { @@ -1828,9 +1832,9 @@ module DataFlow { flowsink.getNode() = sink } - private class FlowThroughCallableLibraryOutRefStep extends ExprStep { - FlowThroughCallableLibraryOutRefStep() { - this = "FlowThroughCallableLibraryOutRefStep" + private class FlowThroughCallableLibraryOutRefStepConfiguration extends ExprStepConfiguration { + FlowThroughCallableLibraryOutRefStepConfiguration() { + this = "FlowThroughCallableLibraryOutRefStepConfiguration" } override predicate stepsToDefinition(Expr exprFrom, AssignableDefinition defTo, ControlFlowElement scope, boolean exactScope, boolean isSuccessor) { @@ -1860,7 +1864,7 @@ module DataFlow { */ predicate flowThroughCallableLibraryOutRef(MethodCall mc, ExprNode arg, SsaDefinitionNode node, boolean preservesValue) { libraryFlowOutRef(mc, arg.getExpr(), _, preservesValue) and - any(FlowThroughCallableLibraryOutRefStep x).hasStep(arg, node) + any(FlowThroughCallableLibraryOutRefStepConfiguration x).hasStep(arg, node) } /** diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/TaintTracking.qll b/csharp/ql/src/semmle/code/csharp/dataflow/TaintTracking.qll index 7229b49ab1d..7959bd07cb6 100755 --- a/csharp/ql/src/semmle/code/csharp/dataflow/TaintTracking.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/TaintTracking.qll @@ -130,15 +130,14 @@ module TaintTracking { result = ea.getQualifier() } - private class LocalTaintExprStep extends DataFlow::Internal::ExprStep { - LocalTaintExprStep() { this = "LocalTaintExprStep" } + private class LocalTaintExprStepConfiguration extends DataFlow::Internal::ExprStepConfiguration { + LocalTaintExprStepConfiguration() { this = "LocalTaintExprStepConfiguration" } override predicate stepsToExpr(Expr exprFrom, Expr exprTo, ControlFlowElement scope, boolean exactScope, boolean isSuccessor) { exactScope = false and ( // Taint propagation using library code - DataFlow::Internal::LocalFlow::libraryFlow(exprFrom, exprTo, scope, false) and - (isSuccessor = false or isSuccessor = true) + DataFlow::Internal::LocalFlow::libraryFlow(exprFrom, exprTo, scope, isSuccessor, false) or // Taint from assigned value to element qualifier (`x[i] = 0`) exists(AssignExpr ae | @@ -232,7 +231,7 @@ module TaintTracking { cached predicate localAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { DataFlow::Internal::Cached::forceCachingInSameStage() and - any(LocalTaintExprStep x).hasStep(nodeFrom, nodeTo) + any(LocalTaintExprStepConfiguration x).hasStep(nodeFrom, nodeTo) or DataFlow::Internal::flowOutOfDelegateLibraryCall(nodeFrom, nodeTo, false) or From ed8112a5389aaf628b8552f349e05f4c7b238193 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Fri, 25 Jan 2019 15:24:55 +0100 Subject: [PATCH 18/33] C#: Cleanup dotnet install script after installation in autobuilder --- .../Semmle.Autobuild.Tests/BuildScripts.cs | 9 ++++++--- csharp/autobuilder/Semmle.Autobuild/DotNetRule.cs | 13 +++++++++++-- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/csharp/autobuilder/Semmle.Autobuild.Tests/BuildScripts.cs b/csharp/autobuilder/Semmle.Autobuild.Tests/BuildScripts.cs index 2b655310e09..de22028fd96 100644 --- a/csharp/autobuilder/Semmle.Autobuild.Tests/BuildScripts.cs +++ b/csharp/autobuilder/Semmle.Autobuild.Tests/BuildScripts.cs @@ -855,6 +855,7 @@ namespace Semmle.Extraction.Tests Actions.RunProcess[@"curl -sO https://dot.net/v1/dotnet-install.sh"] = 0; Actions.RunProcess[@"chmod u+x dotnet-install.sh"] = 0; Actions.RunProcess[@"./dotnet-install.sh --channel release --version 2.1.3 --install-dir C:\Project/.dotnet"] = 0; + Actions.RunProcess[@"rm dotnet-install.sh"] = 0; Actions.RunProcess[@"C:\Project/.dotnet/dotnet --info"] = 0; Actions.RunProcess[@"C:\Project/.dotnet/dotnet clean test.csproj"] = 0; Actions.RunProcess[@"C:\Project/.dotnet/dotnet restore test.csproj"] = 0; @@ -879,7 +880,7 @@ namespace Semmle.Extraction.Tests Actions.LoadXml["test.csproj"] = xml; var autobuilder = CreateAutoBuilder("csharp", false, dotnetVersion: "2.1.3"); - TestAutobuilderScript(autobuilder, 0, 10); + TestAutobuilderScript(autobuilder, 0, 11); } [Fact] @@ -890,6 +891,7 @@ namespace Semmle.Extraction.Tests Actions.RunProcess[@"curl -sO https://dot.net/v1/dotnet-install.sh"] = 0; Actions.RunProcess[@"chmod u+x dotnet-install.sh"] = 0; Actions.RunProcess[@"./dotnet-install.sh --channel release --version 2.1.3 --install-dir C:\Project/.dotnet"] = 0; + Actions.RunProcess[@"rm dotnet-install.sh"] = 0; Actions.RunProcess[@"C:\Project/.dotnet/dotnet --info"] = 0; Actions.RunProcess[@"C:\Project/.dotnet/dotnet clean test.csproj"] = 0; Actions.RunProcess[@"C:\Project/.dotnet/dotnet restore test.csproj"] = 0; @@ -914,7 +916,7 @@ namespace Semmle.Extraction.Tests Actions.LoadXml["test.csproj"] = xml; var autobuilder = CreateAutoBuilder("csharp", false, dotnetVersion: "2.1.3"); - TestAutobuilderScript(autobuilder, 0, 10); + TestAutobuilderScript(autobuilder, 0, 11); } [Fact] @@ -923,6 +925,7 @@ namespace Semmle.Extraction.Tests Actions.RunProcess["cmd.exe /C dotnet --list-sdks"] = 0; Actions.RunProcessOut["cmd.exe /C dotnet --list-sdks"] = "2.1.3 [C:\\Program Files\\dotnet\\sdks]\n2.1.4 [C:\\Program Files\\dotnet\\sdks]"; Actions.RunProcess[@"cmd.exe /C powershell -NoProfile -ExecutionPolicy unrestricted -file C:\Project\install-dotnet.ps1 -Version 2.1.3 -InstallDir C:\Project\.dotnet"] = 0; + Actions.RunProcess[@"cmd.exe /C del C:\Project\install-dotnet.ps1"] = 0; Actions.RunProcess[@"cmd.exe /C C:\Project\.dotnet\dotnet --info"] = 0; Actions.RunProcess[@"cmd.exe /C C:\Project\.dotnet\dotnet clean test.csproj"] = 0; Actions.RunProcess[@"cmd.exe /C C:\Project\.dotnet\dotnet restore test.csproj"] = 0; @@ -947,7 +950,7 @@ namespace Semmle.Extraction.Tests Actions.LoadXml["test.csproj"] = xml; var autobuilder = CreateAutoBuilder("csharp", true, dotnetVersion: "2.1.3"); - TestAutobuilderScript(autobuilder, 0, 8); + TestAutobuilderScript(autobuilder, 0, 9); } [Fact] diff --git a/csharp/autobuilder/Semmle.Autobuild/DotNetRule.cs b/csharp/autobuilder/Semmle.Autobuild/DotNetRule.cs index 9cce54ab50e..f3e95921a44 100644 --- a/csharp/autobuilder/Semmle.Autobuild/DotNetRule.cs +++ b/csharp/autobuilder/Semmle.Autobuild/DotNetRule.cs @@ -185,7 +185,12 @@ Invoke-Command -ScriptBlock $ScriptBlock"; Argument(version). Argument("-InstallDir"). Argument(path); - return install.Script; + + var removeScript = new CommandBuilder(builder.Actions). + RunCommand("del"). + Argument(psScriptFile); + + return install.Script & BuildScript.Try(removeScript.Script); } else { @@ -208,7 +213,11 @@ Invoke-Command -ScriptBlock $ScriptBlock"; Argument("--install-dir"). Argument(path); - return curl.Script & chmod.Script & install.Script; + var removeScript = new CommandBuilder(builder.Actions). + RunCommand("rm"). + Argument("dotnet-install.sh"); + + return curl.Script & chmod.Script & install.Script & BuildScript.Try(removeScript.Script); } }); } From f98abd6bf8cc6c852417c56617b271bcccb60905 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri, 25 Jan 2019 14:41:07 +0000 Subject: [PATCH 19/33] CPP: Add query ID to change note. --- change-notes/1.20/analysis-cpp.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/change-notes/1.20/analysis-cpp.md b/change-notes/1.20/analysis-cpp.md index cecf22563e5..f3f7b91a603 100644 --- a/change-notes/1.20/analysis-cpp.md +++ b/change-notes/1.20/analysis-cpp.md @@ -14,7 +14,7 @@ | **Query** | **Expected impact** | **Change** | |----------------------------|------------------------|------------------------------------------------------------------| -| Array argument size mismatch | Fewer false positives | An exception has been added to this query for variable sized arrays. | +| Array argument size mismatch (`cpp/array-arg-size-mismatch`) | Fewer false positives | An exception has been added to this query for variable sized arrays. | | Suspicious add with sizeof (`cpp/suspicious-add-sizeof`) | Fewer false positives | Pointer arithmetic on `char * const` expressions (and other variations of `char *`) are now correctly excluded from the results. | | Suspicious pointer scaling (`cpp/suspicious-pointer-scaling`) | Fewer false positives | False positives involving types that are not uniquely named in the snapshot have been fixed. | | Lossy function result cast (`cpp/lossy-function-result-cast`) | Fewer false positive results | The whitelist of rounding functions built into this query has been expanded. | From c527f9c90ca0a6acfd1028b4fb2c0729196dda3f Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri, 25 Jan 2019 16:38:25 +0000 Subject: [PATCH 20/33] CPP: Upgrade precision to high. --- cpp/ql/src/Likely Bugs/Conversion/ArrayArgSizeMismatch.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/src/Likely Bugs/Conversion/ArrayArgSizeMismatch.ql b/cpp/ql/src/Likely Bugs/Conversion/ArrayArgSizeMismatch.ql index a055d383d55..a728ed1426f 100644 --- a/cpp/ql/src/Likely Bugs/Conversion/ArrayArgSizeMismatch.ql +++ b/cpp/ql/src/Likely Bugs/Conversion/ArrayArgSizeMismatch.ql @@ -5,7 +5,7 @@ * @kind problem * @id cpp/array-arg-size-mismatch * @problem.severity warning - * @precision medium + * @precision high * @tags reliability */ import cpp From 98ba308207040a0907ef8364d8d46b2dfb0831af Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri, 25 Jan 2019 16:40:11 +0000 Subject: [PATCH 21/33] CPP: Use memberMayBeVarSize. --- cpp/ql/src/Likely Bugs/Conversion/ArrayArgSizeMismatch.ql | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cpp/ql/src/Likely Bugs/Conversion/ArrayArgSizeMismatch.ql b/cpp/ql/src/Likely Bugs/Conversion/ArrayArgSizeMismatch.ql index a728ed1426f..af258c03b9f 100644 --- a/cpp/ql/src/Likely Bugs/Conversion/ArrayArgSizeMismatch.ql +++ b/cpp/ql/src/Likely Bugs/Conversion/ArrayArgSizeMismatch.ql @@ -9,6 +9,7 @@ * @tags reliability */ import cpp +import semmle.code.cpp.commons.Buffer from Function f, FunctionCall c, int i, ArrayType argType, ArrayType paramType, int a, int b where f = c.getTarget() and @@ -18,7 +19,7 @@ where f = c.getTarget() and b = paramType.getArraySize() and argType.getBaseType().getSize() = paramType.getBaseType().getSize() and a < b and - a > 0 and + not memberMayBeVarSize(_, c.getArgument(i).(VariableAccess).getTarget()) and // filter out results for inconsistent declarations strictcount(f.getParameter(i).getType().getSize()) = 1 select c.getArgument(i), "Array of size " + a + From ef3b107cc118ac69b08ce03ada19f798a822e8b2 Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen Date: Thu, 24 Jan 2019 14:58:15 +0100 Subject: [PATCH 22/33] JS: sharpen the js/trivial-conditional whitelist --- change-notes/1.20/analysis-javascript.md | 1 + .../ql/src/Statements/UselessConditional.ql | 23 +++++++++----- .../UselessConditional.expected | 3 ++ .../UselessConditional/UselessConditional.js | 31 +++++++++++++++++++ 4 files changed, 50 insertions(+), 8 deletions(-) diff --git a/change-notes/1.20/analysis-javascript.md b/change-notes/1.20/analysis-javascript.md index 30874ce9c51..376098a07a6 100644 --- a/change-notes/1.20/analysis-javascript.md +++ b/change-notes/1.20/analysis-javascript.md @@ -35,6 +35,7 @@ | Useless assignment to property. | Fewer false-positive results | This rule now treats assignments with complex right-hand sides correctly. | | Unsafe dynamic method access | Fewer false-positive results | This rule no longer flags concatenated strings as unsafe method names. | | Unvalidated dynamic method call | More true-positive results | This rule now flags concatenated strings as unvalidated method names in more cases. | +| Useless conditional | More true-positive results | More true-positive results | This rule now flags additional uses of function call values. | ## Changes to QL libraries diff --git a/javascript/ql/src/Statements/UselessConditional.ql b/javascript/ql/src/Statements/UselessConditional.ql index 0afdfa9f51e..115f16ef126 100644 --- a/javascript/ql/src/Statements/UselessConditional.ql +++ b/javascript/ql/src/Statements/UselessConditional.ql @@ -65,17 +65,24 @@ predicate isInitialParameterUse(Expr e) { } /** - * Holds if `e` directly uses the returned value from a function call that returns a constant boolean value. + * Holds if `e` directly uses the returned value from functions that return constant boolean values. */ predicate isConstantBooleanReturnValue(Expr e) { // unlike `SourceNode.flowsTo` this will not include uses we have refinement information for - exists(DataFlow::CallNode call | exists(call.analyze().getTheBooleanValue()) | - e = call.asExpr() - or - // also support return values that are assigned to variables - exists(SsaExplicitDefinition ssa | - ssa.getDef().getSource() = call.asExpr() and - ssa.getVariable().getAUse() = e + exists(string b | (b = "true" or b = "false") | + forex(DataFlow::CallNode call, Expr ret | + ret = call.getACallee().getAReturnedExpr() and + ( + e = call.asExpr() + or + // also support return values that are assigned to variables + exists(SsaExplicitDefinition ssa | + ssa.getDef().getSource() = call.asExpr() and + ssa.getVariable().getAUse() = e + ) + ) + | + ret.(BooleanLiteral).getValue() = b ) ) or diff --git a/javascript/ql/test/query-tests/Statements/UselessConditional/UselessConditional.expected b/javascript/ql/test/query-tests/Statements/UselessConditional/UselessConditional.expected index b0d95f08153..5de81fba4b8 100644 --- a/javascript/ql/test/query-tests/Statements/UselessConditional/UselessConditional.expected +++ b/javascript/ql/test/query-tests/Statements/UselessConditional/UselessConditional.expected @@ -22,6 +22,9 @@ | UselessConditional.js:102:19:102:19 | x | This use of variable 'x' always evaluates to false. | | UselessConditional.js:103:23:103:23 | x | This use of variable 'x' always evaluates to false. | | UselessConditional.js:109:15:109:16 | {} | This expression always evaluates to true. | +| UselessConditional.js:129:6:129:24 | constantUndefined() | This call to constantUndefined always evaluates to false. | +| UselessConditional.js:135:6:135:32 | constan ... ined1() | This call to constantFalseOrUndefined1 always evaluates to false. | +| UselessConditional.js:139:6:139:32 | constan ... ined2() | This call to constantFalseOrUndefined2 always evaluates to false. | | UselessConditionalGood.js:58:12:58:13 | x2 | This use of variable 'x2' always evaluates to false. | | UselessConditionalGood.js:69:12:69:13 | xy | This use of variable 'xy' always evaluates to false. | | UselessConditionalGood.js:85:12:85:13 | xy | This use of variable 'xy' always evaluates to false. | diff --git a/javascript/ql/test/query-tests/Statements/UselessConditional/UselessConditional.js b/javascript/ql/test/query-tests/Statements/UselessConditional/UselessConditional.js index ca0e5d19af9..f58152bf240 100644 --- a/javascript/ql/test/query-tests/Statements/UselessConditional/UselessConditional.js +++ b/javascript/ql/test/query-tests/Statements/UselessConditional/UselessConditional.js @@ -109,4 +109,35 @@ async function awaitFlow(){ if ((x && {}) || y) {} // NOT OK }); +(function(){ + function constantFalse1() { + return false; + } + if (constantFalse1()) // OK + return; + + function constantFalse2() { + return false; + } + let constantFalse = unknown? constantFalse1 : constantFalse2; + if (constantFalse2()) // OK + return; + + function constantUndefined() { + return undefined; + } + if (constantUndefined()) // NOT OK + return; + + function constantFalseOrUndefined1() { + return unknown? false: undefined; + } + if (constantFalseOrUndefined1()) // NOT OK + return; + + let constantFalseOrUndefined2 = unknown? constantFalse1 : constantUndefined; + if (constantFalseOrUndefined2()) // NOT OK + return; + +}); // semmle-extractor-options: --experimental From 239fe6e4191d005007e8cb41dc22538f8538e80d Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen Date: Mon, 28 Jan 2019 10:18:03 +0100 Subject: [PATCH 23/33] fixup! JS: sharpen the js/trivial-conditional whitelist --- change-notes/1.20/analysis-javascript.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/change-notes/1.20/analysis-javascript.md b/change-notes/1.20/analysis-javascript.md index 376098a07a6..03730a64c9a 100644 --- a/change-notes/1.20/analysis-javascript.md +++ b/change-notes/1.20/analysis-javascript.md @@ -35,7 +35,7 @@ | Useless assignment to property. | Fewer false-positive results | This rule now treats assignments with complex right-hand sides correctly. | | Unsafe dynamic method access | Fewer false-positive results | This rule no longer flags concatenated strings as unsafe method names. | | Unvalidated dynamic method call | More true-positive results | This rule now flags concatenated strings as unvalidated method names in more cases. | -| Useless conditional | More true-positive results | More true-positive results | This rule now flags additional uses of function call values. | +| Useless conditional | More true-positive results | This rule now flags additional uses of function call values. | ## Changes to QL libraries From bf7cdad7366fcbeeac94ecc8910fcb3f50ffda44 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 28 Jan 2019 09:31:06 +0000 Subject: [PATCH 24/33] CPP: Change note. --- change-notes/1.20/analysis-cpp.md | 1 + 1 file changed, 1 insertion(+) diff --git a/change-notes/1.20/analysis-cpp.md b/change-notes/1.20/analysis-cpp.md index f3f7b91a603..732aa86f78e 100644 --- a/change-notes/1.20/analysis-cpp.md +++ b/change-notes/1.20/analysis-cpp.md @@ -9,6 +9,7 @@ | **Query** | **Tags** | **Purpose** | |-----------------------------|-----------|--------------------------------------------------------------------| | Lossy function result cast (`cpp/lossy-function-result-cast`) | correctness | Finds function calls whose result type is a floating point type, which are implicitly cast to an integral type. Newly available but not displayed by default on LGTM. | +| Array argument size mismatch (`cpp/array-arg-size-mismatch`) | reliability | Finds function calls where the size of an array being passed is smaller than the array size of the declared parameter. Newly displayed on LGTM. | ## Changes to existing queries From b841ecbb7c9f9f2b92fb5767385bbdf3620e7b98 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Wed, 23 Jan 2019 15:24:58 +0000 Subject: [PATCH 25/33] Python: Fix tornado and twisted request attribute tracking; 'path' attribute can be trusted, but 'uri' and 'arguments' cannot. --- python/ql/src/semmle/python/web/tornado/Request.qll | 10 ++++++++-- python/ql/src/semmle/python/web/twisted/Request.qll | 3 +-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/python/ql/src/semmle/python/web/tornado/Request.qll b/python/ql/src/semmle/python/web/tornado/Request.qll index bc28dba114d..ae19730e26e 100644 --- a/python/ql/src/semmle/python/web/tornado/Request.qll +++ b/python/ql/src/semmle/python/web/tornado/Request.qll @@ -15,16 +15,22 @@ class TornadoRequest extends TaintKind { result instanceof ExternalStringDictKind and ( name = "headers" or - name = "arguments" or name = "cookies" ) or result instanceof ExternalStringKind and ( - name = "path" or + name = "uri" or name = "query" or name = "body" ) + or + result instanceof ExternalStringSequenceDictKind and + ( + name = "arguments" or + name = "query_arguments" or + name = "body_arguments" + ) } } diff --git a/python/ql/src/semmle/python/web/twisted/Request.qll b/python/ql/src/semmle/python/web/twisted/Request.qll index 8be5db7bb4d..287a33ab1fe 100644 --- a/python/ql/src/semmle/python/web/twisted/Request.qll +++ b/python/ql/src/semmle/python/web/twisted/Request.qll @@ -19,8 +19,7 @@ class TwistedRequest extends TaintKind { or result instanceof ExternalStringKind and ( - name = "uri" or - name = "path" + name = "uri" ) } From 1bec21904821c3695bc10ded7d995664620f04f9 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Mon, 28 Jan 2019 11:41:12 +0000 Subject: [PATCH 26/33] Python: Remove AST test (it will be added to the extractor tests). --- .../ql/test/library-tests/ast/Child.expected | 257 ------------------ python/ql/test/library-tests/ast/Child.ql | 7 - python/ql/test/library-tests/ast/test.py | 94 ------- 3 files changed, 358 deletions(-) delete mode 100644 python/ql/test/library-tests/ast/Child.expected delete mode 100644 python/ql/test/library-tests/ast/Child.ql delete mode 100644 python/ql/test/library-tests/ast/test.py diff --git a/python/ql/test/library-tests/ast/Child.expected b/python/ql/test/library-tests/ast/Child.expected deleted file mode 100644 index afcceb30240..00000000000 --- a/python/ql/test/library-tests/ast/Child.expected +++ /dev/null @@ -1,257 +0,0 @@ -| test.py:0:0 | Module test | test.py:5:1 | ClassDef | -| test.py:0:0 | Module test | test.py:11:1 | FunctionDef | -| test.py:0:0 | Module test | test.py:14:1 | FunctionDef | -| test.py:0:0 | Module test | test.py:17:1 | FunctionDef | -| test.py:0:0 | Module test | test.py:51:1 | FunctionDef | -| test.py:2:2 | deco1() | test.py:2:2 | deco1 | -| test.py:2:2 | deco1() | test.py:3:1 | deco2()() | -| test.py:3:1 | deco2() | test.py:3:2 | deco2 | -| test.py:3:1 | deco2()() | test.py:3:1 | deco2() | -| test.py:3:1 | deco2()() | test.py:4:2 | Attribute() | -| test.py:4:2 | Attribute | test.py:4:2 | Attribute | -| test.py:4:2 | Attribute | test.py:4:2 | deco3 | -| test.py:4:2 | Attribute() | test.py:4:2 | Attribute | -| test.py:4:2 | Attribute() | test.py:5:1 | ClassExpr | -| test.py:5:1 | Class C | test.py:7:5 | FunctionDef | -| test.py:5:1 | ClassDef | test.py:2:2 | deco1() | -| test.py:5:1 | ClassDef | test.py:5:7 | C | -| test.py:5:1 | ClassExpr | test.py:5:1 | Class C | -| test.py:5:1 | ClassExpr | test.py:5:9 | Base | -| test.py:7:5 | Function __init__ | test.py:7:18 | self | -| test.py:7:5 | Function __init__ | test.py:8:9 | Pass | -| test.py:7:5 | FunctionDef | test.py:7:5 | FunctionExpr | -| test.py:7:5 | FunctionDef | test.py:7:9 | __init__ | -| test.py:7:5 | FunctionExpr | test.py:7:5 | Function __init__ | -| test.py:10:1 | Attribute() | test.py:10:2 | Attribute | -| test.py:10:1 | Attribute()() | test.py:10:1 | Attribute() | -| test.py:10:1 | Attribute()() | test.py:11:1 | FunctionExpr | -| test.py:10:2 | Attribute | test.py:10:2 | deco4 | -| test.py:11:1 | Function f | test.py:12:5 | Pass | -| test.py:11:1 | FunctionDef | test.py:10:1 | Attribute()() | -| test.py:11:1 | FunctionDef | test.py:11:5 | f | -| test.py:11:1 | FunctionExpr | test.py:11:1 | Function f | -| test.py:14:1 | Function f | test.py:14:7 | pos0 | -| test.py:14:1 | Function f | test.py:14:13 | pos1 | -| test.py:14:1 | Function f | test.py:14:20 | args | -| test.py:14:1 | Function f | test.py:14:28 | kwargs | -| test.py:14:1 | Function f | test.py:15:5 | Pass | -| test.py:14:1 | FunctionDef | test.py:14:1 | FunctionExpr | -| test.py:14:1 | FunctionDef | test.py:14:5 | f | -| test.py:14:1 | FunctionExpr | test.py:14:1 | Function f | -| test.py:17:1 | Function simple_stmts | test.py:18:5 | Pass | -| test.py:17:1 | Function simple_stmts | test.py:19:5 | ExprStmt | -| test.py:17:1 | Function simple_stmts | test.py:19:13 | Delete | -| test.py:17:1 | Function simple_stmts | test.py:19:20 | Pass | -| test.py:17:1 | Function simple_stmts | test.py:20:5 | If | -| test.py:17:1 | Function simple_stmts | test.py:24:5 | AssignStmt | -| test.py:17:1 | Function simple_stmts | test.py:44:5 | ExprStmt | -| test.py:17:1 | Function simple_stmts | test.py:45:5 | ExprStmt | -| test.py:17:1 | Function simple_stmts | test.py:46:5 | ExprStmt | -| test.py:17:1 | Function simple_stmts | test.py:47:5 | ExprStmt | -| test.py:17:1 | Function simple_stmts | test.py:48:5 | ExprStmt | -| test.py:17:1 | Function simple_stmts | test.py:49:5 | ExprStmt | -| test.py:17:1 | FunctionDef | test.py:17:1 | FunctionExpr | -| test.py:17:1 | FunctionDef | test.py:17:5 | simple_stmts | -| test.py:17:1 | FunctionExpr | test.py:17:1 | Function simple_stmts | -| test.py:19:5 | ExprStmt | test.py:19:5 | foo() | -| test.py:19:5 | foo() | test.py:19:5 | foo | -| test.py:19:13 | Delete | test.py:19:17 | x | -| test.py:20:5 | If | test.py:20:8 | thing | -| test.py:20:5 | If | test.py:21:9 | For | -| test.py:21:9 | For | test.py:21:13 | a | -| test.py:21:9 | For | test.py:21:18 | b | -| test.py:21:9 | For | test.py:22:13 | Pass | -| test.py:24:5 | AssignStmt | test.py:24:5 | tmp | -| test.py:24:5 | AssignStmt | test.py:25:9 | Yield | -| test.py:25:9 | Yield | test.py:25:15 | Tuple | -| test.py:25:15 | Tuple | test.py:25:15 | IntegerLiteral | -| test.py:25:15 | Tuple | test.py:26:9 | name | -| test.py:25:15 | Tuple | test.py:27:9 | Attribute | -| test.py:25:15 | Tuple | test.py:28:9 | BinaryExpr | -| test.py:25:15 | Tuple | test.py:29:9 | BinaryExpr | -| test.py:25:15 | Tuple | test.py:30:9 | BinaryExpr | -| test.py:25:15 | Tuple | test.py:31:9 | Attribute | -| test.py:25:15 | Tuple | test.py:32:9 | Subscript | -| test.py:25:15 | Tuple | test.py:33:9 | Lambda | -| test.py:25:15 | Tuple | test.py:34:9 | BoolExpr | -| test.py:25:15 | Tuple | test.py:35:9 | Compare | -| test.py:25:15 | Tuple | test.py:36:9 | DictComp | -| test.py:25:15 | Tuple | test.py:37:9 | SetComp | -| test.py:25:15 | Tuple | test.py:38:9 | ListComp | -| test.py:25:15 | Tuple | test.py:39:9 | List | -| test.py:25:15 | Tuple | test.py:40:9 | Dict | -| test.py:25:15 | Tuple | test.py:41:9 | Tuple | -| test.py:25:15 | Tuple | test.py:42:10 | Tuple | -| test.py:27:9 | Attribute | test.py:27:9 | attr | -| test.py:28:9 | BinaryExpr | test.py:28:9 | a | -| test.py:28:9 | BinaryExpr | test.py:28:13 | b | -| test.py:29:9 | BinaryExpr | test.py:29:9 | IntegerLiteral | -| test.py:29:9 | BinaryExpr | test.py:29:13 | IntegerLiteral | -| test.py:30:9 | BinaryExpr | test.py:30:9 | FloatLiteral | -| test.py:30:9 | BinaryExpr | test.py:30:15 | IntegerLiteral | -| test.py:31:9 | Attribute | test.py:31:9 | Attribute | -| test.py:31:9 | Attribute | test.py:31:9 | a | -| test.py:32:9 | Attribute | test.py:32:9 | a() | -| test.py:32:9 | Subscript | test.py:32:9 | Attribute | -| test.py:32:9 | Subscript | test.py:32:15 | c | -| test.py:32:9 | a() | test.py:32:9 | a | -| test.py:33:9 | Function lambda | test.py:33:16 | x | -| test.py:33:9 | Function lambda | test.py:33:19 | Return | -| test.py:33:9 | Lambda | test.py:33:9 | Function lambda | -| test.py:33:19 | BinaryExpr | test.py:33:19 | x | -| test.py:33:19 | BinaryExpr | test.py:33:21 | IntegerLiteral | -| test.py:33:19 | Return | test.py:33:19 | BinaryExpr | -| test.py:34:9 | BoolExpr | test.py:34:9 | p | -| test.py:34:9 | BoolExpr | test.py:34:14 | BoolExpr | -| test.py:34:14 | BoolExpr | test.py:34:14 | q | -| test.py:34:14 | BoolExpr | test.py:34:20 | BinaryExpr | -| test.py:34:20 | BinaryExpr | test.py:34:20 | r | -| test.py:34:20 | BinaryExpr | test.py:34:24 | s | -| test.py:35:9 | Compare | test.py:35:9 | a | -| test.py:35:9 | Compare | test.py:35:13 | b | -| test.py:35:9 | Compare | test.py:35:17 | c | -| test.py:35:9 | Compare | test.py:35:22 | IntegerLiteral | -| test.py:36:9 | DictComp | test.py:36:9 | Function dictcomp | -| test.py:36:9 | DictComp | test.py:36:26 | x | -| test.py:36:9 | For | test.py:36:9 | .0 | -| test.py:36:9 | For | test.py:36:9 | For | -| test.py:36:9 | For | test.py:36:11 | ExprStmt | -| test.py:36:9 | For | test.py:36:21 | z | -| test.py:36:9 | For | test.py:36:32 | y | -| test.py:36:9 | For | test.py:36:37 | z | -| test.py:36:9 | Function dictcomp | test.py:36:9 | .0 | -| test.py:36:9 | Function dictcomp | test.py:36:9 | For | -| test.py:36:11 | ExprStmt | test.py:36:11 | Yield | -| test.py:36:11 | Tuple | test.py:36:11 | IntegerLiteral | -| test.py:36:11 | Tuple | test.py:36:15 | y | -| test.py:36:11 | Yield | test.py:36:11 | Tuple | -| test.py:37:9 | For | test.py:37:9 | .0 | -| test.py:37:9 | For | test.py:37:9 | For | -| test.py:37:9 | For | test.py:37:12 | ExprStmt | -| test.py:37:9 | For | test.py:37:22 | z | -| test.py:37:9 | For | test.py:37:33 | y | -| test.py:37:9 | For | test.py:37:38 | z | -| test.py:37:9 | Function setcomp | test.py:37:9 | .0 | -| test.py:37:9 | Function setcomp | test.py:37:9 | For | -| test.py:37:9 | SetComp | test.py:37:9 | Function setcomp | -| test.py:37:9 | SetComp | test.py:37:27 | x | -| test.py:37:12 | ExprStmt | test.py:37:12 | Yield | -| test.py:37:12 | Tuple | test.py:37:12 | IntegerLiteral | -| test.py:37:12 | Tuple | test.py:37:15 | y | -| test.py:37:12 | Yield | test.py:37:12 | Tuple | -| test.py:38:9 | For | test.py:38:9 | .0 | -| test.py:38:9 | For | test.py:38:11 | ExprStmt | -| test.py:38:9 | For | test.py:38:20 | y | -| test.py:38:9 | Function listcomp | test.py:38:9 | .0 | -| test.py:38:9 | Function listcomp | test.py:38:9 | For | -| test.py:38:9 | ListComp | test.py:38:9 | Function listcomp | -| test.py:38:9 | ListComp | test.py:38:25 | z | -| test.py:38:11 | BinaryExpr | test.py:38:11 | y | -| test.py:38:11 | BinaryExpr | test.py:38:14 | IntegerLiteral | -| test.py:38:11 | ExprStmt | test.py:38:11 | Yield | -| test.py:38:11 | Yield | test.py:38:11 | BinaryExpr | -| test.py:42:10 | Tuple | test.py:42:10 | IntegerLiteral | -| test.py:44:5 | ExprStmt | test.py:44:5 | foo() | -| test.py:44:5 | foo() | test.py:44:5 | foo | -| test.py:44:5 | foo() | test.py:44:9 | IntegerLiteral | -| test.py:45:5 | ExprStmt | test.py:45:5 | foo() | -| test.py:45:5 | foo() | test.py:45:5 | foo | -| test.py:45:5 | foo() | test.py:45:9 | Keyword | -| test.py:45:9 | Keyword | test.py:45:11 | IntegerLiteral | -| test.py:46:5 | ExprStmt | test.py:46:5 | foo() | -| test.py:46:5 | foo() | test.py:46:5 | foo | -| test.py:46:5 | foo() | test.py:46:9 | IntegerLiteral | -| test.py:46:5 | foo() | test.py:46:11 | IntegerLiteral | -| test.py:46:5 | foo() | test.py:46:13 | Starred | -| test.py:46:13 | Starred | test.py:46:14 | t | -| test.py:47:5 | ExprStmt | test.py:47:5 | foo() | -| test.py:47:5 | foo() | test.py:47:5 | foo | -| test.py:47:5 | foo() | test.py:47:9 | IntegerLiteral | -| test.py:47:5 | foo() | test.py:47:11 | Keyword | -| test.py:47:5 | foo() | test.py:47:15 | Starred | -| test.py:47:11 | Keyword | test.py:47:13 | IntegerLiteral | -| test.py:47:15 | Starred | test.py:47:16 | t | -| test.py:48:5 | ExprStmt | test.py:48:5 | foo() | -| test.py:48:5 | foo() | test.py:48:5 | foo | -| test.py:48:5 | foo() | test.py:48:9 | IntegerLiteral | -| test.py:48:5 | foo() | test.py:48:11 | Keyword | -| test.py:48:5 | foo() | test.py:48:15 | Starred | -| test.py:48:5 | foo() | test.py:48:18 | DictUnpacking | -| test.py:48:11 | Keyword | test.py:48:13 | IntegerLiteral | -| test.py:48:15 | Starred | test.py:48:16 | t | -| test.py:48:18 | DictUnpacking | test.py:48:20 | d | -| test.py:49:5 | ExprStmt | test.py:49:5 | f() | -| test.py:49:5 | f() | test.py:49:5 | f | -| test.py:49:5 | f() | test.py:49:7 | DictUnpacking | -| test.py:49:7 | DictUnpacking | test.py:49:9 | d | -| test.py:51:1 | Function compound_stmts | test.py:52:5 | If | -| test.py:51:1 | Function compound_stmts | test.py:56:5 | While | -| test.py:51:1 | Function compound_stmts | test.py:61:5 | For | -| test.py:51:1 | Function compound_stmts | test.py:63:5 | With | -| test.py:51:1 | Function compound_stmts | test.py:65:5 | Try | -| test.py:51:1 | Function compound_stmts | test.py:69:5 | Try | -| test.py:51:1 | Function compound_stmts | test.py:73:5 | Try | -| test.py:51:1 | Function compound_stmts | test.py:77:5 | Try | -| test.py:51:1 | Function compound_stmts | test.py:81:5 | Try | -| test.py:51:1 | Function compound_stmts | test.py:87:5 | Try | -| test.py:51:1 | FunctionDef | test.py:51:1 | FunctionExpr | -| test.py:51:1 | FunctionDef | test.py:51:5 | compound_stmts | -| test.py:51:1 | FunctionExpr | test.py:51:1 | Function compound_stmts | -| test.py:52:5 | If | test.py:52:8 | cond | -| test.py:52:5 | If | test.py:53:9 | Return | -| test.py:52:5 | If | test.py:55:9 | Raise | -| test.py:53:9 | Return | test.py:53:16 | x | -| test.py:55:9 | Raise | test.py:55:15 | y | -| test.py:56:5 | While | test.py:56:11 | True | -| test.py:56:5 | While | test.py:57:9 | If | -| test.py:57:9 | If | test.py:57:12 | cond | -| test.py:57:9 | If | test.py:58:13 | Break | -| test.py:57:9 | If | test.py:60:13 | Continue | -| test.py:61:5 | For | test.py:61:9 | x | -| test.py:61:5 | For | test.py:61:14 | y | -| test.py:61:5 | For | test.py:62:9 | Pass | -| test.py:63:5 | With | test.py:63:5 | With | -| test.py:63:5 | With | test.py:63:10 | a | -| test.py:63:5 | With | test.py:63:15 | b | -| test.py:63:5 | With | test.py:63:18 | c | -| test.py:63:5 | With | test.py:63:23 | d | -| test.py:63:5 | With | test.py:64:9 | ExprStmt | -| test.py:64:9 | ExprStmt | test.py:64:9 | body | -| test.py:65:5 | Try | test.py:66:9 | ExprStmt | -| test.py:65:5 | Try | test.py:67:5 | ExceptStmt | -| test.py:66:9 | ExprStmt | test.py:66:9 | t1 | -| test.py:67:5 | ExceptStmt | test.py:68:9 | ExprStmt | -| test.py:68:9 | ExprStmt | test.py:68:9 | e1 | -| test.py:69:5 | Try | test.py:70:9 | ExprStmt | -| test.py:69:5 | Try | test.py:71:5 | ExceptStmt | -| test.py:70:9 | ExprStmt | test.py:70:9 | t2 | -| test.py:71:5 | ExceptStmt | test.py:71:12 | Exception | -| test.py:71:5 | ExceptStmt | test.py:72:9 | ExprStmt | -| test.py:72:9 | ExprStmt | test.py:72:9 | e2 | -| test.py:73:5 | Try | test.py:74:9 | ExprStmt | -| test.py:73:5 | Try | test.py:75:5 | ExceptStmt | -| test.py:74:9 | ExprStmt | test.py:74:9 | t3 | -| test.py:75:5 | ExceptStmt | test.py:75:12 | Exception | -| test.py:75:5 | ExceptStmt | test.py:75:25 | ex | -| test.py:75:5 | ExceptStmt | test.py:76:9 | ExprStmt | -| test.py:76:9 | ExprStmt | test.py:76:9 | e3 | -| test.py:77:5 | Try | test.py:78:9 | ExprStmt | -| test.py:77:5 | Try | test.py:80:9 | ExprStmt | -| test.py:78:9 | ExprStmt | test.py:78:9 | t4 | -| test.py:80:9 | ExprStmt | test.py:80:9 | f4 | -| test.py:81:5 | Try | test.py:82:9 | ExprStmt | -| test.py:81:5 | Try | test.py:83:5 | ExceptStmt | -| test.py:81:5 | Try | test.py:86:9 | ExprStmt | -| test.py:82:9 | ExprStmt | test.py:82:9 | t5 | -| test.py:83:5 | ExceptStmt | test.py:83:12 | Exception | -| test.py:83:5 | ExceptStmt | test.py:83:25 | ex | -| test.py:83:5 | ExceptStmt | test.py:84:9 | ExprStmt | -| test.py:84:9 | ExprStmt | test.py:84:9 | e5 | -| test.py:86:9 | ExprStmt | test.py:86:9 | f5 | -| test.py:87:5 | Try | test.py:88:9 | ExprStmt | -| test.py:87:5 | Try | test.py:90:9 | Try | -| test.py:88:9 | ExprStmt | test.py:88:9 | t6 | -| test.py:90:9 | Try | test.py:91:13 | ExprStmt | -| test.py:90:9 | Try | test.py:93:13 | ExprStmt | -| test.py:91:13 | ExprStmt | test.py:91:13 | t7 | -| test.py:93:13 | ExprStmt | test.py:93:13 | f7 | diff --git a/python/ql/test/library-tests/ast/Child.ql b/python/ql/test/library-tests/ast/Child.ql deleted file mode 100644 index a0ae5909f08..00000000000 --- a/python/ql/test/library-tests/ast/Child.ql +++ /dev/null @@ -1,7 +0,0 @@ -import python -import semmle.python.TestUtils - -from AstNode p, AstNode c -where p.getAChildNode() = c -select compact_location(p), p.toString(), compact_location(c), c.toString() - diff --git a/python/ql/test/library-tests/ast/test.py b/python/ql/test/library-tests/ast/test.py deleted file mode 100644 index 320efb1fdcc..00000000000 --- a/python/ql/test/library-tests/ast/test.py +++ /dev/null @@ -1,94 +0,0 @@ - -@deco1 -@deco2() -@deco3.attr1.attr2 -class C(Base): - - def __init__(self): - pass - -@deco4.attr() -def f(): - pass - -def f(pos0, pos1, *args, **kwargs): - pass - -def simple_stmts(): - pass - foo() ; del x; pass - if thing: - for a in b: - pass - #Expressions - tmp = ( - yield 3, - name, - attr.attrname, - a + b, - 3 & 4, - 3.0 * 4, - a.b.c.d, - a().b[c], - lambda x: x+1, - p or q and r ^ s, - a < b > c in 5, - { 1 : y for z in x for y in z}, - { (1, y) for z in x for y in z}, - [ y**2 for y in z ], - [], - {}, - (), - (1,), - ) - foo(1) - foo(a=1) - foo(1,2,*t) - foo(1,a=1,*t) - foo(1,a=1,*t,**d) - f(**d) - -def compound_stmts(): - if cond: - return x - else: - raise y - while True: - if cond: - break - else: - continue - for x in y: - pass - with a as b, c as d: - body - try: - t1 - except: - e1 - try: - t2 - except Exception: - e2 - try: - t3 - except Exception as ex: - e3 - try: - t4 - finally: - f4 - try: - t5 - except Exception as ex: - e5 - finally: - f5 - try: - t6 - finally: - try: - t7 - finally: - f7 - From 5da209f876b72bae5d823f1562600b7a5f12c194 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Mon, 28 Jan 2019 12:04:04 +0000 Subject: [PATCH 27/33] Python: add failing test for comparison using 'is' and enum members. --- .../Expressions/eq/expressions_test.py | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/python/ql/test/query-tests/Expressions/eq/expressions_test.py b/python/ql/test/query-tests/Expressions/eq/expressions_test.py index 2ffac276553..46b7a0c4005 100644 --- a/python/ql/test/query-tests/Expressions/eq/expressions_test.py +++ b/python/ql/test/query-tests/Expressions/eq/expressions_test.py @@ -24,7 +24,7 @@ -#ODASA-4519 + #OK as we are using identity tests for unique objects V2 = "v2" V3 = "v3" @@ -85,3 +85,21 @@ def both_sides_known(zero_based="auto", query_id=False): if zero_based is False: # False positive here pass +#Avoid depending on enum back port for Python 2 tests: +class Enum(object): + pass + +class MyEnum(Enum): + + memberA = None + memberB = 10 + memberC = ("Hello", "World") + +def comp_enum(x): + if x is MyEnum.memberA: + return + if x is MyEnum.memberB: + return + if x is MyEnum.memberC: + return + From 53fbf51ee8bc04c6b2594d5a887a158385a145e0 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Mon, 28 Jan 2019 12:17:36 +0000 Subject: [PATCH 28/33] Python: Fix handling of enum members in python/ql/src/Expressions/IsComparisons.qll. --- python/ql/src/Expressions/IsComparisons.qll | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/python/ql/src/Expressions/IsComparisons.qll b/python/ql/src/Expressions/IsComparisons.qll index 270c951f3cb..0c6343daefd 100644 --- a/python/ql/src/Expressions/IsComparisons.qll +++ b/python/ql/src/Expressions/IsComparisons.qll @@ -107,6 +107,20 @@ predicate invalid_portable_is_comparison(Compare comp, Cmpop op, ClassObject cls left.refersTo(obj) and right.refersTo(obj) and exists(ImmutableLiteral il | il.getLiteralObject() = obj) ) + and + /* OK to use 'is' when comparing with a member of an enum */ + not exists(Expr left, Expr right, AstNode origin | + comp.compares(left, op, right) and + enum_member(origin) | + left.refersTo(_, origin) or right.refersTo(_, origin) + ) } +private predicate enum_member(AstNode obj) { + exists(ClassObject cls, AssignStmt asgn | + cls.getASuperType().getName() = "Enum" | + cls.getPyClass() = asgn.getScope() and + asgn.getValue() = obj + ) +} From 4e5d4e265ca0d59b18760e31463b02de0eeb6007 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Mon, 28 Jan 2019 13:01:04 +0000 Subject: [PATCH 29/33] Add change note. --- change-notes/1.20/analysis-python.md | 1 + 1 file changed, 1 insertion(+) diff --git a/change-notes/1.20/analysis-python.md b/change-notes/1.20/analysis-python.md index 978e6a0c30d..3eec4dc8999 100644 --- a/change-notes/1.20/analysis-python.md +++ b/change-notes/1.20/analysis-python.md @@ -20,6 +20,7 @@ Removes false positives seen when using Python 3.6, but not when using earlier v | **Query** | **Expected impact** | **Change** | |----------------------------|------------------------|------------------------------------------------------------------| +| Comparison using is when operands support \_\_eq\_\_ (`py/comparison-using-is`) | Fewer false positive results | Results where one of the objects being compared is an enum member are no longer reported. | | Unused import (`py/unused-import`) | Fewer false positive results | Results where the imported module is used in a `doctest` string are no longer reported. | | Unused import (`py/unused-import`) | Fewer false positive results | Results where the imported module is used in a type-hint comment are no longer reported. | From 6d553ae2be625f64eab6e92338511687246671bd Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Mon, 28 Jan 2019 14:26:16 +0000 Subject: [PATCH 30/33] Python: Check os.open as well as os.chmod for weak file permissions. --- .../Security/CWE-732/WeakFilePermissions.ql | 19 +++++++++++++++---- .../CWE-732/WeakFilePermissions.expected | 1 + .../test/query-tests/Security/CWE-732/test.py | 2 ++ .../query-tests/Security/lib/os/__init__.py | 3 +++ 4 files changed, 21 insertions(+), 4 deletions(-) diff --git a/python/ql/src/Security/CWE-732/WeakFilePermissions.ql b/python/ql/src/Security/CWE-732/WeakFilePermissions.ql index f02fc29df76..a65b23845d6 100644 --- a/python/ql/src/Security/CWE-732/WeakFilePermissions.ql +++ b/python/ql/src/Security/CWE-732/WeakFilePermissions.ql @@ -34,9 +34,20 @@ string permissive_permission(int p) { world_permission(p) = 0 and result = "group " + access(group_permission(p)) } -from FunctionObject chmod, CallNode call, NumericObject num, string permission -where +predicate chmod_call(CallNode call, FunctionObject chmod, NumericObject num) { any(ModuleObject os | os.getName() = "os").getAttribute("chmod") = chmod and - chmod.getACall() = call and call.getArg(1).refersTo(num) and + chmod.getACall() = call and call.getArg(1).refersTo(num) +} + +predicate open_call(CallNode call, FunctionObject open, NumericObject num) { + any(ModuleObject os | os.getName() = "os").getAttribute("open") = open and + open.getACall() = call and call.getArg(2).refersTo(num) +} + + +from CallNode call, FunctionObject func, NumericObject num, string permission +where + (chmod_call(call, func, num) or open_call(call, func, num)) + and permission = permissive_permission(num.intValue()) -select call, "Overly permissive mask in chmod sets file to " + permission + "." +select call, "Overly permissive mask in " + func.getName() + " sets file to " + permission + "." diff --git a/python/ql/test/query-tests/Security/CWE-732/WeakFilePermissions.expected b/python/ql/test/query-tests/Security/CWE-732/WeakFilePermissions.expected index c805dfd3f84..3bfb6fe4f88 100644 --- a/python/ql/test/query-tests/Security/CWE-732/WeakFilePermissions.expected +++ b/python/ql/test/query-tests/Security/CWE-732/WeakFilePermissions.expected @@ -4,3 +4,4 @@ | test.py:11:1:11:21 | ControlFlowNode for Attribute() | Overly permissive mask in chmod sets file to group readable. | | test.py:13:1:13:28 | ControlFlowNode for Attribute() | Overly permissive mask in chmod sets file to group writable. | | test.py:14:1:14:19 | ControlFlowNode for Attribute() | Overly permissive mask in chmod sets file to group writable. | +| test.py:16:1:16:25 | ControlFlowNode for Attribute() | Overly permissive mask in open sets file to world readable. | diff --git a/python/ql/test/query-tests/Security/CWE-732/test.py b/python/ql/test/query-tests/Security/CWE-732/test.py index bf551afad5e..273311ef3e7 100644 --- a/python/ql/test/query-tests/Security/CWE-732/test.py +++ b/python/ql/test/query-tests/Security/CWE-732/test.py @@ -12,3 +12,5 @@ os.chmod(file, 0o550) # BAD os.chmod(file, stat.S_IRWXU) # GOOD os.chmod(file, stat.S_IWGRP) # BAD os.chmod(file, 400) # BAD -- Decimal format. + +os.open(file, 'w', 0o704) # BAD diff --git a/python/ql/test/query-tests/Security/lib/os/__init__.py b/python/ql/test/query-tests/Security/lib/os/__init__.py index a882369a42d..d7a7ca0eb38 100644 --- a/python/ql/test/query-tests/Security/lib/os/__init__.py +++ b/python/ql/test/query-tests/Security/lib/os/__init__.py @@ -6,3 +6,6 @@ def popen(cmd, *args, **kwargs): def chmod(path, mode): pass + +def open(path, flags, mode): + pass From 39705cf7333ee3d6840dee8eacb3f6e8d0c34b25 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Mon, 28 Jan 2019 14:33:39 +0000 Subject: [PATCH 31/33] Python: Clarify predicate a bit. --- python/ql/src/semmle/python/dataflow/SsaDefinitions.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/ql/src/semmle/python/dataflow/SsaDefinitions.qll b/python/ql/src/semmle/python/dataflow/SsaDefinitions.qll index 5210c9974bb..fba79d23c05 100644 --- a/python/ql/src/semmle/python/dataflow/SsaDefinitions.qll +++ b/python/ql/src/semmle/python/dataflow/SsaDefinitions.qll @@ -404,11 +404,11 @@ cached module SsaSource { * to the __init__ module of that package. */ cached predicate init_module_submodule_defn(PythonSsaSourceVariable var, ControlFlowNode f) { + var instanceof GlobalVariable and exists(Module init | init.isPackageInit() and exists(init.getPackage().getSubModule(var.getName())) and init.getEntryNode() = f and - var.getScope() = init and - var instanceof GlobalVariable + var.getScope() = init ) } From 54fdf9f29d55b9fb79865654ea3623b9c96aed8a Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Mon, 28 Jan 2019 09:34:45 -0800 Subject: [PATCH 32/33] C++/Docs: respond to doc comments on PR --- cpp/config/suites/c/correctness | 3 ++- cpp/ql/src/Likely Bugs/Likely Typos/FutileParams.qhelp | 2 +- cpp/ql/src/Likely Bugs/Likely Typos/FutileParams.ql | 4 ++++ 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/cpp/config/suites/c/correctness b/cpp/config/suites/c/correctness index e53ccda1187..442e618854d 100644 --- a/cpp/config/suites/c/correctness +++ b/cpp/config/suites/c/correctness @@ -7,7 +7,7 @@ + semmlecode-cpp-queries/Likely Bugs/Conversion/NonzeroValueCastToPointer.ql: /Correctness/Dangerous Conversions + semmlecode-cpp-queries/Likely Bugs/Conversion/ImplicitDowncastFromBitfield.ql: /Correctness/Dangerous Conversions + semmlecode-cpp-queries/Security/CWE/CWE-253/HResultBooleanConversion.ql: /Correctness/Dangerous Conversions - # Consistent Use + # Consistent Use + semmlecode-cpp-queries/Critical/ReturnValueIgnored.ql: /Correctness/Consistent Use + semmlecode-cpp-queries/Likely Bugs/InconsistentCheckReturnNull.ql: /Correctness/Consistent Use + semmlecode-cpp-queries/Likely Bugs/InconsistentCallOnResult.ql: /Correctness/Consistent Use @@ -15,6 +15,7 @@ + semmlecode-cpp-queries/Likely Bugs/Likely Typos/AssignWhereCompareMeant.ql: /Correctness/Common Errors + semmlecode-cpp-queries/Likely Bugs/Likely Typos/CompareWhereAssignMeant.ql: /Correctness/Common Errors + semmlecode-cpp-queries/Likely Bugs/Likely Typos/ExprHasNoEffect.ql: /Correctness/Common Errors ++ semmlecode-cpp-queries/Likely Bugs/Likely Typos/FutileParams.ql: /Correctness/Common Errors + semmlecode-cpp-queries/Likely Bugs/Likely Typos/ShortCircuitBitMask.ql: /Correctness/Common Errors + semmlecode-cpp-queries/Likely Bugs/Likely Typos/MissingEnumCaseInSwitch.ql: /Correctness/Common Errors + semmlecode-cpp-queries/Likely Bugs/Arithmetic/FloatComparison.ql: /Correctness/Common Errors diff --git a/cpp/ql/src/Likely Bugs/Likely Typos/FutileParams.qhelp b/cpp/ql/src/Likely Bugs/Likely Typos/FutileParams.qhelp index 0316bfdfa36..6c4fc404fea 100644 --- a/cpp/ql/src/Likely Bugs/Likely Typos/FutileParams.qhelp +++ b/cpp/ql/src/Likely Bugs/Likely Typos/FutileParams.qhelp @@ -11,7 +11,7 @@ that the incorrect function is being called, or that the author misunderstood th

    In C, a function declared with an empty parameter list `()` is considered to have an unknown parameter list, and therefore can be called with any set of arguments. To declare a function which takes no arguments, you must use `(void)` as the parameter list in any forward declarations. -In C++, either style of declaration will be considered to take no arguments.

    +In C++, either style of declaration indicates that the function accepts no arguments.

    diff --git a/cpp/ql/src/Likely Bugs/Likely Typos/FutileParams.ql b/cpp/ql/src/Likely Bugs/Likely Typos/FutileParams.ql index ec7260d5d7f..bb5a99a69bc 100644 --- a/cpp/ql/src/Likely Bugs/Likely Typos/FutileParams.ql +++ b/cpp/ql/src/Likely Bugs/Likely Typos/FutileParams.ql @@ -4,6 +4,10 @@ * that the code does not follow the author's intent. * @kind problem * @problem.severity warning + * @precision very-high + * @id cpp/futile-params + * @tags correctness + * maintainability */ import cpp From 9642a78bdefb2c1551c6fcbec6e02f1fa593b006 Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Mon, 28 Jan 2019 09:40:19 -0800 Subject: [PATCH 33/33] C++: add FutileParams.ql to C++ suite In theory this query will produce no results on C++ code; in practice, I suspect the "cpp" suite is often run on code compiled as C, so it is likely to be worth running anyways. --- cpp/config/suites/cpp/correctness | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cpp/config/suites/cpp/correctness b/cpp/config/suites/cpp/correctness index ceb15f55260..00ad7a1ad07 100644 --- a/cpp/config/suites/cpp/correctness +++ b/cpp/config/suites/cpp/correctness @@ -8,7 +8,7 @@ + semmlecode-cpp-queries/Likely Bugs/Conversion/ImplicitDowncastFromBitfield.ql: /Correctness/Dangerous Conversions + semmlecode-cpp-queries/Likely Bugs/Conversion/CastArrayPointerArithmetic.ql: /Correctness/Dangerous Conversions + semmlecode-cpp-queries/Security/CWE/CWE-253/HResultBooleanConversion.ql: /Correctness/Dangerous Conversions - # Consistent Use + # Consistent Use + semmlecode-cpp-queries/Critical/ReturnValueIgnored.ql: /Correctness/Consistent Use + semmlecode-cpp-queries/Likely Bugs/InconsistentCheckReturnNull.ql: /Correctness/Consistent Use + semmlecode-cpp-queries/Likely Bugs/InconsistentCallOnResult.ql: /Correctness/Consistent Use @@ -16,6 +16,7 @@ + semmlecode-cpp-queries/Likely Bugs/Likely Typos/AssignWhereCompareMeant.ql: /Correctness/Common Errors + semmlecode-cpp-queries/Likely Bugs/Likely Typos/CompareWhereAssignMeant.ql: /Correctness/Common Errors + semmlecode-cpp-queries/Likely Bugs/Likely Typos/ExprHasNoEffect.ql: /Correctness/Common Errors ++ semmlecode-cpp-queries/Likely Bugs/Likely Typos/FutileParams.ql: /Correctness/Common Errors + semmlecode-cpp-queries/Likely Bugs/Likely Typos/ShortCircuitBitMask.ql: /Correctness/Common Errors + semmlecode-cpp-queries/Likely Bugs/Likely Typos/MissingEnumCaseInSwitch.ql: /Correctness/Common Errors + semmlecode-cpp-queries/Likely Bugs/Arithmetic/FloatComparison.ql: /Correctness/Common Errors