Skip to content

Commit b47a7b2

Browse files
Merge pull request #7313 from thomasspriggs/tas/dynamic_object
Add support for `__CPROVER_DYNAMIC_OBJECT` to incremental SMT decision procedure
2 parents 02d698e + f398ace commit b47a7b2

22 files changed

+374
-37
lines changed
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#include <assert.h>
2+
#include <stdbool.h>
3+
#include <stdlib.h>
4+
5+
bool nondet_bool();
6+
7+
void main()
8+
{
9+
char local;
10+
void *pointer = &local;
11+
const bool make_dynamic = nondet_bool();
12+
if(make_dynamic)
13+
{
14+
pointer = malloc(1);
15+
}
16+
assert(__CPROVER_DYNAMIC_OBJECT(pointer));
17+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
CORE
2+
assert_dynamic.c
3+
--trace
4+
Passing problem to incremental SMT2 solving
5+
line 16 assertion __CPROVER_DYNAMIC_OBJECT\(pointer\)\: FAILURE
6+
make_dynamic\=FALSE
7+
^EXIT=10$
8+
^SIGNAL=0$
9+
--
10+
make_dynamic\=TRUE
11+
--
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#include <assert.h>
2+
#include <stdbool.h>
3+
#include <stdlib.h>
4+
5+
bool nondet_bool();
6+
7+
void main()
8+
{
9+
char local;
10+
void *pointer = &local;
11+
const bool make_dynamic = nondet_bool();
12+
if(make_dynamic)
13+
{
14+
pointer = malloc(1);
15+
}
16+
assert(!__CPROVER_DYNAMIC_OBJECT(pointer));
17+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
CORE
2+
assert_not_dynamic.c
3+
--trace
4+
Passing problem to incremental SMT2 solving
5+
line 16 assertion \!__CPROVER_DYNAMIC_OBJECT\(pointer\)\: FAILURE
6+
make_dynamic\=TRUE
7+
^EXIT=10$
8+
^SIGNAL=0$
9+
--
10+
make_dynamic\=FALSE
11+
--
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#include <assert.h>
2+
#include <stdbool.h>
3+
#include <stdlib.h>
4+
5+
bool nondet_bool();
6+
7+
void main()
8+
{
9+
char local;
10+
void *pointer = &local;
11+
const bool make_dynamic = nondet_bool();
12+
if(make_dynamic)
13+
{
14+
pointer = malloc(1);
15+
}
16+
assert(make_dynamic || !__CPROVER_DYNAMIC_OBJECT(pointer));
17+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
CORE
2+
valid.c
3+
--trace
4+
Passing problem to incremental SMT2 solving
5+
line 16 assertion make_dynamic \|\| \!__CPROVER_DYNAMIC_OBJECT\(pointer\)\: SUCCESS
6+
VERIFICATION SUCCESSFUL
7+
^EXIT=0$
8+
^SIGNAL=0$
9+
--
10+
--

src/solvers/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,7 @@ SRC = $(BOOLEFORCE_SRC) \
203203
smt2_incremental/convert_expr_to_smt.cpp \
204204
smt2_incremental/object_tracking.cpp \
205205
smt2_incremental/type_size_mapping.cpp \
206+
smt2_incremental/smt_is_dynamic_object.cpp \
206207
smt2_incremental/smt_object_size.cpp \
207208
smt2_incremental/smt_response_validation.cpp \
208209
smt2_incremental/smt_solver_process.cpp \

src/solvers/smt2_incremental/convert_expr_to_smt.cpp

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1042,11 +1042,18 @@ static smt_termt convert_expr_to_smt(
10421042

10431043
static smt_termt convert_expr_to_smt(
10441044
const is_dynamic_object_exprt &is_dynamic_object,
1045-
const sub_expression_mapt &converted)
1045+
const sub_expression_mapt &converted,
1046+
const smt_is_dynamic_objectt::make_applicationt &apply_is_dynamic_object)
10461047
{
1047-
UNIMPLEMENTED_FEATURE(
1048-
"Generation of SMT formula for is dynamic object expression: " +
1049-
is_dynamic_object.pretty());
1048+
const smt_termt &pointer = converted.at(is_dynamic_object.address());
1049+
const auto pointer_sort = pointer.get_sort().cast<smt_bit_vector_sortt>();
1050+
INVARIANT(
1051+
pointer_sort, "Pointers should be encoded as bit vector sorted terms.");
1052+
const std::size_t pointer_width = pointer_sort->bit_width();
1053+
return apply_is_dynamic_object(
1054+
std::vector<smt_termt>{smt_bit_vector_theoryt::extract(
1055+
pointer_width - 1,
1056+
pointer_width - config.bv_encoding.object_bits)(pointer)});
10501057
}
10511058

10521059
static smt_termt convert_expr_to_smt(
@@ -1458,7 +1465,8 @@ static smt_termt dispatch_expr_to_smt_conversion(
14581465
const sub_expression_mapt &converted,
14591466
const smt_object_mapt &object_map,
14601467
const type_size_mapt &pointer_sizes,
1461-
const smt_object_sizet::make_applicationt &call_object_size)
1468+
const smt_object_sizet::make_applicationt &call_object_size,
1469+
const smt_is_dynamic_objectt::make_applicationt &apply_is_dynamic_object)
14621470
{
14631471
if(const auto symbol = expr_try_dynamic_cast<symbol_exprt>(expr))
14641472
{
@@ -1660,7 +1668,8 @@ static smt_termt dispatch_expr_to_smt_conversion(
16601668
const auto is_dynamic_object =
16611669
expr_try_dynamic_cast<is_dynamic_object_exprt>(expr))
16621670
{
1663-
return convert_expr_to_smt(*is_dynamic_object, converted);
1671+
return convert_expr_to_smt(
1672+
*is_dynamic_object, converted, apply_is_dynamic_object);
16641673
}
16651674
if(
16661675
const auto is_invalid_pointer =
@@ -1837,7 +1846,8 @@ smt_termt convert_expr_to_smt(
18371846
const exprt &expr,
18381847
const smt_object_mapt &object_map,
18391848
const type_size_mapt &pointer_sizes,
1840-
const smt_object_sizet::make_applicationt &object_size)
1849+
const smt_object_sizet::make_applicationt &object_size,
1850+
const smt_is_dynamic_objectt::make_applicationt &is_dynamic_object)
18411851
{
18421852
#ifndef CPROVER_INVARIANT_DO_NOT_CHECK
18431853
static bool in_conversion = false;
@@ -1856,7 +1866,12 @@ smt_termt convert_expr_to_smt(
18561866
if(find_result != sub_expression_map.cend())
18571867
return;
18581868
smt_termt term = dispatch_expr_to_smt_conversion(
1859-
expr, sub_expression_map, object_map, pointer_sizes, object_size);
1869+
expr,
1870+
sub_expression_map,
1871+
object_map,
1872+
pointer_sizes,
1873+
object_size,
1874+
is_dynamic_object);
18601875
sub_expression_map.emplace_hint(find_result, expr, std::move(term));
18611876
});
18621877
return std::move(sub_expression_map.at(lowered_expr));

src/solvers/smt2_incremental/convert_expr_to_smt.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include <solvers/smt2_incremental/ast/smt_sorts.h>
77
#include <solvers/smt2_incremental/ast/smt_terms.h>
88
#include <solvers/smt2_incremental/object_tracking.h>
9+
#include <solvers/smt2_incremental/smt_is_dynamic_object.h>
910
#include <solvers/smt2_incremental/smt_object_size.h>
1011
#include <solvers/smt2_incremental/type_size_mapping.h>
1112

@@ -27,6 +28,7 @@ smt_termt convert_expr_to_smt(
2728
const exprt &expression,
2829
const smt_object_mapt &object_map,
2930
const type_size_mapt &pointer_sizes,
30-
const smt_object_sizet::make_applicationt &object_size);
31+
const smt_object_sizet::make_applicationt &object_size,
32+
const smt_is_dynamic_objectt::make_applicationt &is_dynamic_object);
3133

3234
#endif // CPROVER_SOLVERS_SMT2_INCREMENTAL_CONVERT_EXPR_TO_SMT_H

src/solvers/smt2_incremental/object_tracking.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
#include <util/arith_tools.h>
66
#include <util/c_types.h>
77
#include <util/pointer_offset_size.h>
8+
#include <util/pointer_predicates.h>
9+
#include <util/prefix.h>
810
#include <util/std_code.h>
911
#include <util/std_expr.h>
1012
#include <util/string_constant.h>
@@ -49,6 +51,7 @@ static decision_procedure_objectt make_null_object()
4951
null_object.unique_id = 0;
5052
null_object.base_expression = null_pointer_exprt{pointer_type(void_type())};
5153
null_object.size = from_integer(0, size_type());
54+
null_object.is_dynamic = false;
5255
return null_object;
5356
}
5457

@@ -60,6 +63,7 @@ static decision_procedure_objectt make_invalid_pointer_object()
6063
invalid_pointer_object.unique_id = 1;
6164
invalid_pointer_object.base_expression = make_invalid_pointer_expr();
6265
invalid_pointer_object.size = from_integer(0, size_type());
66+
invalid_pointer_object.is_dynamic = false;
6367
return invalid_pointer_object;
6468
}
6569

@@ -77,6 +81,23 @@ smt_object_mapt initial_smt_object_map()
7781
return object_map;
7882
}
7983

