[impurity] Consider exited functions as impure

Summary: Consider functions that simply exit as impure by extending the impurity domain with `AbstractDomain.BooleanOr` that signifies whether the program exited.

Reviewed By: skcho

Differential Revision: D20941628

fbshipit-source-id: 19bc90e66
master
Ezgi Çiçek 5 years ago committed by Facebook GitHub Bot
parent b29d1a2f5f
commit 8d44265ca1

@ -139,23 +139,27 @@ let is_modeled_pure tenv pname =
(** Given Pulse summary, extract impurity info, i.e. parameters and global variables that are (** Given Pulse summary, extract impurity info, i.e. parameters and global variables that are
modified by the function and skipped functions. *) modified by the function and skipped functions. *)
let extract_impurity tenv pdesc (exec_state : PulseExecutionState.t) : ImpurityDomain.t = let extract_impurity tenv pdesc (exec_state : PulseExecutionState.t) : ImpurityDomain.t =
match exec_state with let astate, exited =
| ExitProgram astate | ContinueProgram astate -> match exec_state with
(* TODO: consider impure even though the program only exits with pre=post *) | ExitProgram astate ->
let pre_heap = (PulseAbductiveDomain.get_pre astate).BaseDomain.heap in (astate, true)
let post = PulseAbductiveDomain.get_post astate in | ContinueProgram astate ->
let post_stack = post.BaseDomain.stack in (astate, false)
let pname = Procdesc.get_proc_name pdesc in in
let modified_params = let pre_heap = (PulseAbductiveDomain.get_pre astate).BaseDomain.heap in
Procdesc.get_formals pdesc |> get_modified_params pname post_stack pre_heap post let post = PulseAbductiveDomain.get_post astate in
in let post_stack = post.BaseDomain.stack in
let modified_globals = get_modified_globals pre_heap post post_stack in let pname = Procdesc.get_proc_name pdesc in
let skipped_calls = let modified_params =
PulseAbductiveDomain.get_skipped_calls astate Procdesc.get_formals pdesc |> get_modified_params pname post_stack pre_heap post
|> PulseAbductiveDomain.SkippedCalls.filter (fun proc_name _ -> in
Purity.should_report proc_name && not (is_modeled_pure tenv proc_name) ) let modified_globals = get_modified_globals pre_heap post post_stack in
in let skipped_calls =
{modified_globals; modified_params; skipped_calls} PulseAbductiveDomain.get_skipped_calls astate
|> PulseAbductiveDomain.SkippedCalls.filter (fun proc_name _ ->
Purity.should_report proc_name && not (is_modeled_pure tenv proc_name) )
in
{modified_globals; modified_params; skipped_calls; exited}
let checker {exe_env; Callbacks.summary} : Summary.t = let checker {exe_env; Callbacks.summary} : Summary.t =

@ -20,34 +20,39 @@ module ModifiedVar = struct
end end
module ModifiedVarSet = AbstractDomain.FiniteSet (ModifiedVar) module ModifiedVarSet = AbstractDomain.FiniteSet (ModifiedVar)
module Exited = AbstractDomain.BooleanOr
type t = type t =
{ modified_params: ModifiedVarSet.t { modified_params: ModifiedVarSet.t
; modified_globals: ModifiedVarSet.t ; modified_globals: ModifiedVarSet.t
; skipped_calls: SkippedCalls.t } ; skipped_calls: SkippedCalls.t
; exited: Exited.t }
let is_pure {modified_globals; modified_params; skipped_calls} = let is_pure {modified_globals; modified_params; skipped_calls; exited} =
ModifiedVarSet.is_empty modified_globals ModifiedVarSet.is_empty modified_globals
&& ModifiedVarSet.is_empty modified_params && ModifiedVarSet.is_empty modified_params
&& SkippedCalls.is_empty skipped_calls && SkippedCalls.is_empty skipped_calls
&& Exited.is_bottom exited
let pure = let pure =
{ modified_params= ModifiedVarSet.empty { modified_params= ModifiedVarSet.empty
; modified_globals= ModifiedVarSet.empty ; modified_globals= ModifiedVarSet.empty
; skipped_calls= SkippedCalls.empty } ; skipped_calls= SkippedCalls.empty
; exited= Exited.bottom }
let join astate1 astate2 = let join astate1 astate2 =
if phys_equal astate1 astate2 then astate1 if phys_equal astate1 astate2 then astate1
else else
let {modified_globals= mg1; modified_params= mp1; skipped_calls= uk1} = astate1 in let {modified_globals= mg1; modified_params= mp1; skipped_calls= uk1; exited= e1} = astate1 in
let {modified_globals= mg2; modified_params= mp2; skipped_calls= uk2} = astate2 in let {modified_globals= mg2; modified_params= mp2; skipped_calls= uk2; exited= e2} = astate2 in
PhysEqual.optim2 PhysEqual.optim2
~res: ~res:
{ modified_globals= ModifiedVarSet.join mg1 mg2 { modified_globals= ModifiedVarSet.join mg1 mg2
; modified_params= ModifiedVarSet.join mp1 mp2 ; modified_params= ModifiedVarSet.join mp1 mp2
; skipped_calls= SkippedCalls.union (fun _pname t1 _ -> Some t1) uk1 uk2 } ; skipped_calls= SkippedCalls.union (fun _pname t1 _ -> Some t1) uk1 uk2
; exited= Exited.join e1 e2 }
astate1 astate2 astate1 astate2

