Skip to content

Commit c78a3cc

Browse files
author
Remi Delmas
committed
CONTRACTS: new context tracking flag in write set
This is meant to forbid dynamic allocations in loops. Calls to `add_allocated` will fail an assertion when called on a write set with `allow_allocate` set to false.
1 parent 2335333 commit c78a3cc

File tree

5 files changed

+49
-11
lines changed

5 files changed

+49
-11
lines changed

src/ansi-c/library/cprover_contracts.c

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,8 @@ typedef struct
9797
__CPROVER_bool assume_ensures_ctx;
9898
/// \brief True iff this write set checks ensures clauses in an assertion ctx
9999
__CPROVER_bool assert_ensures_ctx;
100+
/// \brief True iff dynamic allocation is allowed (default: true)
101+
__CPROVER_bool allow_allocate;
100102
} __CPROVER_contracts_write_set_t;
101103

102104
/// \brief Type of pointers to \ref __CPROVER_contracts_write_set_t.
@@ -436,6 +438,7 @@ __CPROVER_HIDE:;
436438
set->assert_requires_ctx = assert_requires_ctx;
437439
set->assume_ensures_ctx = assume_ensures_ctx;
438440
set->assert_ensures_ctx = assert_ensures_ctx;
441+
set->allow_allocate = 1;
439442
}
440443

441444
/// \brief Releases resources used by \p set.
@@ -474,6 +477,13 @@ __CPROVER_HIDE:;
474477
// since they are owned by someone else.
475478
}
476479

480+
/// \brief Forbids dynamic allocation in functions that receive that write set.
481+
void __CPROVER_contracts_write_set_forbid_allocate(
482+
__CPROVER_contracts_write_set_ptr_t set)
483+
{
484+
set->allow_allocate = 0;
485+
}
486+
477487
/// \brief Inserts a snapshot of the range starting at \p ptr of size \p size
478488
/// at index \p idx in \p set->contract_assigns.
479489
/// \param[inout] set The set to update
@@ -600,14 +610,36 @@ __CPROVER_HIDE:;
600610
#endif
601611
}
602612

