Skip to content

Commit 148a8b5

Browse files
committed
L1 renaming at each declaration
This was done up until c8f0f7b. The (observable) problem tackled here is that objects declared in loops got the same L1 name, which implies they had the same address. Thus objects were spuriously reported as dead when their address was taken, because a pointer to the latest (live) object would be the same as one to an earlier (genuinely dead) object. A side effect of this change is objects generated for test suites now have L1 indices, as witnessed in the pointer-function-parameters test.
1 parent e066a89 commit 148a8b5

File tree

11 files changed

+100
-71
lines changed

11 files changed

+100
-71
lines changed

regression/cbmc-cover/pointer-function-parameters/test.desc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ main.c
44
^\*\* 5 of 5 covered \(100\.0%\)$
55
^Test suite:$
66
^(tmp(\$\d+)?=[^,]*, a=\(\(signed int \*\)NULL\))|(a=\(\(signed int \*\)NULL\), tmp(\$\d+)?=[^,]*)$
7-
^(a=&tmp(\$\d+)?!0, tmp(\$\d+)?=4)|(tmp(\$\d+)?=4, a=&tmp(\$\d+)?!0)$
8-
^(a=&tmp(\$\d+)?!0, tmp(\$\d+)?=([012356789][0-9]*|4[0-9]+))|(tmp(\$\d+)?=([012356789][0-9]*|4[0-9]+), a=&tmp(\$\d+)?!0)$
7+
^(a=&tmp(\$\d+)?!0@1, tmp(\$\d+)?=4)|(tmp(\$\d+)?=4, a=&tmp(\$\d+)?!0@1)$
8+
^(a=&tmp(\$\d+)?!0@1, tmp(\$\d+)?=([012356789][0-9]*|4[0-9]+))|(tmp(\$\d+)?=([012356789][0-9]*|4[0-9]+), a=&tmp(\$\d+)?!0@1)$
99
^EXIT=0$
1010
^SIGNAL=0$
1111
--
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
int g;
2+
3+
int main()
4+
{
5+
for(int i = 0; i < 4; ++i)
6+
{
7+
int *x;
8+
*&x = &g;
9+
}
10+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CORE
2+
main.c
3+
--pointer-check
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^VERIFICATION SUCCESSFUL$
7+
--
8+
^warning: ignoring

regression/cbmc/vla3/test.desc

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,4 @@ main.c
77
--
88
^warning: ignoring
99
--
10-
Renaming is inconsistent across loop iterations as we map L1 names to types, but
11-
do not actually introduce new L1 ids each time we declare an object.
10+
The array decision procedure does not yet handle member expressions.

src/goto-programs/goto_clean_expr.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@ symbol_exprt goto_convertt::make_compound_literal(
4545

4646
// The lifetime of compound literals is really that of
4747
// the block they are in.
48-
copy(code_declt(result), DECL, dest);
48+
if(!new_symbol.is_static_lifetime)
49+
copy(code_declt(result), DECL, dest);
4950

5051
code_assignt code_assign(result, expr);
5152
code_assign.add_source_location()=source_location;

src/goto-symex/goto_symex_state.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -842,3 +842,35 @@ void goto_statet::output_propagation_map(std::ostream &out)
842842
out << name_value.first << " <- " << format(name_value.second) << "\n";
843843
}
844844
}
845+
846+
void goto_symex_statet::add_object(
847+
ssa_exprt &ssa,
848+
std::size_t l1_index,
849+
const namespacet &ns,
850+
const field_sensitivityt &field_sensitivity)
851+
{
852+
framet &frame = top();
853+
854+
const irep_idt l0_name = ssa.get_identifier();
855+
856+
// save old L1 name, if any
857+
auto c_it = level1.current_names.find(l0_name);
858+
859+
if(c_it != level1.current_names.end())
860+
{
861+
frame.old_level1.emplace(l0_name, c_it->second);
862+
c_it->second = std::make_pair(ssa, l1_index);
863+
}
864+
else
865+
{
866+
c_it = level1.current_names.emplace(l0_name, std::make_pair(ssa, l1_index))
867+
.first;
868+
}
869+
870+
rename(ssa, ns, field_sensitivity, goto_symex_statet::L1);
871+
const irep_idt &l1_name = ssa.get_identifier();
872+
873+
// unique -- store
874+
if(!frame.local_objects.insert(l1_name).second)
875+
PRECONDITION(false);
876+
}