@ -19,10 +19,13 @@ module ModifiedVarSet : sig
include AbstractDomain.FiniteSetS with type elt = ModifiedVar.t include AbstractDomain.FiniteSetS with type elt = ModifiedVar.t
end end
module Exited = AbstractDomain.BooleanOr
type t = type t =
{ modified_params: ModifiedVarSet.t { modified_params: ModifiedVarSet.t
; modified_globals: ModifiedVarSet.t ; modified_globals: ModifiedVarSet.t
; skipped_calls: PulseAbductiveDomain.SkippedCalls.t } ; skipped_calls: PulseAbductiveDomain.SkippedCalls.t
; exited: Exited.t }
val pure : t val pure : t

@ -8,13 +8,13 @@
int x; int x;
void exit_positive_impure_FN(int a[10], int b) { void exit_positive_impure(int a[10], int b) {
if (b > 0) { if (b > 0) {
exit(0); exit(0);
} }
} }
void unreachable_impure_FN(int a[10], int b) { void unreachable_impure(int a[10]) {
exit_positive_impure_FN(a, 10); exit_positive_impure(a, 10);
x = 9; x = 9; // unreachable
} }

@ -7,6 +7,8 @@ codetoanalyze/cpp/impurity/array_test.cpp, call_array_mod_impure, 0, IMPURE_FUNC
codetoanalyze/cpp/impurity/array_test.cpp, call_array_mod_with_fresh_pure_FP, 0, IMPURE_FUNCTION, no_bucket, ERROR, [Impure function call_array_mod_with_fresh_pure_FP with empty pulse summary] codetoanalyze/cpp/impurity/array_test.cpp, call_array_mod_with_fresh_pure_FP, 0, IMPURE_FUNCTION, no_bucket, ERROR, [Impure function call_array_mod_with_fresh_pure_FP with empty pulse summary]
codetoanalyze/cpp/impurity/array_test.cpp, modify_direct_impure, 0, IMPURE_FUNCTION, no_bucket, ERROR, [Impure function modify_direct_impure,parameter `array` modified here] codetoanalyze/cpp/impurity/array_test.cpp, modify_direct_impure, 0, IMPURE_FUNCTION, no_bucket, ERROR, [Impure function modify_direct_impure,parameter `array` modified here]
codetoanalyze/cpp/impurity/array_test.cpp, modify_ptr_impure, 0, IMPURE_FUNCTION, no_bucket, ERROR, [Impure function modify_ptr_impure,parameter `array` modified here] codetoanalyze/cpp/impurity/array_test.cpp, modify_ptr_impure, 0, IMPURE_FUNCTION, no_bucket, ERROR, [Impure function modify_ptr_impure,parameter `array` modified here]
codetoanalyze/cpp/impurity/exit_test.cpp, exit_positive_impure, 0, IMPURE_FUNCTION, no_bucket, ERROR, [Impure function exit_positive_impure]
codetoanalyze/cpp/impurity/exit_test.cpp, unreachable_impure, 0, IMPURE_FUNCTION, no_bucket, ERROR, [Impure function unreachable_impure]
codetoanalyze/cpp/impurity/global_test.cpp, call_modify_global, 0, IMPURE_FUNCTION, no_bucket, ERROR, [Impure function call_modify_global,when calling `modify_global_array_impure` here,global variable `a` modified here,when calling `modify_global_primitive_impure` here,global variable `x` modified here] codetoanalyze/cpp/impurity/global_test.cpp, call_modify_global, 0, IMPURE_FUNCTION, no_bucket, ERROR, [Impure function call_modify_global,when calling `modify_global_array_impure` here,global variable `a` modified here,when calling `modify_global_primitive_impure` here,global variable `x` modified here]
codetoanalyze/cpp/impurity/global_test.cpp, local_static_var_impure, 0, IMPURE_FUNCTION, no_bucket, ERROR, [Impure function local_static_var_impure,global variable `local_static_var_impure.arr` modified here] codetoanalyze/cpp/impurity/global_test.cpp, local_static_var_impure, 0, IMPURE_FUNCTION, no_bucket, ERROR, [Impure function local_static_var_impure,global variable `local_static_var_impure.arr` modified here]
codetoanalyze/cpp/impurity/global_test.cpp, modify_global_array_impure, 0, IMPURE_FUNCTION, no_bucket, ERROR, [Impure function modify_global_array_impure,global variable `a` modified here] codetoanalyze/cpp/impurity/global_test.cpp, modify_global_array_impure, 0, IMPURE_FUNCTION, no_bucket, ERROR, [Impure function modify_global_array_impure,global variable `a` modified here]

