Skip to content

Commit 32b68ce

Browse files
author
Daniel Kroening
authored
Merge pull request #988 from tautschnig/fix-unwind-count
Reset unwinding counters when leaving a loop at the loop head
2 parents c7ce527 + 21afd2f commit 32b68ce

File tree

10 files changed

+108
-34
lines changed

10 files changed

+108
-34
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
int main()
2+
{
3+
for(int i=0; i<2; ++i)
4+
for(int j=0; j<10; ++j);
5+
return 0;
6+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
CORE
2+
main.c
3+
--unwind 11 --unwinding-assertions
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^VERIFICATION SUCCESSFUL$
7+
--
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
int main()
2+
{
3+
l2: goto l1;
4+
l1: int x=5;
5+
goto l2;
6+
7+
return 0;
8+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
CORE
2+
main.c
3+
--unwind 3 --unwinding-assertions
4+
^EXIT=10$
5+
^SIGNAL=0$
6+
^VERIFICATION FAILED$
7+
--
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
int main()
2+
{
3+
int i=0;
4+
l2: if(i==1) int y=0;
5+
l1: int x=5;
6+
goto l2;
7+
8+
return 0;
9+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
CORE
2+
main.c
3+
--unwind 3 --unwinding-assertions
4+
^EXIT=10$
5+
^SIGNAL=0$
6+
^VERIFICATION FAILED$
7+
--

src/goto-symex/goto_symex.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,16 @@ class goto_symext
155155
irep_idt guard_identifier;
156156

157157
// symex
158+
virtual void symex_transition(
159+
statet &state,
160+
goto_programt::const_targett to,
161+
bool is_backwards_goto=false);
162+
virtual void symex_transition(statet &state)
163+
{
164+
goto_programt::const_targett next=state.source.pc;
165+
++next;
166+
symex_transition(state, next);
167+
}
158168

159169
virtual void symex_goto(statet &state);
160170
virtual void symex_start_thread(statet &state);

src/goto-symex/symex_function_call.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,7 @@ void goto_symext::symex_function_call_code(
254254
state.guard.add(false_exprt());
255255
}
256256

257-
state.source.pc++;
257+
symex_transition(state);
258258
return;
259259
}
260260

@@ -276,7 +276,7 @@ void goto_symext::symex_function_call_code(
276276
symex_assign_rec(state, code);
277277
}
278278

279-
state.source.pc++;
279+
symex_transition(state);
280280
return;
281281
}
282282

@@ -314,7 +314,7 @@ void goto_symext::symex_function_call_code(
314314
frame.loop_iterations[identifier].count++;
315315

316316
state.source.is_set=true;
317-
state.source.pc=goto_function.body.instructions.begin();
317+
symex_transition(state, goto_function.body.instructions.begin());
318318
}
319319

320320
/// pop one call frame
@@ -326,7 +326,7 @@ void goto_symext::pop_frame(statet &state)
326326
statet::framet &frame=state.top();
327327

328328
// restore program counter
329-
state.source.pc=frame.calling_location.pc;
329+
symex_transition(state, frame.calling_location.pc);
330330

331331
// restore L1 renaming
332332
state.level1.restore_from(frame.old_level1);

src/goto-symex/symex_goto.cpp

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,8 @@ void goto_symext::symex_goto(statet &state)
3636
if(!state.guard.is_false())
3737
target.location(state.guard.as_expr(), state.source);
3838

39-
// reset unwinding counter
40-
if(instruction.is_backwards_goto())
41-
frame.loop_iterations[goto_programt::loop_id(state.source.pc)].count=0;
42-
4339
// next instruction
44-
state.source.pc++;
40+
symex_transition(state);
4541
return; // nothing to do
4642
}
4743

@@ -77,7 +73,7 @@ void goto_symext::symex_goto(statet &state)
7773
symex_assume(state, negated_cond);
7874

7975
// next instruction
80-
state.source.pc++;
76+
symex_transition(state);
8177
return;
8278
}
8379

@@ -91,17 +87,14 @@ void goto_symext::symex_goto(statet &state)
9187
// no!
9288
loop_bound_exceeded(state, new_guard);
9389

94-
// reset unwinding
95-
unwind=0;
96-
9790
// next instruction
98-
state.source.pc++;
91+
symex_transition(state);
9992
return;
10093
}
10194

10295
if(new_guard.is_true())
10396
{
104-
state.source.pc=goto_target;
97+
symex_transition(state, goto_target, true);
10598
return; // nothing else to do
10699
}
107100
}
@@ -122,7 +115,7 @@ void goto_symext::symex_goto(statet &state)
122115

123116
if(state_pc==goto_target)
124117
{
125-
state.source.pc=goto_target;
118+
symex_transition(state, goto_target);
126119
return; // nothing else to do
127120
}
128121
}
@@ -140,7 +133,7 @@ void goto_symext::symex_goto(statet &state)
140133
goto_state_list.push_back(statet::goto_statet(state));
141134
statet::goto_statet &new_state=goto_state_list.back();
142135

143-
state.source.pc=state_pc;
136+
symex_transition(state, state_pc, !forward);
144137

145138
// adjust guards
146139
if(new_guard.is_true())

src/goto-symex/symex_main.cpp

Lines changed: 44 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,30 @@ Author: Daniel Kroening, [email protected]
2020

