diff --git a/python/ql/src/semmle/python/dataflow/SsaDefinitions.qll b/python/ql/src/semmle/python/dataflow/SsaDefinitions.qll index 9ecb1c550e7..b2f80189327 100644 --- a/python/ql/src/semmle/python/dataflow/SsaDefinitions.qll +++ b/python/ql/src/semmle/python/dataflow/SsaDefinitions.qll @@ -356,7 +356,8 @@ 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 - call.getFunction().(AttrNode).getObject() = use + call.getFunction().(AttrNode).getObject() = use and + not test_contains(_, call) } /** Holds if `v` is defined by assignment at `defn` and given `value`. */ diff --git a/python/ql/test/library-tests/PointsTo/new/Dataflow.expected b/python/ql/test/library-tests/PointsTo/new/Dataflow.expected index 193ccf8fd1e..e643bccb3d9 100644 --- a/python/ql/test/library-tests/PointsTo/new/Dataflow.expected +++ b/python/ql/test/library-tests/PointsTo/new/Dataflow.expected @@ -54,6 +54,7 @@ | b_condition.py:0 | h_0 = ScopeEntryDefinition | | b_condition.py:0 | k_0 = ScopeEntryDefinition | | b_condition.py:0 | loop_0 = ScopeEntryDefinition | +| b_condition.py:0 | method_check_0 = ScopeEntryDefinition | | b_condition.py:0 | not_or_not_0 = ScopeEntryDefinition | | b_condition.py:0 | odasa6261_0 = ScopeEntryDefinition | | b_condition.py:0 | split_bool1_0 = ScopeEntryDefinition | @@ -160,6 +161,13 @@ | b_condition.py:104 | a_1 = Pi(a_0) [false] | | b_condition.py:105 | a_2 = Pi(a_1) [false] | | b_condition.py:107 | a_3 = Pi(a_2) [false] | +| b_condition.py:109 | method_check_1 = FunctionExpr | +| b_condition.py:109 | x_0 = ParameterDefinition | +| b_condition.py:109 | x_5 = phi(x_2, x_4) | +| b_condition.py:111 | x_1 = Pi(x_0) [true] | +| b_condition.py:111 | x_2 = ArgumentRefinement(x_1) | +| b_condition.py:113 | x_3 = Pi(x_0) [false] | +| b_condition.py:113 | x_4 = ArgumentRefinement(x_3) | | d_globals.py:0 | D_0 = ScopeEntryDefinition | | d_globals.py:0 | Ugly_0 = ScopeEntryDefinition | | d_globals.py:0 | X_0 = ScopeEntryDefinition | diff --git a/python/ql/test/library-tests/PointsTo/new/Definitions.expected b/python/ql/test/library-tests/PointsTo/new/Definitions.expected index 3cce615988f..5d519fa01cb 100644 --- a/python/ql/test/library-tests/PointsTo/new/Definitions.expected +++ b/python/ql/test/library-tests/PointsTo/new/Definitions.expected @@ -37,6 +37,7 @@ | b_condition.py:0 | Global Variable h | ScopeEntryDefinition | | b_condition.py:0 | Global Variable k | ScopeEntryDefinition | | b_condition.py:0 | Global Variable loop | ScopeEntryDefinition | +| b_condition.py:0 | Global Variable method_check | ScopeEntryDefinition | | b_condition.py:0 | Global Variable not_or_not | ScopeEntryDefinition | | b_condition.py:0 | Global Variable odasa6261 | ScopeEntryDefinition | | b_condition.py:0 | Global Variable split_bool1 | ScopeEntryDefinition | @@ -136,6 +137,13 @@ | b_condition.py:104 | Local Variable a | PyEdgeRefinement | | b_condition.py:105 | Local Variable a | PyEdgeRefinement | | b_condition.py:107 | Local Variable a | PyEdgeRefinement | +| b_condition.py:109 | Global Variable method_check | AssignmentDefinition | +| b_condition.py:109 | Local Variable x | ParameterDefinition | +| b_condition.py:109 | Local Variable x | PhiFunction | +| b_condition.py:111 | Local Variable x | ArgumentRefinement | +| b_condition.py:111 | Local Variable x | PyEdgeRefinement | +| b_condition.py:113 | Local Variable x | ArgumentRefinement | +| b_condition.py:113 | Local Variable x | PyEdgeRefinement | | d_globals.py:0 | Global Variable D | ScopeEntryDefinition | | d_globals.py:0 | Global Variable Ugly | ScopeEntryDefinition | | d_globals.py:0 | Global Variable X | ScopeEntryDefinition | diff --git a/python/ql/test/library-tests/PointsTo/new/Live.expected b/python/ql/test/library-tests/PointsTo/new/Live.expected index a0a70d136c7..8717de94032 100644 --- a/python/ql/test/library-tests/PointsTo/new/Live.expected +++ b/python/ql/test/library-tests/PointsTo/new/Live.expected @@ -162,6 +162,8 @@ | Global Variable list | b_condition.py:101 | entry | | Global Variable loop | b_condition.py:42 | exit | | Global Variable loop | b_condition.py:43 | entry | +| Global Variable method_check | b_condition.py:42 | exit | +| Global Variable method_check | b_condition.py:43 | entry | | Global Variable not_or_not | b_condition.py:42 | exit | | Global Variable not_or_not | b_condition.py:43 | entry | | Global Variable object | b_condition.py:0 | entry | @@ -298,6 +300,10 @@ | Global Variable use | b_condition.py:88 | exit | | Global Variable use | b_condition.py:90 | entry | | Global Variable use | b_condition.py:90 | exit | +| Global Variable use | b_condition.py:109 | entry | +| Global Variable use | b_condition.py:110 | exit | +| Global Variable use | b_condition.py:111 | entry | +| Global Variable use | b_condition.py:113 | entry | | Global Variable v2 | b_condition.py:42 | exit | | Global Variable v2 | b_condition.py:43 | entry | | Global Variable v2 | b_condition.py:44 | exit | @@ -372,6 +378,12 @@ | Local Variable x | b_condition.py:88 | exit | | Local Variable x | b_condition.py:90 | entry | | Local Variable x | b_condition.py:90 | exit | +| Local Variable x | b_condition.py:109 | entry | +| Local Variable x | b_condition.py:110 | exit | +| Local Variable x | b_condition.py:111 | entry | +| Local Variable x | b_condition.py:111 | exit | +| Local Variable x | b_condition.py:113 | entry | +| Local Variable x | b_condition.py:113 | exit | | Local Variable y | b_condition.py:5 | entry | | Local Variable y | b_condition.py:5 | exit | | Local Variable y | b_condition.py:7 | exit | diff --git a/python/ql/test/library-tests/PointsTo/new/NameSpace.expected b/python/ql/test/library-tests/PointsTo/new/NameSpace.expected index bcf7d969dd7..b3c8ad622a5 100644 --- a/python/ql/test/library-tests/PointsTo/new/NameSpace.expected +++ b/python/ql/test/library-tests/PointsTo/new/NameSpace.expected @@ -14,6 +14,7 @@ | b_condition.py:0 | Module code.b_condition | h | Function h | | b_condition.py:0 | Module code.b_condition | k | Function k | | b_condition.py:0 | Module code.b_condition | loop | Function loop | +| b_condition.py:0 | Module code.b_condition | method_check | Function method_check | | b_condition.py:0 | Module code.b_condition | not_or_not | Function not_or_not | | b_condition.py:0 | Module code.b_condition | odasa6261 | Function odasa6261 | | b_condition.py:0 | Module code.b_condition | split_bool1 | Function split_bool1 | diff --git a/python/ql/test/library-tests/PointsTo/new/PointsToUnknown.expected b/python/ql/test/library-tests/PointsTo/new/PointsToUnknown.expected index 93f0b8c515c..fe490094107 100644 --- a/python/ql/test/library-tests/PointsTo/new/PointsToUnknown.expected +++ b/python/ql/test/library-tests/PointsTo/new/PointsToUnknown.expected @@ -114,6 +114,13 @@ | b_condition.py:99 | ControlFlowNode for use() | 99 | | b_condition.py:105 | ControlFlowNode for Subscript | 105 | | b_condition.py:105 | ControlFlowNode for UnaryExpr | 105 | +| b_condition.py:110 | ControlFlowNode for Attribute | 110 | +| b_condition.py:110 | ControlFlowNode for Attribute() | 110 | +| b_condition.py:110 | ControlFlowNode for x | 109 | +| b_condition.py:111 | ControlFlowNode for use | 111 | +| b_condition.py:111 | ControlFlowNode for use() | 111 | +| b_condition.py:113 | ControlFlowNode for use | 113 | +| b_condition.py:113 | ControlFlowNode for use() | 113 | | c_tests.py:5 | ControlFlowNode for IfExp | 5 | | c_tests.py:5 | ControlFlowNode for cond | 5 | | c_tests.py:5 | ControlFlowNode for unknown | 5 | diff --git a/python/ql/test/library-tests/PointsTo/new/PointsToWithContext.expected b/python/ql/test/library-tests/PointsTo/new/PointsToWithContext.expected index b7cced59a58..5b4b438bbab 100755 --- a/python/ql/test/library-tests/PointsTo/new/PointsToWithContext.expected +++ b/python/ql/test/library-tests/PointsTo/new/PointsToWithContext.expected @@ -185,6 +185,8 @@ WARNING: Predicate points_to has been deprecated and may be removed in future (P | b_condition.py:106 | ControlFlowNode for Exception | builtin-class Exception | builtin-class type | 106 | runtime | | b_condition.py:106 | ControlFlowNode for Exception() | Exception() | builtin-class Exception | 106 | runtime | | b_condition.py:107 | ControlFlowNode for Str | 'Hello' | builtin-class str | 107 | runtime | +| b_condition.py:109 | ControlFlowNode for FunctionExpr | Function method_check | builtin-class function | 109 | import | +| b_condition.py:109 | ControlFlowNode for method_check | Function method_check | builtin-class function | 109 | import | | e_temporal.py:2 | ControlFlowNode for ImportExpr | Module sys | builtin-class module | 2 | import | | e_temporal.py:2 | ControlFlowNode for sys | Module sys | builtin-class module | 2 | import | | e_temporal.py:4 | ControlFlowNode for FunctionExpr | Function f | builtin-class function | 4 | import | diff --git a/python/ql/test/library-tests/PointsTo/new/PointsToWithType.expected b/python/ql/test/library-tests/PointsTo/new/PointsToWithType.expected index 131957da9fb..31d1a220849 100644 --- a/python/ql/test/library-tests/PointsTo/new/PointsToWithType.expected +++ b/python/ql/test/library-tests/PointsTo/new/PointsToWithType.expected @@ -185,6 +185,8 @@ WARNING: Predicate points_to has been deprecated and may be removed in future (P | b_condition.py:106 | ControlFlowNode for Exception | builtin-class Exception | builtin-class type | 106 | | b_condition.py:106 | ControlFlowNode for Exception() | Exception() | builtin-class Exception | 106 | | b_condition.py:107 | ControlFlowNode for Str | 'Hello' | builtin-class str | 107 | +| b_condition.py:109 | ControlFlowNode for FunctionExpr | Function method_check | builtin-class function | 109 | +| b_condition.py:109 | ControlFlowNode for method_check | Function method_check | builtin-class function | 109 | | d_globals.py:2 | ControlFlowNode for FunctionExpr | Function j | builtin-class function | 2 | | d_globals.py:2 | ControlFlowNode for j | Function j | builtin-class function | 2 | | d_globals.py:3 | ControlFlowNode for Tuple | Tuple | builtin-class tuple | 3 | diff --git a/python/ql/test/library-tests/PointsTo/new/SSA.expected b/python/ql/test/library-tests/PointsTo/new/SSA.expected index 5d8c600a433..c42c07241b2 100644 --- a/python/ql/test/library-tests/PointsTo/new/SSA.expected +++ b/python/ql/test/library-tests/PointsTo/new/SSA.expected @@ -86,6 +86,7 @@ WARNING: Predicate ssa_variable_points_to has been deprecated and may be removed | b_condition.py:96 | y_6 = SingleSuccessorGuard(y_5) [false] | NoneType None | builtin-class NoneType | | b_condition.py:97 | x_3 = ArgumentRefinement(x_2) | NoneType None | builtin-class NoneType | | b_condition.py:101 | not_or_not_1 = FunctionExpr | Function not_or_not | builtin-class function | +| b_condition.py:109 | method_check_1 = FunctionExpr | Function method_check | builtin-class function | | c_tests.py:0 | __name___0 = ScopeEntryDefinition | 'code.c_tests' | builtin-class str | | c_tests.py:4 | f_0 = FunctionExpr | Function f | builtin-class function | | c_tests.py:5 | x_0 = IfExp | NoneType None | builtin-class NoneType | diff --git a/python/ql/test/library-tests/PointsTo/new/SourceEdgeDefinitions.expected b/python/ql/test/library-tests/PointsTo/new/SourceEdgeDefinitions.expected index 900b5ee9152..40c4d753fb2 100644 --- a/python/ql/test/library-tests/PointsTo/new/SourceEdgeDefinitions.expected +++ b/python/ql/test/library-tests/PointsTo/new/SourceEdgeDefinitions.expected @@ -20,3 +20,4 @@ | b_condition.py:102 | Local Variable a | ControlFlowNode for a | | b_condition.py:104 | Local Variable a | ControlFlowNode for a | | b_condition.py:105 | Local Variable a | ControlFlowNode for a | +| b_condition.py:110 | Local Variable x | ControlFlowNode for x | diff --git a/python/ql/test/library-tests/PointsTo/new/SourceNodeDefinitions.expected b/python/ql/test/library-tests/PointsTo/new/SourceNodeDefinitions.expected index e3cffec2918..a36aeeb3afb 100644 --- a/python/ql/test/library-tests/PointsTo/new/SourceNodeDefinitions.expected +++ b/python/ql/test/library-tests/PointsTo/new/SourceNodeDefinitions.expected @@ -50,6 +50,7 @@ | b_condition.py:0 | Global Variable h | Entry node for Module code.b_condition | definition | | b_condition.py:0 | Global Variable k | Entry node for Module code.b_condition | definition | | b_condition.py:0 | Global Variable loop | Entry node for Module code.b_condition | definition | +| b_condition.py:0 | Global Variable method_check | Entry node for Module code.b_condition | definition | | b_condition.py:0 | Global Variable not_or_not | Entry node for Module code.b_condition | definition | | b_condition.py:0 | Global Variable odasa6261 | Entry node for Module code.b_condition | definition | | b_condition.py:0 | Global Variable split_bool1 | Entry node for Module code.b_condition | definition | @@ -115,3 +116,7 @@ | b_condition.py:101 | Global Variable not_or_not | ControlFlowNode for not_or_not | definition | | b_condition.py:101 | Local Variable a | ControlFlowNode for a | definition | | b_condition.py:101 | Local Variable a | Entry node for Function not_or_not | definition | +| b_condition.py:109 | Global Variable method_check | ControlFlowNode for method_check | definition | +| b_condition.py:109 | Local Variable x | ControlFlowNode for x | definition | +| b_condition.py:111 | Local Variable x | ControlFlowNode for use() | refinement | +| b_condition.py:113 | Local Variable x | ControlFlowNode for use() | refinement | diff --git a/python/ql/test/library-tests/PointsTo/new/SsaUses.expected b/python/ql/test/library-tests/PointsTo/new/SsaUses.expected index 04a81665b68..4733d44dcf5 100644 --- a/python/ql/test/library-tests/PointsTo/new/SsaUses.expected +++ b/python/ql/test/library-tests/PointsTo/new/SsaUses.expected @@ -63,6 +63,7 @@ | b_condition.py:0 | h_1 | Exit node for Module code.b_condition | | b_condition.py:0 | k_1 | Exit node for Module code.b_condition | | b_condition.py:0 | loop_1 | Exit node for Module code.b_condition | +| b_condition.py:0 | method_check_1 | Exit node for Module code.b_condition | | b_condition.py:0 | not_or_not_1 | Exit node for Module code.b_condition | | b_condition.py:0 | odasa6261_1 | Exit node for Module code.b_condition | | b_condition.py:0 | split_bool1_1 | Exit node for Module code.b_condition | @@ -91,6 +92,7 @@ | b_condition.py:39 | h_0 | ControlFlowNode for thing() | | b_condition.py:39 | k_0 | ControlFlowNode for thing() | | b_condition.py:39 | loop_0 | ControlFlowNode for thing() | +| b_condition.py:39 | method_check_0 | ControlFlowNode for thing() | | b_condition.py:39 | not_or_not_0 | ControlFlowNode for thing() | | b_condition.py:39 | odasa6261_0 | ControlFlowNode for thing() | | b_condition.py:39 | split_bool1_0 | ControlFlowNode for thing() | @@ -105,6 +107,7 @@ | b_condition.py:43 | h_0 | ControlFlowNode for use() | | b_condition.py:43 | k_0 | ControlFlowNode for use() | | b_condition.py:43 | loop_0 | ControlFlowNode for use() | +| b_condition.py:43 | method_check_0 | ControlFlowNode for use() | | b_condition.py:43 | not_or_not_0 | ControlFlowNode for use() | | b_condition.py:43 | odasa6261_0 | ControlFlowNode for use() | | b_condition.py:43 | split_bool1_0 | ControlFlowNode for use() | @@ -118,6 +121,7 @@ | b_condition.py:44 | h_0 | ControlFlowNode for use() | | b_condition.py:44 | k_0 | ControlFlowNode for use() | | b_condition.py:44 | loop_0 | ControlFlowNode for use() | +| b_condition.py:44 | method_check_0 | ControlFlowNode for use() | | b_condition.py:44 | not_or_not_0 | ControlFlowNode for use() | | b_condition.py:44 | odasa6261_0 | ControlFlowNode for use() | | b_condition.py:44 | split_bool1_0 | ControlFlowNode for use() | @@ -168,6 +172,10 @@ | b_condition.py:102 | a_0 | ControlFlowNode for a | | b_condition.py:104 | a_1 | ControlFlowNode for a | | b_condition.py:105 | a_2 | ControlFlowNode for a | +| b_condition.py:109 | x_5 | Exit node for Function method_check | +| b_condition.py:110 | x_0 | ControlFlowNode for x | +| b_condition.py:111 | x_1 | ControlFlowNode for x | +| b_condition.py:113 | x_3 | ControlFlowNode for x | | d_globals.py:0 | D_1 | Exit node for Module code.d_globals | | d_globals.py:0 | Ugly_1 | Exit node for Module code.d_globals | | d_globals.py:0 | X_1 | Exit node for Module code.d_globals | diff --git a/python/ql/test/library-tests/PointsTo/new/Values.expected b/python/ql/test/library-tests/PointsTo/new/Values.expected index d89f6a4fdef..db8da913c00 100644 --- a/python/ql/test/library-tests/PointsTo/new/Values.expected +++ b/python/ql/test/library-tests/PointsTo/new/Values.expected @@ -139,6 +139,7 @@ | b_condition.py:106 | ControlFlowNode for Exception | runtime | builtin-class Exception | builtin-class type | | b_condition.py:106 | ControlFlowNode for Exception() | runtime | Exception() | builtin-class Exception | | b_condition.py:107 | ControlFlowNode for Str | runtime | 'Hello' | builtin-class str | +| b_condition.py:109 | ControlFlowNode for FunctionExpr | import | Function method_check | builtin-class function | | e_temporal.py:2 | ControlFlowNode for ImportExpr | import | Module sys | builtin-class module | | e_temporal.py:4 | ControlFlowNode for FunctionExpr | import | Function f | builtin-class function | | e_temporal.py:5 | ControlFlowNode for Attribute | code/e_temporal.py:12 from import | list object | builtin-class list | diff --git a/python/ql/test/library-tests/PointsTo/new/VarUses.expected b/python/ql/test/library-tests/PointsTo/new/VarUses.expected index 18fb97ea47a..83bf756373e 100644 --- a/python/ql/test/library-tests/PointsTo/new/VarUses.expected +++ b/python/ql/test/library-tests/PointsTo/new/VarUses.expected @@ -55,6 +55,7 @@ | b_condition.py:0 | k | Exit node for Module code.b_condition | | b_condition.py:0 | list | Exit node for Module code.b_condition | | b_condition.py:0 | loop | Exit node for Module code.b_condition | +| b_condition.py:0 | method_check | Exit node for Module code.b_condition | | b_condition.py:0 | not_or_not | Exit node for Module code.b_condition | | b_condition.py:0 | object | Exit node for Module code.b_condition | | b_condition.py:0 | odasa6261 | Exit node for Module code.b_condition | @@ -109,6 +110,7 @@ | b_condition.py:39 | h | ControlFlowNode for thing() | | b_condition.py:39 | k | ControlFlowNode for thing() | | b_condition.py:39 | loop | ControlFlowNode for thing() | +| b_condition.py:39 | method_check | ControlFlowNode for thing() | | b_condition.py:39 | not_or_not | ControlFlowNode for thing() | | b_condition.py:39 | odasa6261 | ControlFlowNode for thing() | | b_condition.py:39 | split_bool1 | ControlFlowNode for thing() | @@ -124,6 +126,7 @@ | b_condition.py:43 | h | ControlFlowNode for use() | | b_condition.py:43 | k | ControlFlowNode for use() | | b_condition.py:43 | loop | ControlFlowNode for use() | +| b_condition.py:43 | method_check | ControlFlowNode for use() | | b_condition.py:43 | not_or_not | ControlFlowNode for use() | | b_condition.py:43 | odasa6261 | ControlFlowNode for use() | | b_condition.py:43 | split_bool1 | ControlFlowNode for use() | @@ -138,6 +141,7 @@ | b_condition.py:44 | h | ControlFlowNode for use() | | b_condition.py:44 | k | ControlFlowNode for use() | | b_condition.py:44 | loop | ControlFlowNode for use() | +| b_condition.py:44 | method_check | ControlFlowNode for use() | | b_condition.py:44 | not_or_not | ControlFlowNode for use() | | b_condition.py:44 | odasa6261 | ControlFlowNode for use() | | b_condition.py:44 | split_bool1 | ControlFlowNode for use() | @@ -202,6 +206,12 @@ | b_condition.py:104 | a | ControlFlowNode for a | | b_condition.py:105 | a | ControlFlowNode for a | | b_condition.py:106 | Exception | ControlFlowNode for Exception | +| b_condition.py:109 | x | Exit node for Function method_check | +| b_condition.py:110 | x | ControlFlowNode for x | +| b_condition.py:111 | use | ControlFlowNode for use | +| b_condition.py:111 | x | ControlFlowNode for x | +| b_condition.py:113 | use | ControlFlowNode for use | +| b_condition.py:113 | x | ControlFlowNode for x | | d_globals.py:0 | D | Exit node for Module code.d_globals | | d_globals.py:0 | Ugly | Exit node for Module code.d_globals | | d_globals.py:0 | X | Exit node for Module code.d_globals | diff --git a/python/ql/test/library-tests/PointsTo/new/code/b_condition.py b/python/ql/test/library-tests/PointsTo/new/code/b_condition.py index 7574955ca96..d2d5e78d598 100644 --- a/python/ql/test/library-tests/PointsTo/new/code/b_condition.py +++ b/python/ql/test/library-tests/PointsTo/new/code/b_condition.py @@ -106,3 +106,10 @@ def not_or_not(*a): raise Exception() "Hello" +def method_check(x): + if x.m(): + use(x) + else: + use(x) + +