Skip to content

Commit 9f90b20

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. A problem not yet fully fixed is regression/cbmc/vla3, which still fails despite the work here.
1 parent 44d8f23 commit 9f90b20

File tree

10 files changed

+93
-69
lines changed

10 files changed

+93
-69
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

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: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -797,3 +797,34 @@ void goto_statet::output_propagation_map(std::ostream &out)
797797
out << name_value.first << " <- " << format(name_value.second) << "\n";
798798
}
799799
}
800+
801+
void goto_symex_statet::add_object(
802+
ssa_exprt &ssa,
803+
std::size_t l1_index,
804+
const namespacet &ns)
805+
{
806+
framet &frame = top();
807+
808+
const irep_idt l0_name = ssa.get_identifier();
809+
810+
// save old L1 name, if any
811+
auto c_it = level1.current_names.find(l0_name);
812+
813+
if(c_it != level1.current_names.end())
814+
{
815+
frame.old_level1.emplace(l0_name, c_it->second);
816+
c_it->second = std::make_pair(ssa, l1_index);
817+
}
818+
else
819+
{
820+
c_it = level1.current_names.emplace(l0_name, std::make_pair(ssa, l1_index))
821+
.first;
822+
}
823+
824+
rename(ssa, ns, goto_symex_statet::L1);
825+
const irep_idt &l1_name = ssa.get_identifier();
826+
827+
// unique -- store
828+
if(!frame.local_objects.insert(l1_name).second)
829+
PRECONDITION(false);
830+
}

src/goto-symex/goto_symex_state.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -146,9 +146,6 @@ class goto_symex_statet final : public goto_statet
146146

147147
symex_target_equationt *symex_target;
148148

149-
// we remember all L1 renamings
150-
std::set<irep_idt> l1_history;
151-
152149
symex_level0t level0;
153150
symex_level1t level1;
154151

@@ -257,6 +254,10 @@ class goto_symex_statet final : public goto_statet
257254

258255
const framet &previous_frame() { return *(--(--call_stack().end())); }
259256

257+
/// Turn L0-renamed \p ssa into an L1-renamed SSA expression with an L1 index
258+
/// \p l1_index that must not have previously been used.
259+
void add_object(ssa_exprt &ssa, std::size_t l1_index, const namespacet &ns);
260+
260261
void print_backtrace(std::ostream &) const;
261262

262263
// 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, goto_symex_statet::L1);
41+
state.rename(ssa, ns, 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);
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);

src/goto-symex/symex_function_call.cpp

Lines changed: 10 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

@@ -305,7 +306,7 @@ void goto_symext::symex_function_call_code(
305306
framet &frame = state.new_frame();
306307

307308
// preserve locality of local variables
308-
locality(identifier, state, goto_function, ns);
309+
locality(identifier, state, path_storage, goto_function, ns);
309310

310311
// assign actuals to formal parameters
311312
parameter_assignments(identifier, goto_function, state, arguments);
@@ -380,69 +381,28 @@ void goto_symext::symex_end_of_function(statet &state)
380381
pop_frame(state);
381382
}
382383

383-
/// preserves locality of local variables of a given function by applying L1
384-
/// renaming to the local identifiers
384+
/// preserves locality of parameters of a given function by applying L1
385+
/// renaming to them
385386
static void locality(
386387
const irep_idt &function_identifier,
387388
goto_symext::statet &state,
389+
path_storaget &path_storage,
388390
const goto_functionst::goto_functiont &goto_function,
389391
const namespacet &ns)
390392
{
391393
unsigned &frame_nr=
392394
state.threads[state.source.thread_nr].function_frame[function_identifier];
393395
frame_nr++;
394396

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

443-
// now unique -- store
444-
frame.local_objects.insert(l1_name);
445-
state.l1_history.insert(l1_name);
403+
const std::size_t fresh_l1_index =
404+
path_storage.get_unique_index(ssa.get_identifier(), frame_nr);
405+
state.add_object(ssa, fresh_l1_index, ns);
446406
}
447407
}
448408

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
// set up L1 name
7174
if(!state.level1.current_names.insert(
@@ -75,7 +78,6 @@ void goto_symext::symex_start_thread(statet &state)
7578
state.rename(lhs, ns, 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)