@ -89,13 +89,10 @@ class Test {
return System.nanoTime(); return System.nanoTime();
} }
// In pulse, we get Exited summary where pre=post void exit_impure() {
// TODO: change impurity to track exit as impure
void exit_impure_FN() {
System.exit(1); System.exit(1);
} }
// In pulse, we get Exited summary where pre=post
void modify_exit_impure(int[] a) { void modify_exit_impure(int[] a) {
a[0] = 0; a[0] = 0;
System.exit(1); System.exit(1);

@ -34,6 +34,7 @@ codetoanalyze/java/impurity/PurityModeled.java, PurityModeled.write_impure():voi
codetoanalyze/java/impurity/Test.java, Test.Test(int):void, 0, IMPURE_FUNCTION, no_bucket, ERROR, [Impure function void Test.Test(int),global variable `Test` modified here] codetoanalyze/java/impurity/Test.java, Test.Test(int):void, 0, IMPURE_FUNCTION, no_bucket, ERROR, [Impure function void Test.Test(int),global variable `Test` modified here]
codetoanalyze/java/impurity/Test.java, Test.alias_impure(int[],int,int):void, 0, IMPURE_FUNCTION, no_bucket, ERROR, [Impure function void Test.alias_impure(int[],int,int),parameter `array` modified here] codetoanalyze/java/impurity/Test.java, Test.alias_impure(int[],int,int):void, 0, IMPURE_FUNCTION, no_bucket, ERROR, [Impure function void Test.alias_impure(int[],int,int),parameter `array` modified here]
codetoanalyze/java/impurity/Test.java, Test.call_impure_impure(int):void, 0, IMPURE_FUNCTION, no_bucket, ERROR, [Impure function void Test.call_impure_impure(int),when calling `void Test.set_impure(int,int)` here,parameter `this` modified here] codetoanalyze/java/impurity/Test.java, Test.call_impure_impure(int):void, 0, IMPURE_FUNCTION, no_bucket, ERROR, [Impure function void Test.call_impure_impure(int),when calling `void Test.set_impure(int,int)` here,parameter `this` modified here]
codetoanalyze/java/impurity/Test.java, Test.exit_impure():void, 0, IMPURE_FUNCTION, no_bucket, ERROR, [Impure function void Test.exit_impure()]
codetoanalyze/java/impurity/Test.java, Test.global_array_set_impure(int,int):void, 0, IMPURE_FUNCTION, no_bucket, ERROR, [Impure function void Test.global_array_set_impure(int,int),global variable `Test` modified here] codetoanalyze/java/impurity/Test.java, Test.global_array_set_impure(int,int):void, 0, IMPURE_FUNCTION, no_bucket, ERROR, [Impure function void Test.global_array_set_impure(int,int),global variable `Test` modified here]
codetoanalyze/java/impurity/Test.java, Test.local_field_write_impure(Test):void, 0, IMPURE_FUNCTION, no_bucket, ERROR, [Impure function void Test.local_field_write_impure(Test),parameter `x` modified here] codetoanalyze/java/impurity/Test.java, Test.local_field_write_impure(Test):void, 0, IMPURE_FUNCTION, no_bucket, ERROR, [Impure function void Test.local_field_write_impure(Test),parameter `x` modified here]
codetoanalyze/java/impurity/Test.java, Test.modify_exit_impure(int[]):void, 0, IMPURE_FUNCTION, no_bucket, ERROR, [Impure function void Test.modify_exit_impure(int[]),parameter `a` modified here] codetoanalyze/java/impurity/Test.java, Test.modify_exit_impure(int[]):void, 0, IMPURE_FUNCTION, no_bucket, ERROR, [Impure function void Test.modify_exit_impure(int[]),parameter `a` modified here]

Loading…
Cancel
Save