Skip to content

Commit 23045d1

Browse files
authored
Merge pull request #7007 from Herbping/loop_invariant_synthesis
CONTRACTS: New classes for loop-invariant-synthesizer interface
2 parents b7ada58 + 948994a commit 23045d1

13 files changed

+417
-0
lines changed
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#include <stdlib.h>
2+
3+
int main()
4+
{
5+
unsigned int size;
6+
__CPROVER_assume(size < 50);
7+
int *p = malloc(size * 4);
8+
int result = 0;
9+
10+
for(unsigned int i = 0; i < size; i++)
11+
{
12+
result += p[i];
13+
}
14+
15+
for(unsigned int i = 0; i < size; i++)
16+
// clang-format off
17+
__CPROVER_loop_invariant(1 == 1)
18+
// clang-format on
19+
{
20+
result += p[i];
21+
}
22+
23+
for(unsigned int i = 0; i < size; i++)
24+
{
25+
result += p[i];
26+
}
27+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
CORE
2+
main.c
3+
--synthesize-loop-invariants --apply-loop-contracts
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^\[main\.\d+\] line 10 Check loop invariant before entry: SUCCESS$
7+
^\[main\.\d+\] line 10 Check that loop invariant is preserved: SUCCESS$
8+
^\[main\.\d+\] line 15 Check loop invariant before entry: SUCCESS$
9+
^\[main\.\d+\] line 15 Check that loop invariant is preserved: SUCCESS$
10+
^\[main\.\d+\] line 23 Check loop invariant before entry: SUCCESS$
11+
^\[main\.\d+\] line 23 Check that loop invariant is preserved: SUCCESS$
12+
^VERIFICATION SUCCESSFUL$
13+
--
14+
^warning: ignoring
15+
--
16+
This test case checks if invariants are generated for unannotated loops.

src/goto-instrument/Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ SRC = accelerate/accelerate.cpp \
6868
source_lines.cpp \
6969
splice_call.cpp \
7070
stack_depth.cpp \
71+
synthesizer/enumerative_loop_invariant_synthesizer.cpp \
72+
synthesizer/synthesizer_utils.cpp \
7173
thread_instrumentation.cpp \
7274
undefined_functions.cpp \
7375
uninitialized.cpp \

src/goto-instrument/goto_instrument_parse_options.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1146,6 +1146,17 @@ void goto_instrument_parse_optionst::instrument_goto_program()
11461146
goto_model.goto_functions.update();
11471147
}
11481148

1149+
if(cmdline.isset("synthesize-loop-invariants"))
1150+
{
1151+
log.warning() << "Loop invariant synthesizer is still work in progress. "
1152+
"It only generates TRUE as invariants."
1153+
<< messaget::eom;
1154+
1155+
// Synthesize loop invariants and annotate them into `goto_model`
1156+
enumerative_loop_invariant_synthesizert synthesizer(goto_model, log);
1157+
annotate_invariants(synthesizer.synthesize_all(), goto_model, log);
1158+
}
1159+
11491160
if(
11501161
cmdline.isset(FLAG_LOOP_CONTRACTS) || cmdline.isset(FLAG_REPLACE_CALL) ||
11511162
cmdline.isset(FLAG_ENFORCE_CONTRACT))
@@ -1895,6 +1906,7 @@ void goto_instrument_parse_optionst::help()
18951906
"\n"
18961907
"Code contracts:\n"
18971908
HELP_LOOP_CONTRACTS
1909+
HELP_LOOP_INVARIANT_SYNTHESIZER
18981910
HELP_REPLACE_CALL
18991911
HELP_ENFORCE_CONTRACT
19001912
"\n"

src/goto-instrument/goto_instrument_parse_options.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ Author: Daniel Kroening, [email protected]
4141
#include "unwindset.h"
4242

4343
#include "contracts/contracts.h"
44+
#include "synthesizer/enumerative_loop_invariant_synthesizer.h"
4445
#include "wmm/weak_memory.h"
4546

4647
// clang-format off
@@ -116,6 +117,7 @@ Author: Daniel Kroening, [email protected]
116117
OPT_NONDET_VOLATILE \
117118
"(ensure-one-backedge-per-target)" \
118119
OPT_CONFIG_LIBRARY \
120+
OPT_SYNTHESIZE_LOOP_INVARIANTS \
119121
// empty last line
120122

121123
// clang-format on

