diff --git a/infer/src/pulse/PulseModelsPython.ml b/infer/src/pulse/PulseModelsPython.ml index d230c8c216..f799b3207c 100644 --- a/infer/src/pulse/PulseModelsPython.ml +++ b/infer/src/pulse/PulseModelsPython.ml @@ -109,6 +109,11 @@ let store_fast name locals value : model = start_model @@ fun () -> Dict.set locals name value +let store_global name globals value : model = + let open DSL.Syntax in + start_model @@ fun () -> Dict.set globals name value + + let store_name name locals _globals value : model = let open DSL.Syntax in start_model @@ fun () -> Dict.set locals name value @@ -135,6 +140,8 @@ let matchers : matcher list = ; -"$builtins" &:: "py_make_none" <>--> make_none ; -"$builtins" &:: "py_store_fast" <>$ capt_arg_payload $+ capt_arg_payload $+ capt_arg_payload $--> store_fast + ; -"$builtins" &:: "py_store_global" <>$ capt_arg_payload $+ capt_arg_payload $+ capt_arg_payload + $--> store_global ; -"$builtins" &:: "py_store_name" <>$ capt_arg_payload $+ capt_arg_payload $+ capt_arg_payload $+ capt_arg_payload $--> store_name ] |> List.map ~f:(ProcnameDispatcher.Call.contramap_arg_payload ~f:ValueOrigin.addr_hist) diff --git a/infer/tests/codetoanalyze/python/pulse/issues.exp b/infer/tests/codetoanalyze/python/pulse/issues.exp index 07e2afb97e..cd2ec8b929 100644 --- a/infer/tests/codetoanalyze/python/pulse/issues.exp +++ b/infer/tests/codetoanalyze/python/pulse/issues.exp @@ -2,3 +2,6 @@ level0.py, level0::__module_body__, 15, TAINT_ERROR, no_bucket, ERROR, [in call level1.py, level1::basic_flow_bad, 2, TAINT_ERROR, no_bucket, ERROR, [in call to `closure:level1:0.call`,source of the taint here: value returned from `level1::taint_source` with kind `Simple`,return from call to `closure:level1:0.call`,when calling `closure:level1:1.call` here,flows to this sink: value passed as argument `#1` to `level1::taint_sink` with kind `Simple`], source: level1::taint_source, sink: level1::taint_sink, tainted expression: UNKNOWN level1.py, level1::call_fst_bad, 2, TAINT_ERROR, no_bucket, ERROR, [in call to `closure:level1:0.call`,source of the taint here: value returned from `level1::taint_source` with kind `Simple`,return from call to `closure:level1:0.call`,when calling `closure:level1:1.call` here,flows to this sink: value passed as argument `#1` to `level1::taint_sink` with kind `Simple`], source: level1::taint_source, sink: level1::taint_sink, tainted expression: UNKNOWN level1.py, level1::call_sink_fst_arg_bad, 1, TAINT_ERROR, no_bucket, ERROR, [in call to `closure:level1:0.call`,source of the taint here: value returned from `level1::taint_source` with kind `Simple`,return from call to `closure:level1:0.call`,when calling `closure:level1:7.call` here,when calling `level1::sink_fst_arg` here,when calling `closure:level1:1.call` here,flows to this sink: value passed as argument `#1` to `level1::taint_sink` with kind `Simple`], source: level1::taint_source, sink: level1::taint_sink, tainted expression: closure:level1:0.call() +level1.py, level1::call_taint_sink_on_global_bad2, 3, TAINT_ERROR, no_bucket, ERROR, [in call to `closure:level1:0.call`,source of the taint here: value returned from `level1::taint_source` with kind `Simple`,return from call to `closure:level1:0.call`,when calling `closure:level1:1.call` here,flows to this sink: value passed as argument `#1` to `level1::taint_sink` with kind `Simple`], source: level1::taint_source, sink: level1::taint_sink, tainted expression: UNKNOWN +level1.py, level1::__module_body__, 60, TAINT_ERROR, no_bucket, ERROR, [in call to `closure:level1:2.call`,in call to `level1::basic_flow_bad`,in call to `closure:level1:0.call`,source of the taint here: value returned from `level1::taint_source` with kind `Simple`,return from call to `closure:level1:0.call`,return from call to `level1::basic_flow_bad`,return from call to `closure:level1:2.call`,when calling `closure:level1:10.call` here,when calling `level1::call_taint_sink_on_global_bad1` here,when calling `closure:level1:1.call` here,flows to this sink: value passed as argument `#1` to `level1::taint_sink` with kind `Simple`], source: level1::taint_source, sink: level1::taint_sink, tainted expression: globals->call_taint_sink_on_global_bad1->globals->g +level1.py, level1::__module_body__, 63, TAINT_ERROR, no_bucket, ERROR, [in call to `closure:level1:2.call`,in call to `level1::basic_flow_bad`,in call to `closure:level1:0.call`,source of the taint here: value returned from `level1::taint_source` with kind `Simple`,return from call to `closure:level1:0.call`,return from call to `level1::basic_flow_bad`,return from call to `closure:level1:2.call`,when calling `closure:level1:12.call` here,when calling `level1::call_taint_sink_on_global_bad2` here,when calling `closure:level1:1.call` here,flows to this sink: value passed as argument `#0` to `level1::taint_sink` with kind `Simple`], source: level1::taint_source, sink: level1::taint_sink, tainted expression: globals->call_taint_sink_on_global_bad2->globals->taint_source->globals->taint_sink->globals diff --git a/infer/tests/codetoanalyze/python/pulse/level1.py b/infer/tests/codetoanalyze/python/pulse/level1.py index 5d3d3a11f1..8d28ba6cee 100644 --- a/infer/tests/codetoanalyze/python/pulse/level1.py +++ b/infer/tests/codetoanalyze/python/pulse/level1.py @@ -37,7 +37,7 @@ def call_sink_fst_arg_bad(untainted) -> None: def call_sink_fst_arg_ok(untainted) -> None: sink_fst_arg(untainted, taint_source()) -def FN_call_taint_sink_on_global_bad1(): +def call_taint_sink_on_global_bad1(): global g taint_sink(g) @@ -45,7 +45,7 @@ def call_taint_sink_on_global_ok(): global g taint_sink(g) -def FN_call_taint_sink_on_global_bad2(): +def call_taint_sink_on_global_bad2(): global g g = taint_source() taint_sink(g) @@ -58,7 +58,7 @@ def FN_call_taint_sink_on_global_bad2(): call_sink_fst_arg_bad(0) call_sink_fst_arg_ok(0) g = taint_source() -FN_call_taint_sink_on_global_bad1() +call_taint_sink_on_global_bad1() g = 0 call_taint_sink_on_global_ok() -FN_call_taint_sink_on_global_bad2() +call_taint_sink_on_global_bad2()