Skip to content

Commit c14150b

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 problem not yet fully fixed is regression/cbmc/vla3, which still fails despite the work here.
1 parent 857323e commit c14150b

File tree

9 files changed

+88
-66
lines changed

9 files changed

+88
-66
lines changed
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
@@ -780,3 +780,34 @@ void goto_symex_statet::output_propagation_map(std::ostream &out)
780780
out << name_value.first << " <- " << format(name_value.second) << "\n";
781781
}
782782
}
783+
784+
void goto_symex_statet::add_object(
785+
ssa_exprt &ssa,
786+
std::size_t l1_index,
787+
const namespacet &ns)
788+
{
789+
framet &frame = top();
790+
791+
const irep_idt l0_name = ssa.get_identifier();
792+
793+
// save old L1 name, if any
794+
auto c_it = level1.current_names.find(l0_name);
795+
796+
if(c_it != level1.current_names.end())
797+
{
798+
frame.old_level1.emplace(l0_name, c_it->second);
799+
c_it->second = std::make_pair(ssa, l1_index);
800+
}
801+
else
802+
{
803+
c_it = level1.current_names.emplace(l0_name, std::make_pair(ssa, l1_index))
804+
.first;
805+
}
806+
807+
rename(ssa, ns, goto_symex_statet::L1);
808+
const irep_idt &l1_name = ssa.get_identifier();
809+
810+
// unique -- store
811+
if(!frame.local_objects.insert(l1_name).second)
812+
PRECONDITION(false);
813+
}

src/goto-symex/goto_symex_state.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,6 @@ class goto_symex_statet final
5858
symex_targett::sourcet source;
5959
symex_target_equationt *symex_target;
6060

61-
// we remember all L1 renamings
62-
std::set<irep_idt> l1_history;
63-
6461
symex_level0t level0;
6562
symex_level1t level1;
6663
symex_level2t level2;
@@ -239,6 +236,10 @@ class goto_symex_statet final
239236

240237
const framet &previous_frame() { return *(--(--call_stack().end())); }
241238

239+
/// Turn L0-renamed \p ssa into an L1-renamed SSA expression with an L1 index
240+
/// \p l1_index that must not have previously been used.
241+
void add_object(ssa_exprt &ssa, std::size_t l1_index, const namespacet &ns);
242+
242243
void print_backtrace(std::ostream &) const;
243244

244245
// threads

src/goto-symex/path_storage.h

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

101+
/// Provide a unique index for a given \p id, starting from \p minimum_index.
102+
std::size_t get_unique_index(const irep_idt &id, std::size_t minimum_index)
103+
{
104+
auto entry = unique_index_map.emplace(id, minimum_index);
105+
106+
if(!entry.second)
107+
entry.first->second = std::max(entry.first->second + 1, minimum_index);
108+
109+
return entry.first->second;
110+
}
111+
101112
private:
102113
// Derived classes should override these methods, allowing the base class to
103114
// enforce preconditions.
104115
virtual patht &private_peek() = 0;
105116
virtual void private_pop() = 0;
117+
118+
std::unordered_map<irep_idt, std::size_t> unique_index_map;
106119
};
107120

108121
/// \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: 7 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -376,8 +376,8 @@ void goto_symext::symex_end_of_function(statet &state)
376376
pop_frame(state);
377377
}
378378

379-
/// preserves locality of local variables of a given function by applying L1
380-
/// renaming to the local identifiers
379+
/// preserves locality of parameters of a given function by applying L1
380+
/// renaming to them
381381
void goto_symext::locality(
382382
const irep_idt &function_identifier,
383383
statet &state,
@@ -387,57 +387,15 @@ void goto_symext::locality(
387387
state.threads[state.source.thread_nr].function_frame[function_identifier];
388388
frame_nr++;
389389

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

438-
// now unique -- store
439-
frame.local_objects.insert(l1_name);
440-
state.l1_history.insert(l1_name);
396+
const std::size_t fresh_l1_index =
397+
path_storage.get_unique_index(ssa.get_identifier(), frame_nr);
398+
state.add_object(ssa, fresh_l1_index, ns);
441399
}
442400
}
443401

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)