2121
#include "goto_symex.h"
2222

23+
void goto_symext::symex_transition(
24+
statet &state,
25+
goto_programt::const_targett to,
26+
bool is_backwards_goto)
27+
{
28+
if(!state.call_stack().empty())
29+
{
30+
// initialize the loop counter of any loop we are newly entering
31+
// upon this transition; we are entering a loop if
32+
// 1. the transition from state.source.pc to "to" is not a backwards goto
33+
// or
34+
// 2. we are arriving from an outer loop
35+
statet::framet &frame=state.top();
36+
const goto_programt::instructiont &instruction=*to;
37+
for(const auto &i_e : instruction.incoming_edges)
38+
if(i_e->is_goto() && i_e->is_backwards_goto() &&
39+
(!is_backwards_goto ||
40+
state.source.pc->location_number>i_e->location_number))
41+
frame.loop_iterations[goto_programt::loop_id(i_e)].count=0;
42+
}
43+
44+
state.source.pc=to;
45+
}
46+
2347
void goto_symext::new_name(symbolt &symbol)
2448
{
2549
get_new_name(symbol, ns);
@@ -114,6 +138,8 @@ void goto_symext::operator()(
114138
state.symex_target=&target;
115139
state.dirty=new dirtyt(goto_functions);
116140

141+
symex_transition(state, state.source.pc);
142+
117143
assert(state.top().end_of_function->is_end_function());
118144

119145
while(!state.call_stack().empty())
@@ -127,6 +153,7 @@ void goto_symext::operator()(
127153
unsigned t=state.source.thread_nr+1;
128154
// std::cout << "********* Now executing thread " << t << '\n';
129155
state.switch_to_thread(t);
156+
symex_transition(state, state.source.pc);
130157
}
131158
}
132159

@@ -190,20 +217,20 @@ void goto_symext::symex_step(
190217
case SKIP:
191218
if(!state.guard.is_false())
192219
target.location(state.guard.as_expr(), state.source);
193-
state.source.pc++;
220+
symex_transition(state);
194221
break;
195222

196223
case END_FUNCTION:
197224
// do even if state.guard.is_false() to clear out frame created
198225
// in symex_start_thread
199226
symex_end_of_function(state);
200-
state.source.pc++;
227+
symex_transition(state);
201228
break;
202229

203230
case LOCATION:
204231
if(!state.guard.is_false())
205232
target.location(state.guard.as_expr(), state.source);
206-
state.source.pc++;
233+
symex_transition(state);
207234
break;
208235

209236
case GOTO:
@@ -219,7 +246,7 @@ void goto_symext::symex_step(
219246
symex_assume(state, tmp);
220247
}
221248

222-
state.source.pc++;
249+
symex_transition(state);
223250
break;
224251

225252
case ASSERT:
@@ -233,21 +260,21 @@ void goto_symext::symex_step(
233260
vcc(tmp, msg, state);
234261
}
235262

236-
state.source.pc++;
263+
symex_transition(state);
237264
break;
238265

239266
case RETURN:
240267
if(!state.guard.is_false())
241268
return_assignment(state);
242269

243-
state.source.pc++;
270+
symex_transition(state);
244271
break;
245272

246273
case ASSIGN:
247274
if(!state.guard.is_false())
248275
symex_assign_rec(state, to_code_assign(instruction.code));
249276

250-
state.source.pc++;
277+
symex_transition(state);
251278
break;
252279

253280
case FUNCTION_CALL:
@@ -267,58 +294,58 @@ void goto_symext::symex_step(
267294
symex_function_call(goto_functions, state, deref_code);
268295
}
269296
else
270-
state.source.pc++;
297+
symex_transition(state);
271298
break;
272299

273300
case OTHER:
274301
if(!state.guard.is_false())
275302
symex_other(goto_functions, state);
276303

277-
state.source.pc++;
304+
symex_transition(state);
278305
break;
279306

280307
case DECL:
281308
if(!state.guard.is_false())
282309
symex_decl(state);
283310

284-
state.source.pc++;
311+
symex_transition(state);
285312
break;
286313

287314
case DEAD:
288315
symex_dead(state);
289-
state.source.pc++;
316+
symex_transition(state);
290317
break;
291318

292319
case START_THREAD:
293320
symex_start_thread(state);
294-
state.source.pc++;
321+
symex_transition(state);
295322
break;
296323

297324
case END_THREAD:
298325
// behaves like assume(0);
299326
if(!state.guard.is_false())
300327
state.guard.add(false_exprt());
301-
state.source.pc++;
328+
symex_transition(state);
302329
break;
303330

304331
case ATOMIC_BEGIN:
305332
symex_atomic_begin(state);
306-
state.source.pc++;
333+
symex_transition(state);
307334
break;
308335

309336
case ATOMIC_END:
310337
symex_atomic_end(state);
311-
state.source.pc++;
338+
symex_transition(state);
312339
break;
313340

314341
case CATCH:
315342
symex_catch(state);
316-
state.source.pc++;
343+
symex_transition(state);
317344
break;
318345

319346
case THROW:
320347
symex_throw(state);
321-
state.source.pc++;
348+
symex_transition(state);
322349
break;
323350

324351
case NO_INSTRUCTION_TYPE:

0 commit comments

Comments
 (0)