src/goto-symex/goto_symex_state.h

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -148,9 +148,6 @@ class goto_symex_statet final : public goto_statet
148148

149149
symex_target_equationt *symex_target;
150150

151-
// we remember all L1 renamings
152-
std::set<irep_idt> l1_history;
153-
154151
symex_level0t level0;
155152
symex_level1t level1;
156153

@@ -269,6 +266,14 @@ class goto_symex_statet final : public goto_statet
269266

270267
const framet &previous_frame() { return *(--(--call_stack().end())); }
271268

269+
/// Turn L0-renamed \p ssa into an L1-renamed SSA expression with an L1 index
270+
/// \p l1_index that must not have previously been used.
271+
void add_object(
272+
ssa_exprt &ssa,
273+
std::size_t l1_index,
274+
const namespacet &ns,
275+
const field_sensitivityt &field_sensitivity);
276+
272277
void print_backtrace(std::ostream &) const;
273278

274279
// threads

src/goto-symex/path_storage.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,11 +90,24 @@ class path_storaget
9090
/// Counter for nondet objects, which require unique names
9191
symex_nondet_generatort build_symex_nondet;
9292

93+
/// Provide a unique index for a given \p id, starting from \p minimum_index.
94+
std::size_t get_unique_index(const irep_idt &id, std::size_t minimum_index)
95+
{
96+
auto entry = unique_index_map.emplace(id, minimum_index);
97+
98+
if(!entry.second)
99+
entry.first->second = std::max(entry.first->second + 1, minimum_index);
100+
101+
return entry.first->second;
102+
}
103+
93104
private:
94105
// Derived classes should override these methods, allowing the base class to
95106
// enforce preconditions.
96107
virtual patht &private_peek() = 0;
97108
virtual void private_pop() = 0;
109+
110+
std::unordered_map<irep_idt, std::size_t> unique_index_map;
98111
};
99112

100113
/// \brief LIFO save queue: depth-first search, try to finish paths

src/goto-symex/symex_decl.cpp

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,14 @@ void goto_symext::symex_decl(statet &state)
3434

3535
void goto_symext::symex_decl(statet &state, const symbol_exprt &expr)
3636
{
37-
// We increase the L2 renaming to make these non-deterministic.
38-
// We also prevent propagation of old values.
37+
// each declaration introduces a new object, which we record as a fresh L1
38+
// index
3939

4040
ssa_exprt ssa(expr);
41-
state.rename(ssa, ns, field_sensitivity, goto_symex_statet::L1);
41+
state.rename(ssa, ns, field_sensitivity, goto_symex_statet::L0);
42+
const std::size_t fresh_l1_index =
43+
path_storage.get_unique_index(ssa.get_identifier(), 1);
44+
state.add_object(ssa, fresh_l1_index, ns, field_sensitivity);
4245
const irep_idt &l1_identifier=ssa.get_identifier();
4346

4447
// rename type to L2
@@ -62,16 +65,11 @@ void goto_symext::symex_decl(statet &state, const symbol_exprt &expr)
6265
state.value_set.assign(ssa, rhs, ns, true, false);
6366
}
6467

65-
// prevent propagation
66-
state.propagation.erase(l1_identifier);
67-
6868
// L2 renaming
69-
// inlining may yield multiple declarations of the same identifier
70-
// within the same L1 context
71-
const auto level2_it =
72-
state.level2.current_names.emplace(l1_identifier, std::make_pair(ssa, 0))
73-
.first;
74-
symex_renaming_levelt::increase_counter(level2_it);
69+
bool is_new =
70+
state.level2.current_names.emplace(l1_identifier, std::make_pair(ssa, 1))
71+
.second;
72+
CHECK_RETURN(is_new);
7573
const bool record_events=state.record_events;
7674
state.record_events=false;
7775
state.rename(ssa, ns, field_sensitivity);

src/goto-symex/symex_function_call.cpp

