diff --git a/regression/cbmc-java/phi-merge_uninitialized_values/PhiMergeUninitialized.class b/regression/cbmc-java/phi-merge_uninitialized_values/PhiMergeUninitialized.class new file mode 100644 index 00000000000..1f36e928d7a Binary files /dev/null and b/regression/cbmc-java/phi-merge_uninitialized_values/PhiMergeUninitialized.class differ diff --git a/regression/cbmc-java/phi-merge_uninitialized_values/PhiMergeUninitialized.java b/regression/cbmc-java/phi-merge_uninitialized_values/PhiMergeUninitialized.java new file mode 100644 index 00000000000..9e20f0124d9 --- /dev/null +++ b/regression/cbmc-java/phi-merge_uninitialized_values/PhiMergeUninitialized.java @@ -0,0 +1,54 @@ +public class PhiMergeUninitialized { + + public int dynamicAllocationUninitialized(Boolean trigger) { + + Ephemeral obj; + if (trigger) { + obj = new Ephemeral(42); + } else { + obj = new Aetherial(20); + } + + assert obj.val == 20; + return obj.val; + } + + private Ephemeral field; + + public int fieldUninitialized(Boolean trigger) { + if (trigger) { + field = new Ephemeral(42); + } + + assert field.val == 42; + return field.val; + } + + private static Ephemeral staticField; + + public int staticFieldUninitialized(Boolean trigger) { + if (trigger) { + staticField = new Ephemeral(42); + } else { + staticField = new Aetherial(76); + } + + assert staticField.val == 76; + return staticField.val; + } + + class Ephemeral { + Ephemeral(int value) { + val = value; + } + + int val; + } + + class Aetherial extends Ephemeral { + Aetherial(int value) { + super(value); + } + } +} + diff --git a/regression/cbmc-java/phi-merge_uninitialized_values/field.desc b/regression/cbmc-java/phi-merge_uninitialized_values/field.desc new file mode 100644 index 00000000000..f83a55f6641 --- /dev/null +++ b/regression/cbmc-java/phi-merge_uninitialized_values/field.desc @@ -0,0 +1,16 @@ +CORE +PhiMergeUninitialized.class +--function PhiMergeUninitialized.fieldUninitialized --show-vcc +activate-multi-line-match +^EXIT=0$ +^SIGNAL=0$ +-- +^.*:\s+(dynamic_object|new_tmp)[0-9]+(@[0-9]+)?#0\) +^.*\?\s+(dynamic_object|new_tmp)[0-9]+(@[0-9]+)?#0\s+: +-- +These regexes are making sure that a variable of generation 0 dosen't appear in a phi merge, so the below +statement: + + (guard ? dynamic_object2@3#1 : dynamic_object3@3#0) + +Should not appear. First regex deals with when the gen zero is the latter position, second when it's in the former. \ No newline at end of file diff --git a/regression/cbmc-java/phi-merge_uninitialized_values/local.desc b/regression/cbmc-java/phi-merge_uninitialized_values/local.desc new file mode 100644 index 00000000000..0369f5967a7 --- /dev/null +++ b/regression/cbmc-java/phi-merge_uninitialized_values/local.desc @@ -0,0 +1,16 @@ +CORE +PhiMergeUninitialized.class +--function PhiMergeUninitialized.dynamicAllocationUninitialized --show-vcc +activate-multi-line-match +^EXIT=0$ +^SIGNAL=0$ +-- +^.*:\s+(dynamic_object|new_tmp)[0-9]+(@[0-9]+)?#0\) +^.*\?\s+(dynamic_object|new_tmp)[0-9]+(@[0-9]+)?#0\s+: +-- +These regexes are making sure that a variable of generation 0 dosen't appear in a phi merge, so the below +statement: + + (guard ? dynamic_object2@3#1 : dynamic_object3@3#0) + +Should not appear. First regex deals with when the gen zero is the latter position, second when it's in the former. \ No newline at end of file diff --git a/regression/cbmc-java/phi-merge_uninitialized_values/static_field.desc b/regression/cbmc-java/phi-merge_uninitialized_values/static_field.desc new file mode 100644 index 00000000000..6289e5f872a --- /dev/null +++ b/regression/cbmc-java/phi-merge_uninitialized_values/static_field.desc @@ -0,0 +1,16 @@ +CORE +PhiMergeUninitialized.class +--function PhiMergeUninitialized.staticFieldUninitialized --show-vcc +activate-multi-line-match +^EXIT=0$ +^SIGNAL=0$ +-- +^.*:\s+(dynamic_object|new_tmp)[0-9]+(@[0-9]+)?#0\) +^.*\?\s+(dynamic_object|new_tmp)[0-9]+(@[0-9]+)?#0\s+: +-- +These regexes are making sure that a variable of generation 0 dosen't appear in a phi merge, so the below +statement: + + (guard ? dynamic_object2@3#1 : dynamic_object3@3#0) + +Should not appear. First regex deals with when the gen zero is the latter position, second when it's in the former. \ No newline at end of file diff --git a/regression/cbmc/phi-merge_uninitialized_values/dynamic.desc b/regression/cbmc/phi-merge_uninitialized_values/dynamic.desc new file mode 100644 index 00000000000..a6a1dbd4839 --- /dev/null +++ b/regression/cbmc/phi-merge_uninitialized_values/dynamic.desc @@ -0,0 +1,16 @@ +CORE +test.c +--function dynamicAllocationUninitialized --show-vcc +activate-multi-line-match +^EXIT=0$ +^SIGNAL=0$ +-- +^.*:\s+dynamic_object[0-9]+(@[0-9]+)?#0\) +^.*\?\s+dynamic_object[0-9]+(@[0-9]+)?#0\s+: +-- +These regexes are making sure that a variable of generation 0 dosen't appear in a phi merge, so the below +statement: + + (guard ? dynamic_object2@3#1 : dynamic_object3@3#0) + +Should not appear. First regex deals with when the gen zero is the latter position, second when it's in the former. \ No newline at end of file diff --git a/regression/cbmc/phi-merge_uninitialized_values/global.desc b/regression/cbmc/phi-merge_uninitialized_values/global.desc new file mode 100644 index 00000000000..95483b1acfb --- /dev/null +++ b/regression/cbmc/phi-merge_uninitialized_values/global.desc @@ -0,0 +1,16 @@ +CORE +test.c +--function globalUninitialized --show-vcc +activate-multi-line-match +^EXIT=0$ +^SIGNAL=0$ +-- +^.*:\s+global(@[0-9]+)?#0\) +^.*\?\s+global(@[0-9]+)?#0\s+: +-- +These regexes are making sure that a variable of generation 0 dosen't appear in a phi merge, so the below +statement: + + (guard ? global#1 : global#0) + +Should not appear. First regex deals with when the gen zero is the latter position, second when it's in the former. \ No newline at end of file diff --git a/regression/cbmc/phi-merge_uninitialized_values/local.desc b/regression/cbmc/phi-merge_uninitialized_values/local.desc new file mode 100644 index 00000000000..459d31c32b0 --- /dev/null +++ b/regression/cbmc/phi-merge_uninitialized_values/local.desc @@ -0,0 +1,16 @@ +CORE +test.c +--function localUninitialized --show-vcc +activate-multi-line-match +^EXIT=0$ +^SIGNAL=0$ +-- +^.*:\s+local(@[0-9]+)?#0\) +^.*\?\s+local(@[0-9]+)?#0\s+: +-- +These regexes are making sure that a variable of generation 0 dosen't appear in a phi merge, so the below +statement: + + (guard ? local#1 : local#0) + +Should not appear. First regex deals with when the gen zero is the latter position, second when it's in the former. \ No newline at end of file diff --git a/regression/cbmc/phi-merge_uninitialized_values/static_local.desc b/regression/cbmc/phi-merge_uninitialized_values/static_local.desc new file mode 100644 index 00000000000..ce1ed0f81c8 --- /dev/null +++ b/regression/cbmc/phi-merge_uninitialized_values/static_local.desc @@ -0,0 +1,16 @@ +CORE +test.c +--function staticLocalUninitialized --show-vcc +activate-multi-line-match +^EXIT=0$ +^SIGNAL=0$ +-- +^.*:\s+staticLocal(@[0-9]+)?#0\) +^.*\?\s+staticLocal(@[0-9]+)?#0\s+: +-- +These regexes are making sure that a variable of generation 0 dosen't appear in a phi merge, so the below +statement: + + (guard ? staticLocal#1 : dynamic_object#0) + +Should not appear. First regex deals with when the gen zero is the latter position, second when it's in the former. \ No newline at end of file diff --git a/regression/cbmc/phi-merge_uninitialized_values/test.c b/regression/cbmc/phi-merge_uninitialized_values/test.c new file mode 100644 index 00000000000..1dcdd7194a0 --- /dev/null +++ b/regression/cbmc/phi-merge_uninitialized_values/test.c @@ -0,0 +1,56 @@ +#include +#include + +void dynamicAllocationUninitialized(int trigger) +{ + int *obj; + if(trigger) + { + obj = (int *)malloc(sizeof(int)); + *obj = 42; + } + else + { + obj = (int *)malloc(sizeof(int)); + *obj = 76; + } + + assert(*obj == 42); +} + +int global; +void globalUninitialized(int trigger) +{ + if(trigger) + { + global = 44; + } + else + { + global = 20; + } + + assert(global == 44); +} + +void staticLocalUninitialized(int trigger) +{ + static int staticLocal; + if(trigger) + { + staticLocal = 43; + } + + assert(staticLocal == 43); +} + +void localUninitialized(int trigger) +{ + int local; + if(trigger) + { + local = 24; + } + + assert(local == 24); +} diff --git a/regression/test.pl b/regression/test.pl index 92639accd3f..d137e2dbb84 100755 --- a/regression/test.pl +++ b/regression/test.pl @@ -174,7 +174,7 @@ ($$$$$$$$$) binmode $fh; my $whole_file = <$fh>; $whole_file =~ s/\r\n/\n/g; - my $is_match = $whole_file =~ /$result/; + my $is_match = $whole_file =~ /$result/m; $r = ($included ? !$is_match : $is_match); } else diff --git a/src/goto-symex/goto_symex.cpp b/src/goto-symex/goto_symex.cpp index bfd37cee334..3a5bea45c52 100644 --- a/src/goto-symex/goto_symex.cpp +++ b/src/goto-symex/goto_symex.cpp @@ -22,13 +22,19 @@ void goto_symext::do_simplify(exprt &expr) simplify(expr, ns); } +nondet_symbol_exprt goto_symext::build_symex_nondet(typet &type) +{ + irep_idt identifier = "symex::nondet" + std::to_string(nondet_count++); + nondet_symbol_exprt new_expr(identifier, type); + return new_expr; +} + void goto_symext::replace_nondet(exprt &expr) { if(expr.id()==ID_side_effect && expr.get(ID_statement)==ID_nondet) { - irep_idt identifier="symex::nondet"+std::to_string(nondet_count++); - nondet_symbol_exprt new_expr(identifier, expr.type()); + nondet_symbol_exprt new_expr = build_symex_nondet(expr.type()); new_expr.add_source_location()=expr.source_location(); expr.swap(new_expr); } diff --git a/src/goto-symex/goto_symex.h b/src/goto-symex/goto_symex.h index 7811a4497eb..335d477ce96 100644 --- a/src/goto-symex/goto_symex.h +++ b/src/goto-symex/goto_symex.h @@ -368,6 +368,8 @@ class goto_symext exprt &code, const irep_idt &identifier); + nondet_symbol_exprt build_symex_nondet(typet &type); + // exceptions void symex_throw(statet &); void symex_catch(statet &); diff --git a/src/goto-symex/symex_builtin_functions.cpp b/src/goto-symex/symex_builtin_functions.cpp index f827f1ecaea..1fff82d17fa 100644 --- a/src/goto-symex/symex_builtin_functions.cpp +++ b/src/goto-symex/symex_builtin_functions.cpp @@ -184,6 +184,12 @@ void goto_symext::symex_allocate( else throw "failed to zero initialize dynamic object"; } + else + { + exprt nondet = build_symex_nondet(object_type); + code_assignt assignment(value_symbol.symbol_expr(), nondet); + symex_assign(state, assignment); + } exprt rhs; diff --git a/src/goto-symex/symex_goto.cpp b/src/goto-symex/symex_goto.cpp index 5951cd8284c..409de30c2c6 100644 --- a/src/goto-symex/symex_goto.cpp +++ b/src/goto-symex/symex_goto.cpp @@ -443,10 +443,22 @@ void goto_symext::phi_function( exprt rhs; + // Don't add a conditional to the assignment when: + // 1. Either guard is false, so we can't follow that branch. + // 2. Either identifier is of generation zero, and so hasn't been + // initialized and therefor an invalid target. if(dest_state.guard.is_false()) rhs=goto_state_rhs; else if(goto_state.guard.is_false()) rhs=dest_state_rhs; + else if(goto_state.level2_current_count(l1_identifier) == 0) + { + rhs = dest_state_rhs; + } + else if(dest_state.level2.current_count(l1_identifier) == 0) + { + rhs = goto_state_rhs; + } else { rhs=if_exprt(diff_guard.as_expr(), goto_state_rhs, dest_state_rhs);