Skip to content

Commit 2364387

Browse files
committed
Dirty locals copied across threads require program-order constraints
We previously lacked SHARED_WRITE events in program order in a newly-spawned thread for dirty locals being copied from the spawning thread. This resulted in spurious failures as reading from initial values seemed possible, when the from-read constraint should have prevented such reads. Also, replace the variable "t" by the more descriptive "new_thread_nr."
1 parent de5bf78 commit 2364387

File tree

2 files changed

+23
-13
lines changed

2 files changed

+23
-13
lines changed
Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
KNOWNBUG
1+
CORE
22
main.c
33
-Dlocals_bug
44
^EXIT=0$
@@ -7,12 +7,6 @@ main.c
77
--
88
^warning: ignoring
99
--
10-
There is a need for further debugging around copying local objects in
11-
the procedure spawning threads as we generate the following non-sensical
12-
constraint:
13-
// 28 file regression/cbmc-concurrency/dirty_local3/main.c line 3 function worker
14-
(57) CONSTRAINT(z!1@0#2 == z!1@0 || !choice_rf0)
15-
^^^^^^^^^^^^^^^^
16-
comparison of L2 and L1 SSA symbols
17-
// 28 file regression/cbmc-concurrency/dirty_local3/main.c line 3 function worker
18-
(58) CONSTRAINT(choice_rf0)
10+
We previously missed SHARED_WRITE events in program order in a newly-spawned
11+
thread for dirty locals, resulting in spurious failures as reading from initial
12+
values seemed possible.

src/goto-symex/symex_start_thread.cpp

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ void goto_symext::symex_start_thread(statet &state)
4040
instruction.get_target();
4141

4242
// put into thread vector
43-
std::size_t t=state.threads.size();
43+
const std::size_t new_thread_nr = state.threads.size();
4444
state.threads.push_back(statet::threadt(guard_manager));
4545
// statet::threadt &cur_thread=state.threads[state.source.thread_nr];
4646
statet::threadt &new_thread=state.threads.back();
@@ -54,6 +54,8 @@ void goto_symext::symex_start_thread(statet &state)
5454
new_thread.abstract_events=&(target.new_thread(cur_thread.abstract_events));
5555
#endif
5656

57+
const std::size_t current_thread_nr = state.source.thread_nr;
58+
5759
// create a copy of the local variables for the new thread
5860
framet &frame = state.call_stack().top();
5961

@@ -72,7 +74,8 @@ void goto_symext::symex_start_thread(statet &state)
7274
ssa_exprt lhs(pair.second.first.get_original_expr());
7375

7476
// get L0 name for current thread
75-
const renamedt<ssa_exprt, L0> l0_lhs = symex_level0(std::move(lhs), ns, t);
77+
const renamedt<ssa_exprt, L0> l0_lhs =
78+
symex_level0(std::move(lhs), ns, new_thread_nr);
7679
const irep_idt &l0_name = l0_lhs.get().get_identifier();
7780
std::size_t l1_index = path_storage.get_unique_l1_index(l0_name, 0);
7881
CHECK_RETURN(l1_index == 0);
@@ -93,7 +96,20 @@ void goto_symext::symex_start_thread(statet &state)
9396
symex_assignt{
9497
state, symex_targett::assignment_typet::HIDDEN, ns, symex_config, target}
9598
.assign_symbol(lhs_l1, expr_skeletont{}, rhs, lhs_conditions);
99+
const exprt l2_lhs = state.rename(lhs_l1, ns).get();
96100
state.record_events.pop();
101+
102+
// record a shared write in the new thread
103+
if(
104+
state.write_is_shared(lhs_l1, ns) ==
105+
goto_symex_statet::write_is_shared_resultt::SHARED &&
106+
is_ssa_expr(l2_lhs))
107+
{
108+
state.source.thread_nr = new_thread_nr;
109+
target.shared_write(
110+
state.guard.as_expr(), to_ssa_expr(l2_lhs), 0, state.source);
111+
state.source.thread_nr = current_thread_nr;
112+
}
97113
}
98114

99115
// initialize all variables marked thread-local
@@ -112,7 +128,7 @@ void goto_symext::symex_start_thread(statet &state)
112128
ssa_exprt lhs(symbol.symbol_expr());
113129

114130
// get L0 name for current thread
115-
lhs.set_level_0(t);
131+
lhs.set_level_0(new_thread_nr);
116132

117133
exprt rhs=symbol.value;
118134
if(rhs.is_nil())

0 commit comments

Comments
 (0)