Lines changed: 11 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ Author: Daniel Kroening, [email protected]
2121
static void locality(
2222
const irep_idt &function_identifier,
2323
goto_symext::statet &state,
24+
path_storaget &path_storage,
2425
const goto_functionst::goto_functiont &goto_function,
2526
const namespacet &ns,
2627
const field_sensitivityt &field_sensitivity);
@@ -306,7 +307,8 @@ void goto_symext::symex_function_call_code(
306307
framet &frame = state.new_frame();
307308

308309
// preserve locality of local variables
309-
locality(identifier, state, goto_function, ns, field_sensitivity);
310+
locality(
311+
identifier, state, path_storage, goto_function, ns, field_sensitivity);
310312

311313
// assign actuals to formal parameters
312314
parameter_assignments(identifier, goto_function, state, arguments);
@@ -381,11 +383,12 @@ void goto_symext::symex_end_of_function(statet &state)
381383
pop_frame(state);
382384
}
383385

384-
/// preserves locality of local variables of a given function by applying L1
385-
/// renaming to the local identifiers
386+
/// preserves locality of parameters of a given function by applying L1
387+
/// renaming to them
386388
static void locality(
387389
const irep_idt &function_identifier,
388390
goto_symext::statet &state,
391+
path_storaget &path_storage,
389392
const goto_functionst::goto_functiont &goto_function,
390393
const namespacet &ns,
391394
const field_sensitivityt &field_sensitivity)
@@ -394,57 +397,15 @@ static void locality(
394397
state.threads[state.source.thread_nr].function_frame[function_identifier];
395398
frame_nr++;
396399

397-
std::set<irep_idt> local_identifiers;
398-
399-
get_local_identifiers(goto_function, local_identifiers);
400-
401-
framet &frame = state.top();
402-
403-
for(std::set<irep_idt>::const_iterator
404-
it=local_identifiers.begin();
405-
it!=local_identifiers.end();
406-
it++)
400+
for(const auto &param : goto_function.type.parameters())
407401
{
408402
// get L0 name
409-
ssa_exprt ssa(ns.lookup(*it).symbol_expr());
403+
ssa_exprt ssa(ns.lookup(param.get_identifier()).symbol_expr());
410404
state.rename(ssa, ns, field_sensitivity, goto_symex_statet::L0);
411-
const irep_idt l0_name=ssa.get_identifier();
412-
413-
// save old L1 name for popping the frame
414-
auto c_it = state.level1.current_names.find(l0_name);
415-
416-
if(c_it != state.level1.current_names.end())
417-
{
418-
frame.old_level1.emplace(l0_name, c_it->second);
419-
c_it->second = std::make_pair(ssa, frame_nr);
420-
}
421-
else
422-
{
423-
c_it = state.level1.current_names
424-
.emplace(l0_name, std::make_pair(ssa, frame_nr))
425-
.first;
426-
}
427-
428-
// do L1 renaming -- these need not be unique, as
429-
// identifiers may be shared among functions
430-
// (e.g., due to inlining or other code restructuring)
431-
432-
state.rename(ssa, ns, field_sensitivity, goto_symex_statet::L1);
433-
434-
irep_idt l1_name=ssa.get_identifier();
435-
unsigned offset=0;
436-
437-
while(state.l1_history.find(l1_name)!=state.l1_history.end())
438-
{
439-
symex_renaming_levelt::increase_counter(c_it);
440-
++offset;
441-
ssa.set_level_1(frame_nr+offset);
442-
l1_name=ssa.get_identifier();
443-
}
444405

445-
// now unique -- store
446-
frame.local_objects.insert(l1_name);
447-
state.l1_history.insert(l1_name);
406+
const std::size_t fresh_l1_index =
407+
path_storage.get_unique_index(ssa.get_identifier(), frame_nr);
408+
state.add_object(ssa, fresh_l1_index, ns, field_sensitivity);
448409
}
449410
}
450411

src/goto-symex/symex_start_thread.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@ void goto_symext::symex_start_thread(statet &state)
6666

6767
// get L0 name for current thread
6868
lhs.set_level_0(t);
69+
const irep_idt &l0_name = lhs.get_identifier();
70+
std::size_t l1_index = path_storage.get_unique_index(l0_name, 0);
71+
CHECK_RETURN(l1_index == 0);
6972

7073
// setup L1 name
7174
// with field sensitivity this insert may happen multiple times
@@ -75,7 +78,6 @@ void goto_symext::symex_start_thread(statet &state)
7578
state.rename(lhs, ns, field_sensitivity, goto_symex_statet::L1);
7679
const irep_idt l1_name=lhs.get_l1_object_identifier();
7780
// store it
78-
state.l1_history.insert(l1_name);
7981
new_thread.call_stack.back().local_objects.insert(l1_name);
8082

8183
// make copy

0 commit comments

Comments
 (0)