603-
/// \brief Adds the pointer \p ptr to \p set->allocated.
613+
/// \brief Adds the dynamically allocated pointer \p ptr to \p set->allocated.
604614
/// \param[inout] set The set to update
605-
/// \param[in] ptr Pointer to an object declared using a `DECL x` or
606-
/// `x = __CPROVER_allocate(...)` GOTO instruction.
615+
/// \param[in] ptr Pointer to a dynamic object `x = __CPROVER_allocate(...)`.
607616
void __CPROVER_contracts_write_set_add_allocated(
608617
__CPROVER_contracts_write_set_ptr_t set,
609618
void *ptr)
610619
{
620+
__CPROVER_HIDE:;
621+
__CPROVER_assert(
622+
set->allow_allocate, "dynamic allocation is allowed");
623+
#if DFCC_DEBUG
624+
// call inlined below
625+
__CPROVER_contracts_obj_set_add(&(set->allocated), ptr);
626+
#else
627+
__CPROVER_size_t object_id = __CPROVER_POINTER_OBJECT(ptr);
628+
set->allocated.nof_elems = (set->allocated.elems[object_id] != 0)
629+
? set->allocated.nof_elems
630+
: set->allocated.nof_elems + 1;
631+
set->allocated.elems[object_id] = ptr;
632+
set->allocated.is_empty = 0;
633+
#endif
634+
}
635+
636+
/// \brief Adds the pointer \p ptr to \p set->allocated.
637+
/// \param[inout] set The set to update
638+
/// \param[in] ptr Pointer to an object declared using `DECL x`.
639+
void __CPROVER_contracts_write_set_add_decl(
640+
__CPROVER_contracts_write_set_ptr_t set,
641+
void *ptr)
642+
{
611643
__CPROVER_HIDE:;
612644
#if DFCC_DEBUG
613645
// call inlined below

src/goto-instrument/contracts/dynamic-frames/dfcc_instrument.cpp

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -380,8 +380,7 @@ void dfcc_instrumentt::instrument_function_body(
380380
for(const auto &local_static : local_statics)
381381
{
382382
// automatically add local statics to the write set
383-
insert_add_allocated_call(
384-
function_id, write_set, local_static, begin, body);
383+
insert_add_decl_call(function_id, write_set, local_static, begin, body);
385384

386385
// automatically remove local statics to the write set
387386
insert_record_dead_call(function_id, write_set, local_static, end, body);
@@ -510,7 +509,7 @@ bool dfcc_instrumentt::must_track_decl_or_dead(
510509
return retval;
511510
}
512511

513-
void dfcc_instrumentt::insert_add_allocated_call(
512+
void dfcc_instrumentt::insert_add_decl_call(
514513
const irep_idt &function_id,
515514
const exprt &write_set,
516515
const symbol_exprt &symbol_expr,
@@ -523,7 +522,7 @@ void dfcc_instrumentt::insert_add_allocated_call(
523522

524523
payload.add(goto_programt::make_function_call(
525524
code_function_callt{
526-
library.dfcc_fun_symbol[dfcc_funt::WRITE_SET_ADD_ALLOCATED].symbol_expr(),
525+
library.dfcc_fun_symbol[dfcc_funt::WRITE_SET_ADD_DECL].symbol_expr(),
527526
{write_set, address_of_exprt(symbol_expr)}},
528527
target->source_location()));
529528

@@ -538,7 +537,7 @@ void dfcc_instrumentt::insert_add_allocated_call(
538537
/// ```c
539538
/// DECL x;
540539
/// ----
541-
/// insert_add_allocated_call(...);
540+
/// insert_add_decl_call(...);
542541
/// ```
543542
void dfcc_instrumentt::instrument_decl(
544543
const irep_idt &function_id,
@@ -552,7 +551,7 @@ void dfcc_instrumentt::instrument_decl(
552551

553552
const auto &decl_symbol = target->decl_symbol();
554553
target++;
555-
insert_add_allocated_call(
554+
insert_add_decl_call(
556555
function_id, write_set, decl_symbol, target, goto_program);
557556
target--;
558557
}

src/goto-instrument/contracts/dynamic-frames/dfcc_instrument.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -175,15 +175,15 @@ class dfcc_instrumentt
175175
/// forward.
176176
/// ```
177177
/// IF !write_set GOTO skip_target;
178-
/// CALL __CPROVER_contracts_write_set_add_allocated(write_set, &x);
178+
/// CALL __CPROVER_contracts_write_set_add_decl(write_set, &x);
179179
/// skip_target: SKIP;
180180
/// ```
181181
/// \param function_id Name of the function in which the instructions is added
182182
/// \param write_set The write set to the symbol expr to
183183
/// \param symbol_expr The symbol to add to the write set
184184
/// \param target The instruction pointer to insert at
185185
/// \param goto_program the goto_program being instrumented
186-
void insert_add_allocated_call(
186+
void insert_add_decl_call(
187187
const irep_idt &function_id,
188188
const exprt &write_set,
189189
const symbol_exprt &symbol_expr,

src/goto-instrument/contracts/dynamic-frames/dfcc_library.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@ const std::map<dfcc_funt, irep_idt> create_dfcc_fun_to_name()
7979
CONTRACTS_PREFIX "obj_set_contains_exact"},
8080
{dfcc_funt::WRITE_SET_CREATE, CONTRACTS_PREFIX "write_set_create"},
8181
{dfcc_funt::WRITE_SET_RELEASE, CONTRACTS_PREFIX "write_set_release"},
82+
{dfcc_funt::WRITE_SET_FORBID_ALLOCATE,
83+
CONTRACTS_PREFIX "write_set_forbid_dynamic"},
8284
{dfcc_funt::WRITE_SET_INSERT_ASSIGNABLE,
8385
CONTRACTS_PREFIX "write_set_insert_assignable"},
8486
{dfcc_funt::WRITE_SET_INSERT_OBJECT_WHOLE,
@@ -91,6 +93,7 @@ const std::map<dfcc_funt, irep_idt> create_dfcc_fun_to_name()
9193
CONTRACTS_PREFIX "write_set_add_freeable"},
9294
{dfcc_funt::WRITE_SET_ADD_ALLOCATED,
9395
CONTRACTS_PREFIX "write_set_add_allocated"},
96+
{dfcc_funt::WRITE_SET_ADD_DECL, CONTRACTS_PREFIX "write_set_add_decl"},
9497
{dfcc_funt::WRITE_SET_RECORD_DEAD,
9598
CONTRACTS_PREFIX "write_set_record_dead"},
9699
{dfcc_funt::WRITE_SET_RECORD_DEALLOCATED,

src/goto-instrument/contracts/dynamic-frames/dfcc_library.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ enum class dfcc_funt
7575
WRITE_SET_CREATE,
7676
/// \see __CPROVER_contracts_write_set_release
7777
WRITE_SET_RELEASE,
78+
/// \see __CPROVER_contracts_write_set_forbid_allocate
79+
WRITE_SET_FORBID_ALLOCATE,
7880
/// \see __CPROVER_contracts_write_set_insert_assignable
7981
WRITE_SET_INSERT_ASSIGNABLE,
8082
/// \see __CPROVER_contracts_write_set_insert_object_whole
@@ -87,6 +89,8 @@ enum class dfcc_funt
8789
WRITE_SET_ADD_FREEABLE,
8890
/// \see __CPROVER_contracts_write_set_add_allocated
8991
WRITE_SET_ADD_ALLOCATED,
92+
/// \see __CPROVER_contracts_write_set_add_decl
93+
WRITE_SET_ADD_DECL,
9094
/// \see __CPROVER_contracts_write_set_record_dead
9195
WRITE_SET_RECORD_DEAD,
9296
/// \see __CPROVER_contracts_write_set_record_deallocated

0 commit comments

Comments
 (0)