src/goto-instrument/module_dependencies.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,6 @@ langapi # should go away
1010
linking
1111
pointer-analysis
1212
solvers
13+
synthesizer
1314
util
1415
wmm
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*******************************************************************\
2+
3+
Module: Enumerative Loop Invariant Synthesizer
4+
5+
Author: Qinheping Hu
6+
7+
\*******************************************************************/
8+
9+
/// \file
10+
/// Enumerative Loop Invariant Synthesizer
11+
12+
#include "enumerative_loop_invariant_synthesizer.h"
13+
14+
void enumerative_loop_invariant_synthesizert::init_candidates()
15+
{
16+
for(auto &function_p : goto_model.goto_functions.function_map)
17+
{
18+
natural_loopst natural_loops;
19+
natural_loops(function_p.second.body);
20+
21+
// Initialize invariants for unannotated loops as true
22+
for(const auto &loop_head_and_content : natural_loops.loop_map)
23+
{
24+
goto_programt::const_targett loop_end =
25+
get_loop_end_from_loop_head_and_content(
26+
loop_head_and_content.first, loop_head_and_content.second);
27+
28+
loop_idt new_id(function_p.first, loop_end->loop_number);
29+
30+
// we only synthesize invariants for unannotated loops
31+
if(loop_end->condition().find(ID_C_spec_loop_invariant).is_nil())
32+
{
33+
invariant_candiate_map[new_id] = true_exprt();
34+
}
35+
}
36+
}
37+
}
38+
39+
invariant_mapt enumerative_loop_invariant_synthesizert::synthesize_all()
40+
{
41+
init_candidates();
42+
43+
// Now this method only generate true for all unnotated loops.
44+
// The implementation will be added later.
45+
return invariant_candiate_map;
46+
}
47+
48+
exprt enumerative_loop_invariant_synthesizert::synthesize(loop_idt loop_id)
49+
{
50+
return true_exprt();
51+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/*******************************************************************\
2+
3+
Module: Enumerative Loop Invariant Synthesizer
4+
5+
Author: Qinheping Hu
6+
7+
\*******************************************************************/
8+
9+
/// \file
10+
/// Enumerative Loop Invariant Synthesizer
11+
12+
// NOLINTNEXTLINE(whitespace/line_length)
13+
#ifndef CPROVER_GOTO_INSTRUMENT_SYNTHESIZER_ENUMERATIVE_LOOP_INVARIANT_SYNTHESIZER_H
14+
// NOLINTNEXTLINE(whitespace/line_length)
15+
#define CPROVER_GOTO_INSTRUMENT_SYNTHESIZER_ENUMERATIVE_LOOP_INVARIANT_SYNTHESIZER_H
16+
17+
#include <goto-programs/goto_model.h>
18+
19+
#include "loop_invariant_synthesizer_base.h"
20+
21+
class messaget;
22+
23+
/// Enumerative loop invariant synthesizers.
24+
/// It handles `goto_model` containing only checks instrumented by
25+
/// `goto-instrument` with the `--pointer-check` flag.
26+
class enumerative_loop_invariant_synthesizert
27+
: public loop_invariant_synthesizer_baset
28+
{
29+
public:
30+
enumerative_loop_invariant_synthesizert(
31+
const goto_modelt &goto_model,
32+
messaget &log)
33+
: loop_invariant_synthesizer_baset(goto_model, log)
34+
{
35+
}
36+
37+
invariant_mapt synthesize_all() override;
38+
exprt synthesize(loop_idt loop_id) override;
39+
40+
private:
41+
/// Initialize invariants as true for all unannotated loops.
42+
void init_candidates();
43+
44+
invariant_mapt invariant_candiate_map;
45+
};
46+
47+
// NOLINTNEXTLINE(whitespace/line_length)
48+
#endif // CPROVER_GOTO_INSTRUMENT_SYNTHESIZER_ENUMERATIVE_LOOP_INVARIANT_SYNTHESIZER_H
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/*******************************************************************\
2+
3+
Module: Loop Invariant Synthesizer Interface
4+
5+
Author: Qinheping Hu
6+
7+
\*******************************************************************/
8+
9+
/// \file
10+
/// Loop Invariant Synthesizer Interface
11+
12+
#ifndef CPROVER_GOTO_INSTRUMENT_SYNTHESIZER_LOOP_INVARIANT_SYNTHESIZER_BASE_H
13+
#define CPROVER_GOTO_INSTRUMENT_SYNTHESIZER_LOOP_INVARIANT_SYNTHESIZER_BASE_H
14+
15+
#include <goto-programs/goto_model.h>
16+
17+
#include "synthesizer_utils.h"
18+
19+
#define OPT_SYNTHESIZE_LOOP_INVARIANTS "(synthesize-loop-invariants)"
20+
#define HELP_LOOP_INVARIANT_SYNTHESIZER \
21+
" --synthesize-loop-invariants\n" \
22+
" synthesize and apply loop invariants\n"
23+
24+
class messaget;
25+
26+
/// A base class for loop invariant synthesizers.
27+
/// Provides a method for synthesizing loop invariants in a given `goto_model`.
28+
///
29+
/// Derived class should clarify what types of `goto_model` they targets, e.g.,
30+
/// a `goto_model` contains only memory safety checks, or a `goto_model`
31+
/// contains both memory safety checks and correctness checks.
32+
class loop_invariant_synthesizer_baset
33+
{
34+
public:
35+
loop_invariant_synthesizer_baset(const goto_modelt &goto_model, messaget &log)
36+
: goto_model(goto_model), log(log)
37+
{
38+
}
39+
virtual ~loop_invariant_synthesizer_baset() = default;
40+
41+
/// Synthesize loop invariants with which all checks in `goto_model`
42+
/// succeed. The result is a map from `loop_idt` ids of loops to `exprt`
43+
/// the goto-expression representation of synthesized invariants.
44+
virtual invariant_mapt synthesize_all() = 0;
45+
46+
/// Synthesize loop invariant for a specified loop in the `goto_model`
47+
virtual exprt synthesize(loop_idt) = 0;
48+
49+
protected:
50+
const goto_modelt &goto_model;
51+
messaget &log;
52+
};
53+
54+
#endif // CPROVER_GOTO_INSTRUMENT_SYNTHESIZER_LOOP_INVARIANT_SYNTHESIZER_BASE_H
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
analyses
2+
ansi-c
3+
goto-instrument/contracts
4+
goto-instrument/synthesizer
5+
goto-instrument
6+
goto-programs
7+
langapi
8+
util

0 commit comments

Comments
 (0)