Skip to content

Commit fe8b401

Browse files
committed
Concurrency: treat updates to an unknown field as atomic
Writing to an object that is composed of multiple fields is generally treated in a field-sensitive (and thus: single-field) manner, which had fixed several issues in handling shared arrays or structs. When the specific field being updated cannot be determined during symbolic execution (as is the case with non-const indices into arrays), we update all fields that make up the full object. Such a full-object update must then be treated as an atomic operation to avoid losing intermittent writes performed by other threads. Fixes: diffblue#123
1 parent d7099ae commit fe8b401

File tree

3 files changed

+45
-0
lines changed

3 files changed

+45
-0
lines changed
+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
int data[2];
2+
unsigned sync;
3+
4+
void thread()
5+
{
6+
data[sync % 2] = 1;
7+
__CPROVER_assert(data[sync % 2] == 1, "1");
8+
}
9+
10+
int main()
11+
{
12+
unsigned nondet;
13+
sync = nondet;
14+
__CPROVER_ASYNC_1:
15+
thread();
16+
unsigned sync_value = sync;
17+
data[(sync_value + 1) % 2] = 2;
18+
__CPROVER_assert(data[(sync_value + 1) % 2] == 2, "2");
19+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CORE
2+
main.c
3+
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^VERIFICATION SUCCESSFUL$
7+
--
8+
^warning: ignoring

src/goto-symex/goto_symex.cpp

+18
Original file line numberDiff line numberDiff line change
@@ -117,10 +117,28 @@ void goto_symext::symex_assign(
117117
return;
118118
}
119119

120+
// We may end up reading (and writing) all components of an object composed
121+
// of multiple fields. In such cases, we must do so atomically to avoid
122+
// overwriting components modified by another thread. Note that this also
123+
// implies multiple shared reads on the rhs being treated as atomic.
124+
const bool maybe_divisible =
125+
lhs.id() == ID_index ||
126+
(is_ssa_expr(lhs) &&
127+
state.field_sensitivity.is_divisible(to_ssa_expr(lhs), false));
128+
const bool need_atomic_section = maybe_divisible &&
129+
state.threads.size() > 1 &&
130+
state.atomic_section_id == 0;
131+
132+
if(need_atomic_section)
133+
symex_atomic_begin(state);
134+
120135
exprt::operandst lhs_if_then_else_conditions;
121136
symex_assignt{
122137
shadow_memory, state, assignment_type, ns, symex_config, target}
123138
.assign_rec(lhs, expr_skeletont{}, rhs, lhs_if_then_else_conditions);
139+
140+
if(need_atomic_section)
141+
symex_atomic_end(state);
124142
}
125143
}
126144

0 commit comments

Comments
 (0)