84+
/// This function returns true for heap allocated objects or false for stack
85+
/// allocated objects.
86+
static bool is_dynamic(const exprt &object)
87+
{
88+
// This check corresponds to the symbols created in
89+
// `goto_symext::symex_allocate`, which implements the `__CPROVER_allocate`
90+
// intrinsic function used by the standard library models.
91+
const bool dynamic_type = object.type().get_bool(ID_C_dynamic);
92+
if(dynamic_type)
93+
return true;
94+
const auto symbol = expr_try_dynamic_cast<symbol_exprt>(object);
95+
bool symbol_is_dynamic =
96+
symbol &&
97+
has_prefix(id2string(symbol->get_identifier()), SYMEX_DYNAMIC_PREFIX);
98+
return symbol_is_dynamic;
99+
}
100+
80101
void track_expression_objects(
81102
const exprt &expression,
82103
const namespacet &ns,
@@ -93,6 +114,7 @@ void track_expression_objects(
93114
object.base_expression = object_base;
94115
object.unique_id = object_map.size();
95116
object.size = *size;
117+
object.is_dynamic = is_dynamic(object_base);
96118
object_map.emplace_hint(find_result, object_base, std::move(object));
97119
});
98120
}

src/solvers/smt2_incremental/object_tracking.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,11 @@ struct decision_procedure_objectt
4343
/// to deferencing a pointer to this object with a zero offset.
4444
exprt base_expression;
4545
/// Number which uniquely identifies this particular object.
46-
std::size_t unique_id;
46+
std::size_t unique_id = 0;
4747
/// Expression which evaluates to the size of the object in bytes.
4848
exprt size;
49+
/// This is true for heap allocated objects and false for stack allocated.
50+
bool is_dynamic = false;
4951
};
5052

