Skip to content

Commit 7409787

Browse files
Merge pull request #6835 from thomasspriggs/tas/smt_object_size
Add support for object_size expressions to incremental SMT solving
2 parents 8699438 + 6ffe24c commit 7409787

15 files changed

+498
-192
lines changed
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#include <stdbool.h>
2+
#include <stddef.h>
3+
#include <stdint.h>
4+
5+
int main()
6+
{
7+
uint16_t x;
8+
uint32_t y;
9+
bool nondet_bool1;
10+
void *ptr = nondet_bool1 ? (&x) : (&y);
11+
size_t size = __CPROVER_OBJECT_SIZE(ptr);
12+
__CPROVER_assert(size == 2 || size == 4, "Expected int sizes.");
13+
__CPROVER_assert(size == 2, "Size is always 2. (Can be disproved.)");
14+
__CPROVER_assert(size == 4, "Size is always 4. (Can be disproved.)");
15+
size_t null_size = __CPROVER_OBJECT_SIZE(NULL);
16+
__CPROVER_assert(null_size == 254, "Size of NULL.");
17+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
CORE
2+
object_size.c
3+
--trace
4+
line 12 Expected int sizes\.: SUCCESS
5+
line 13 Size is always 2\. \(Can be disproved\.\): FAILURE
6+
line 14 Size is always 4\. \(Can be disproved\.\): FAILURE
7+
line 16 Size of NULL\.: FAILURE
8+
size=2ul
9+
size=4ul
10+
null_size=0ul
11+
^EXIT=10$
12+
^SIGNAL=0$
13+
--
14+
--
15+
Test that the model of object_size can take only the expected values in the case
16+
where the pointer it is given may point to one of two objects. Test that the
17+
size of the null object is zero.

src/solvers/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,7 @@ SRC = $(BOOLEFORCE_SRC) \
201201
smt2_incremental/smt_core_theory.cpp \
202202
smt2_incremental/smt_index.cpp \
203203
smt2_incremental/smt_logics.cpp \
204+
smt2_incremental/smt_object_size.cpp \
204205
smt2_incremental/smt_options.cpp \
205206
smt2_incremental/smt_response_validation.cpp \
206207
smt2_incremental/smt_responses.cpp \

src/solvers/smt2_incremental/convert_expr_to_smt.cpp

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1238,11 +1238,18 @@ static smt_termt convert_expr_to_smt(
12381238

12391239
static smt_termt convert_expr_to_smt(
12401240
const object_size_exprt &object_size,
1241-
const sub_expression_mapt &converted)
1241+
const sub_expression_mapt &converted,
1242+
const smt_object_sizet::make_applicationt &call_object_size)
12421243
{
1243-
UNIMPLEMENTED_FEATURE(
1244-
"Generation of SMT formula for object_size expression: " +
1245-
object_size.pretty());
1244+
const smt_termt &pointer = converted.at(object_size.pointer());
1245+
const auto pointer_sort = pointer.get_sort().cast<smt_bit_vector_sortt>();
1246+
INVARIANT(
1247+
pointer_sort, "Pointers should be encoded as bit vector sorted terms.");
1248+
const std::size_t pointer_width = pointer_sort->bit_width();
1249+
return call_object_size(
1250+
std::vector<smt_termt>{smt_bit_vector_theoryt::extract(
1251+
pointer_width - 1,
1252+
pointer_width - config.bv_encoding.object_bits)(pointer)});
12461253
}
12471254

12481255
static smt_termt
@@ -1291,7 +1298,8 @@ static smt_termt convert_expr_to_smt(
12911298
static smt_termt dispatch_expr_to_smt_conversion(
12921299
const exprt &expr,
12931300
const sub_expression_mapt &converted,
1294-
const smt_object_mapt &object_map)
1301+
const smt_object_mapt &object_map,
1302+
const smt_object_sizet::make_applicationt &call_object_size)
12951303
{
12961304
if(const auto symbol = expr_try_dynamic_cast<symbol_exprt>(expr))
12971305
{
@@ -1589,7 +1597,7 @@ static smt_termt dispatch_expr_to_smt_conversion(
15891597
}
15901598
if(const auto object_size = expr_try_dynamic_cast<object_size_exprt>(expr))
15911599
{
1592-
return convert_expr_to_smt(*object_size, converted);
1600+
return convert_expr_to_smt(*object_size, converted, call_object_size);
15931601
}
15941602
if(const auto let = expr_try_dynamic_cast<let_exprt>(expr))
15951603
{
@@ -1647,8 +1655,10 @@ at_scope_exitt<functiont> at_scope_exit(functiont exit_function)
16471655
}
16481656
#endif
16491657

1650-
smt_termt
1651-
convert_expr_to_smt(const exprt &expr, const smt_object_mapt &object_map)
1658+
smt_termt convert_expr_to_smt(
1659+
const exprt &expr,
1660+
const smt_object_mapt &object_map,
1661+
const smt_object_sizet::make_applicationt &object_size)
16521662
{
16531663
#ifndef CPROVER_INVARIANT_DO_NOT_CHECK
16541664
static bool in_conversion = false;
@@ -1665,8 +1675,8 @@ convert_expr_to_smt(const exprt &expr, const smt_object_mapt &object_map)
16651675
const auto find_result = sub_expression_map.find(expr);
16661676
if(find_result != sub_expression_map.cend())
16671677
return;
1668-
smt_termt term =
1669-
dispatch_expr_to_smt_conversion(expr, sub_expression_map, object_map);
1678+
smt_termt term = dispatch_expr_to_smt_conversion(
1679+
expr, sub_expression_map, object_map, object_size);
16701680
sub_expression_map.emplace_hint(find_result, expr, std::move(term));
16711681
});
16721682
return std::move(sub_expression_map.at(expr));

src/solvers/smt2_incremental/convert_expr_to_smt.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#define CPROVER_SOLVERS_SMT2_INCREMENTAL_CONVERT_EXPR_TO_SMT_H
55

66
#include <solvers/smt2_incremental/object_tracking.h>
7+
#include <solvers/smt2_incremental/smt_object_size.h>
78
#include <solvers/smt2_incremental/smt_sorts.h>
89
#include <solvers/smt2_incremental/smt_terms.h>
910

@@ -16,7 +17,9 @@ smt_sortt convert_type_to_smt_sort(const typet &type);
1617

1718
/// \brief Converts the \p expression to an smt encoding of the same expression
1819
/// stored as term ast (abstract syntax tree).
19-
smt_termt
20-
convert_expr_to_smt(const exprt &expression, const smt_object_mapt &object_map);
20+
smt_termt convert_expr_to_smt(
21+
const exprt &expression,
22+
const smt_object_mapt &object_map,
23+
const smt_object_sizet::make_applicationt &object_size);
2124

2225
#endif // CPROVER_SOLVERS_SMT2_INCREMENTAL_CONVERT_EXPR_TO_SMT_H

src/solvers/smt2_incremental/object_tracking.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
#include "object_tracking.h"
44

5+
#include <util/arith_tools.h>
56
#include <util/c_types.h>
67
#include <util/pointer_offset_size.h>
78
#include <util/std_code.h>
@@ -42,6 +43,7 @@ static decision_procedure_objectt make_null_object()
4243
decision_procedure_objectt null_object;
4344
null_object.unique_id = 0;
4445
null_object.base_expression = null_pointer_exprt{pointer_type(void_type())};
46+
null_object.size = from_integer(0, size_type());
4547
return null_object;
4648
}
4749

@@ -64,10 +66,12 @@ void track_expression_objects(
6466
const auto find_result = object_map.find(object_base);
6567
if(find_result != object_map.cend())
6668
return;
69+
const auto size = size_of_expr(object_base.type(), ns);
70+
INVARIANT(size, "Objects are expected to have well defined size");
6771
decision_procedure_objectt object;
6872
object.base_expression = object_base;
6973
object.unique_id = object_map.size();
70-
object.size = size_of_expr(object_base.type(), ns);
74+
object.size = *size;
7175
object_map.emplace_hint(find_result, object_base, std::move(object));
7276
});
7377
}