5153
/// 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: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,7 @@ smt2_incremental_decision_proceduret::smt2_incremental_decision_proceduret(
255255
smt_set_option_commandt{smt_option_produce_modelst{true}});
256256
solver_process->send(smt_set_logic_commandt{smt_logic_allt{}});
257257
solver_process->send(object_size_function.declaration);
258+
solver_process->send(is_dynamic_object_function.declaration);
258259
}
259260

260261
void smt2_incremental_decision_proceduret::ensure_handle_for_expr_defined(
@@ -321,12 +322,14 @@ smt2_incremental_decision_proceduret::convert_expr_to_smt(const exprt &expr)
321322
ns,
322323
pointer_sizes_map,
323324
object_map,
324-
object_size_function.make_application);
325+
object_size_function.make_application,
326+
is_dynamic_object_function.make_application);
325327
return ::convert_expr_to_smt(
326328
substituted,
327329
object_map,
328330
pointer_sizes_map,
329-
object_size_function.make_application);
331+
object_size_function.make_application,
332+
is_dynamic_object_function.make_application);
330333
}
331334

332335
exprt smt2_incremental_decision_proceduret::handle(const exprt &expr)
@@ -376,7 +379,8 @@ array_exprt smt2_incremental_decision_proceduret::get_expr(
376379
from_integer(index, index_type),
377380
object_map,
378381
pointer_sizes_map,
379-
object_size_function.make_application)),
382+
object_size_function.make_application,
383+
is_dynamic_object_function.make_application)),
380384
type.element_type()));
381385
}
382386
return array_exprt{elements, type};
@@ -442,7 +446,8 @@ exprt smt2_incremental_decision_proceduret::get(const exprt &expr) const
442446
expr,
443447
object_map,
444448
pointer_sizes_map,
445-
object_size_function.make_application);
449+
object_size_function.make_application,
450+
is_dynamic_object_function.make_application);
446451
}
447452
else
448453
{
@@ -548,26 +553,28 @@ static decision_proceduret::resultt lookup_decision_procedure_result(
548553
UNREACHABLE;
549554
}
550555

551-
void smt2_incremental_decision_proceduret::define_object_sizes()
556+
void smt2_incremental_decision_proceduret::define_object_properties()
552557
{
553-
object_size_defined.resize(object_map.size());
558+
object_properties_defined.resize(object_map.size());
554559
for(const auto &key_value : object_map)
555560
{
556561
const decision_procedure_objectt &object = key_value.second;
557-
if(object_size_defined[object.unique_id])
562+
if(object_properties_defined[object.unique_id])
558563
continue;
559564
else
560-
object_size_defined[object.unique_id] = true;
565+
object_properties_defined[object.unique_id] = true;
561566
define_dependent_functions(object.size);
562567
solver_process->send(object_size_function.make_definition(
563568
object.unique_id, convert_expr_to_smt(object.size)));
569+
solver_process->send(is_dynamic_object_function.make_definition(
570+
object.unique_id, object.is_dynamic));
564571
}
565572
}
566573

567574
decision_proceduret::resultt smt2_incremental_decision_proceduret::dec_solve()
568575
{
569576
++number_of_solver_calls;
570-
define_object_sizes();
577+
define_object_properties();
571578
const smt_responset result = get_response_to_command(
572579
*solver_process, smt_check_sat_commandt{}, identifier_table);
573580
if(const auto check_sat_response = result.cast<smt_check_sat_responset>())

src/solvers/smt2_incremental/smt2_incremental_decision_procedure.h

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
#include <solvers/smt2_incremental/ast/smt_terms.h>
1313
#include <solvers/smt2_incremental/object_tracking.h>
14+
#include <solvers/smt2_incremental/smt_is_dynamic_object.h>
1415
#include <solvers/smt2_incremental/smt_object_size.h>
1516
#include <solvers/smt2_incremental/type_size_mapping.h>
1617
#include <solvers/stack_decision_procedure.h>
@@ -92,8 +93,9 @@ class smt2_incremental_decision_proceduret final
9293
/// \note This function is non-const because it mutates the object_map.
9394
smt_termt convert_expr_to_smt(const exprt &expr);
9495
void define_index_identifiers(const exprt &expr);
95-
/// Sends the solver the definitions of the object sizes.
96-
void define_object_sizes();
96+
/// Sends the solver the definitions of the object sizes and dynamic memory
97+
/// statuses.
98+
void define_object_properties();
9799

98100
/// Namespace for looking up the expressions which symbol_exprts relate to.
99101
/// This includes the symbols defined outside of the decision procedure but
@@ -149,16 +151,21 @@ class smt2_incremental_decision_proceduret final
149151
/// This map is used to track object related state. See documentation in
150152
/// object_tracking.h for details.
151153
smt_object_mapt object_map;
152-
/// The size of each object is separately defined as a pre-solving step.
153-
/// `object_size_defined[object ID]` is set to true for objects where the size
154-
/// has been defined. This is used to avoid defining the size of the same
155-
/// object multiple times in the case where multiple rounds of solving are
156-
/// carried out.
157-
std::vector<bool> object_size_defined;
154+
/// The size of each object and the dynamic object stus is separately defined
155+
/// as a pre-solving step. `object_properties_defined[object ID]` is set to
156+
/// true for objects where the size has been defined. This is used to avoid
157+
/// defining the size of the same object multiple times in the case where
158+
/// multiple rounds of solving are carried out.
159+
std::vector<bool> object_properties_defined;
158160
/// Implementation of the SMT formula for the object size function. This is
159161
/// stateful because it depends on the configuration of the number of object
160162
/// bits and how many bits wide the size type is configured to be.
161163
smt_object_sizet object_size_function;
164+
/// Implementation of the SMT formula for the dynamic object status lookup
165+
/// function. This is stateful because it depends on the configuration of the
166+
/// number of object bits and how many bits wide the size type is configured
167+
/// to be.
168+
smt_is_dynamic_objectt is_dynamic_object_function;
162169
/// Precalculated type sizes used for pointer arithmetic.
163170
type_size_mapt pointer_sizes_map;
164171
};

0 commit comments

Comments
 (0)