src/solvers/smt2_incremental/object_tracking.h

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,33 @@
11
// Author: Diffblue Ltd.
22

3+
/// \file
4+
/// Data structures and algorithms used by smt2_incremental_decision_proceduret
5+
/// to track data about the objects which pointers point to. An object here
6+
/// is the whole of an allocated block of memory. Objects in this sense have
7+
/// no sub objects; only offsets. Valid examples of objects include -
8+
/// * Primitives stored on the stack such as `int foo;`.
9+
/// * Pointer primitives stored on the stack such as `int *sam;`.
10+
/// * The entirety of a struct stored on the stack such as -
11+
/// `struct bart{int eggs, int ham} bar;`
12+
/// * The entirety of an array stored on the stack such as `int green[20];`
13+
/// * The memory allocated by a malloc call - `malloc(20)`.
14+
/// Examples of things / expressions which are not objects -
15+
/// * A pointer to a primitive stored on the stack, such as `&foo` or `&sam`.
16+
/// The value of these pointers encodes the combination of the unique object
17+
/// identifier of `foo` / `sam` objects and a (zero) offset, but these
18+
/// pointer values / memory addresses are not in themselves objects, although
19+
/// the values may be stored in another object. This is a distinction between
20+
/// values and the objects which contain them.
21+
/// * A field within a struct, such as `bar.ham` from the previous example. A
22+
/// pointer to this field is an offset into the base `bar` object.
23+
/// * A pointer to element within an array, such as `&(green[5])`. A pointer to
24+
/// an element in this example is an offset into the base `int green[20]`
25+
/// object.
26+
/// \note
27+
/// The functionality in this file is intended to cover tracking objects and
28+
/// their sizes only. It does not track anything to do with the offsets into
29+
/// objects or the SMT encodings of objects / offsets / pointers.
30+
331
#ifndef CPROVER_SOLVERS_SMT2_INCREMENTAL_OBJECT_TRACKING_H
432
#define CPROVER_SOLVERS_SMT2_INCREMENTAL_OBJECT_TRACKING_H
533

@@ -17,7 +45,7 @@ struct decision_procedure_objectt
1745
/// Number which uniquely identifies this particular object.
1846
std::size_t unique_id;
1947
/// Expression which evaluates to the size of the object in bytes.
20-
optionalt<exprt> size;
48+
exprt size;
2149
};
2250

2351
/// The model of addresses we use consists of a unique object identifier and an

src/solvers/smt2_incremental/smt2_incremental_decision_procedure.cpp

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ smt2_incremental_decision_proceduret::smt2_incremental_decision_proceduret(
139139
smt_set_option_commandt{smt_option_produce_modelst{true}});
140140
solver_process->send(smt_set_logic_commandt{
141141
smt_logic_quantifier_free_uninterpreted_functions_bit_vectorst{}});
142+
solver_process->send(object_size_function.declaration);
142143
}
143144

144145
void smt2_incremental_decision_proceduret::ensure_handle_for_expr_defined(
@@ -162,7 +163,8 @@ smt_termt
162163
smt2_incremental_decision_proceduret::convert_expr_to_smt(const exprt &expr)
163164
{
164165
track_expression_objects(expr, ns, object_map);
165-
return ::convert_expr_to_smt(expr, object_map);
166+
return ::convert_expr_to_smt(
167+
expr, object_map, object_size_function.make_application);
166168
}
167169

168170
exprt smt2_incremental_decision_proceduret::handle(const exprt &expr)
@@ -205,7 +207,8 @@ exprt smt2_incremental_decision_proceduret::get(const exprt &expr) const
205207
objects_are_already_tracked(expr, object_map),
206208
"Objects in expressions being read should already be tracked from "
207209
"point of being set/handled.");
208-
descriptor = ::convert_expr_to_smt(expr, object_map);
210+
descriptor = ::convert_expr_to_smt(
211+
expr, object_map, object_size_function.make_application);
209212
}
210213
else
211214
{
@@ -320,9 +323,26 @@ static decision_proceduret::resultt lookup_decision_procedure_result(
320323
UNREACHABLE;
321324
}
322325

326+
void smt2_incremental_decision_proceduret::define_object_sizes()
327+
{
328+
object_size_defined.resize(object_map.size());
329+
for(const auto &key_value : object_map)
330+
{
331+
const decision_procedure_objectt &object = key_value.second;
332+
if(object_size_defined[object.unique_id])
333+
continue;
334+
else
335+
object_size_defined[object.unique_id] = true;
336+
define_dependent_functions(object.size);
337+
solver_process->send(object_size_function.make_definition(
338+
object.unique_id, convert_expr_to_smt(object.size)));
339+
}
340+
}
341+
323342
decision_proceduret::resultt smt2_incremental_decision_proceduret::dec_solve()
324343
{
325344
++number_of_solver_calls;
345+
define_object_sizes();
326346
const smt_responset result =
327347
get_response_to_command(*solver_process, smt_check_sat_commandt{});
328348
if(const auto check_sat_response = result.cast<smt_check_sat_responset>())

src/solvers/smt2_incremental/smt2_incremental_decision_procedure.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <util/std_expr.h>
1111

1212
#include <solvers/smt2_incremental/object_tracking.h>
13+
#include <solvers/smt2_incremental/smt_object_size.h>
1314
#include <solvers/smt2_incremental/smt_terms.h>
1415
#include <solvers/stack_decision_procedure.h>
1516

@@ -60,6 +61,8 @@ class smt2_incremental_decision_proceduret final
6061
/// \brief Add objects in \p expr to object_map if needed and convert to smt.
6162
/// \note This function is non-const because it mutates the object_map.
6263
smt_termt convert_expr_to_smt(const exprt &expr);
64+
/// Sends the solver the definitions of the object sizes.
65+
void define_object_sizes();
6366

6467
const namespacet &ns;
6568

@@ -84,6 +87,8 @@ class smt2_incremental_decision_proceduret final
8487
std::unordered_map<exprt, smt_identifier_termt, irep_hash>
8588
expression_identifiers;
8689
smt_object_mapt object_map;
90+
std::vector<bool> object_size_defined;
91+
smt_object_sizet object_size_function;
8792
};
8893

8994
#endif // CPROVER_SOLVERS_SMT2_INCREMENTAL_SMT2_INCREMENTAL_DECISION_PROCEDURE_H
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// Author: Diffblue Ltd.
2+
3+
#include "smt_object_size.h"
4+
5+
#include <util/c_types.h>
6+
#include <util/config.h>
7+
8+
#include <solvers/smt2_incremental/convert_expr_to_smt.h>
9+
#include <solvers/smt2_incremental/smt_core_theory.h>
10+
#include <solvers/smt2_incremental/smt_sorts.h>
11+
12+
static smt_declare_function_commandt make_object_size_function_declaration()
13+
{
14+
return smt_declare_function_commandt{
15+
smt_identifier_termt{
16+
"size_of_object", convert_type_to_smt_sort(size_type())},
17+
{smt_bit_vector_sortt{config.bv_encoding.object_bits}}};
18+
}
19+
20+
smt_object_sizet::smt_object_sizet()
21+
: declaration{make_object_size_function_declaration()},
22+
make_application{smt_command_functiont{declaration}}
23+
{
24+
}
25+
26+
smt_commandt smt_object_sizet::make_definition(
27+
const std::size_t unique_id,
28+
smt_termt size) const
29+
{
30+
const auto id_sort =
31+
declaration.parameter_sorts().at(0).get().cast<smt_bit_vector_sortt>();
32+
INVARIANT(id_sort, "Object identifiers are expected to have bit vector sort");
33+
const auto bit_vector_of_id =
34+
smt_bit_vector_constant_termt{unique_id, *id_sort};
35+
return smt_assert_commandt{smt_core_theoryt::equal(
36+
make_application(std::vector<smt_termt>{bit_vector_of_id}),
37+
std::move(size))};
38+
}

0 commit comments

Comments
 (0)