@@ -72,7 +72,7 @@ typedef struct
72
72
/// \brief Set of freeable pointers derived from the contract (indexed mode)
73
73
__CPROVER_contracts_obj_set_t contract_frees ;
74
74
/// \brief Set of freeable pointers derived from the contract (append mode)
75
- __CPROVER_contracts_obj_set_t contract_frees_replacement ;
75
+ __CPROVER_contracts_obj_set_t contract_frees_append ;
76
76
/// \brief Set of objects allocated by the function under analysis
77
77
/// (indexed mode)
78
78
__CPROVER_contracts_obj_set_t allocated ;
@@ -83,12 +83,9 @@ typedef struct
83
83
/// (indexed mode)
84
84
__CPROVER_contracts_obj_set_ptr_t linked_is_fresh ;
85
85
/// \brief Object set recording the is_fresh allocations in post conditions
86
- /// (replacement mode only)
87
86
__CPROVER_contracts_obj_set_ptr_t linked_allocated ;
88
87
/// \brief Object set recording the deallocations (used by was_freed)
89
88
__CPROVER_contracts_obj_set_ptr_t linked_deallocated ;
90
- /// \brief True iff this write set is used for contract replacement
91
- __CPROVER_bool replacement ;
92
89
/// \brief True iff the write set checks requires clauses in an assumption ctx
93
90
__CPROVER_bool assume_requires_ctx ;
94
91
/// \brief True iff the write set checks requires clauses in an assertion ctx
@@ -97,6 +94,10 @@ typedef struct
97
94
__CPROVER_bool assume_ensures_ctx ;
98
95
/// \brief True iff this write set checks ensures clauses in an assertion ctx
99
96
__CPROVER_bool assert_ensures_ctx ;
97
+ /// \brief True iff dynamic allocation is allowed (default: true)
98
+ __CPROVER_bool allow_allocate ;
99
+ /// \brief True iff dynamic deallocation is allowed (default: true)
100
+ __CPROVER_bool allow_deallocate ;
100
101
} __CPROVER_contracts_write_set_t ;
101
102
102
103
/// \brief Type of pointers to \ref __CPROVER_contracts_write_set_t.
@@ -388,7 +389,6 @@ __CPROVER_HIDE:;
388
389
/// \param[inout] set Pointer to the object to initialise
389
390
/// \param[in] contract_assigns_size Max size of the assigns clause
390
391
/// \param[in] contract_frees_size Max size of the frees clause
391
- /// \param[in] replacement True iff this write set is used to replace a contract
392
392
/// \param[in] assume_requires_ctx True iff this write set is used to check side
393
393
/// effects in a requires clause in contract checking mode
394
394
/// \param[in] assert_requires_ctx True iff this write set is used to check side
@@ -397,15 +397,20 @@ __CPROVER_HIDE:;
397
397
/// side effects in an ensures clause in contract replacement mode
398
398
/// \param[in] assert_ensures_ctx True iff this write set is used to check for
399
399
/// side effects in an ensures clause in contract checking mode
400
+ /// \param[in] allow_allocate True iff the context gobally allows dynamic
401
+ /// allocation.
402
+ /// \param[in] allow_deallocate True iff the context gobally allows dynamic
403
+ /// deallocation.
400
404
void __CPROVER_contracts_write_set_create (
401
405
__CPROVER_contracts_write_set_ptr_t set ,
402
406
__CPROVER_size_t contract_assigns_size ,
403
407
__CPROVER_size_t contract_frees_size ,
404
- __CPROVER_bool replacement ,
405
408
__CPROVER_bool assume_requires_ctx ,
406
409
__CPROVER_bool assert_requires_ctx ,
407
410
__CPROVER_bool assume_ensures_ctx ,
408
- __CPROVER_bool assert_ensures_ctx )
411
+ __CPROVER_bool assert_ensures_ctx ,
412
+ __CPROVER_bool allow_allocate ,
413
+ __CPROVER_bool allow_deallocate )
409
414
{
410
415
__CPROVER_HIDE :;
411
416
#ifdef DFCC_DEBUG
@@ -417,16 +422,8 @@ __CPROVER_HIDE:;
417
422
& (set -> contract_assigns ), contract_assigns_size );
418
423
__CPROVER_contracts_obj_set_create_indexed_by_object_id (
419
424
& (set -> contract_frees ));
420
- set -> replacement = replacement ;
421
- if (replacement )
422
- {
423
- __CPROVER_contracts_obj_set_create_append (
424
- & (set -> contract_frees_replacement ), contract_frees_size );
425
- }
426
- else
427
- {
428
- set -> contract_frees_replacement .elems = 0 ;
429
- }
425
+ __CPROVER_contracts_obj_set_create_append (
426
+ & (set -> contract_frees_append ), contract_frees_size );
430
427
__CPROVER_contracts_obj_set_create_indexed_by_object_id (& (set -> allocated ));
431
428
__CPROVER_contracts_obj_set_create_indexed_by_object_id (& (set -> deallocated ));
432
429
set -> linked_is_fresh = 0 ;
@@ -436,6 +433,8 @@ __CPROVER_HIDE:;
436
433
set -> assert_requires_ctx = assert_requires_ctx ;
437
434
set -> assume_ensures_ctx = assume_ensures_ctx ;
438
435
set -> assert_ensures_ctx = assert_ensures_ctx ;
436
+ set -> allow_allocate = allow_allocate ;
437
+ set -> allow_deallocate = allow_deallocate ;
439
438
}
440
439
441
440
/// \brief Releases resources used by \p set.
@@ -454,20 +453,16 @@ __CPROVER_HIDE:;
454
453
__CPROVER_rw_ok (& (set -> contract_frees .elems ), 0 ),
455
454
"contract_frees writable" );
456
455
__CPROVER_assert (
457
- (set -> replacement == 0 ) ||
458
- __CPROVER_rw_ok (& (set -> contract_frees_replacement .elems ), 0 ),
459
- "contract_frees_replacement writable" );
456
+ __CPROVER_rw_ok (& (set -> contract_frees_append .elems ), 0 ),
457
+ "contract_frees_append writable" );
460
458
__CPROVER_assert (
461
459
__CPROVER_rw_ok (& (set -> allocated .elems ), 0 ), "allocated writable" );
462
460
__CPROVER_assert (
463
461
__CPROVER_rw_ok (& (set -> deallocated .elems ), 0 ), "deallocated writable" );
464
462
#endif
465
463
__CPROVER_deallocate (set -> contract_assigns .elems );
466
464
__CPROVER_deallocate (set -> contract_frees .elems );
467
- if (set -> replacement != 0 )
468
- {
469
- __CPROVER_deallocate (set -> contract_frees_replacement .elems );
470
- }
465
+ __CPROVER_deallocate (set -> contract_frees_append .elems );
471
466
__CPROVER_deallocate (set -> allocated .elems );
472
467
__CPROVER_deallocate (set -> deallocated .elems );
473
468
// do not free set->linked_is_fresh->elems or set->deallocated_linked->elems
@@ -585,29 +580,44 @@ __CPROVER_HIDE:;
585
580
586
581
// append pointer if available
587
582
#ifdef DFCC_DEBUG
588
- if (set -> replacement )
589
- __CPROVER_contracts_obj_set_append (& (set -> contract_frees_replacement ), ptr );
583
+ __CPROVER_contracts_obj_set_append (& (set -> contract_frees_append ), ptr );
590
584
#else
591
- if (set -> replacement )
592
- {
593
- set -> contract_frees_replacement .nof_elems =
594
- set -> contract_frees_replacement .watermark ;
595
- set -> contract_frees_replacement
596
- .elems [set -> contract_frees_replacement .watermark ] = ptr ;
597
- set -> contract_frees_replacement .watermark += 1 ;
598
- set -> contract_frees_replacement .is_empty = 0 ;
599
- }
585
+ set -> contract_frees_append .nof_elems = set -> contract_frees_append .watermark ;
586
+ set -> contract_frees_append .elems [set -> contract_frees_append .watermark ] = ptr ;
587
+ set -> contract_frees_append .watermark += 1 ;
588
+ set -> contract_frees_append .is_empty = 0 ;
600
589
#endif
601
590
}
602
591
603
- /// \brief Adds the pointer \p ptr to \p set->allocated.
592
+ /// \brief Adds the dynamically allocated pointer \p ptr to \p set->allocated.
604
593
/// \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.
594
+ /// \param[in] ptr Pointer to a dynamic object `x = __CPROVER_allocate(...)`.
607
595
void __CPROVER_contracts_write_set_add_allocated (
608
596
__CPROVER_contracts_write_set_ptr_t set ,
609
597
void * ptr )
610
598
{
599
+ __CPROVER_HIDE :;
600
+ __CPROVER_assert (set -> allow_allocate , "dynamic allocation is allowed" );
601
+ #if DFCC_DEBUG
602
+ // call inlined below
603
+ __CPROVER_contracts_obj_set_add (& (set -> allocated ), ptr );
604
+ #else
605
+ __CPROVER_size_t object_id = __CPROVER_POINTER_OBJECT (ptr );
606
+ set -> allocated .nof_elems = (set -> allocated .elems [object_id ] != 0 )
607
+ ? set -> allocated .nof_elems
608
+ : set -> allocated .nof_elems + 1 ;
609
+ set -> allocated .elems [object_id ] = ptr ;
610
+ set -> allocated .is_empty = 0 ;
611
+ #endif
612
+ }
613
+
614
+ /// \brief Adds the pointer \p ptr to \p set->allocated.
615
+ /// \param[inout] set The set to update
616
+ /// \param[in] ptr Pointer to an object declared using `DECL x`.
617
+ void __CPROVER_contracts_write_set_add_decl (
618
+ __CPROVER_contracts_write_set_ptr_t set ,
619
+ void * ptr )
620
+ {
611
621
__CPROVER_HIDE :;
612
622
#if DFCC_DEBUG
613
623
// call inlined below
@@ -659,10 +669,6 @@ void __CPROVER_contracts_write_set_record_deallocated(
659
669
void * ptr )
660
670
{
661
671
__CPROVER_HIDE :;
662
- #ifdef DFCC_DEBUG
663
- __CPROVER_assert (set -> replacement == 0 , "!replacement" );
664
- #endif
665
-
666
672
#if DFCC_DEBUG
667
673
// we record the deallocation to be able to evaluate was_freed post conditions
668
674
__CPROVER_contracts_obj_set_add (& (set -> deallocated ), ptr );
@@ -735,7 +741,6 @@ __CPROVER_bool __CPROVER_contracts_write_set_check_assignment(
735
741
// manually inlined below
736
742
{
737
743
__CPROVER_HIDE :;
738
- __CPROVER_assert (set -> replacement == 0 , "!replacement" );
739
744
__CPROVER_assert (
740
745
((ptr == 0 ) | __CPROVER_rw_ok (ptr , size )),
741
746
"ptr NULL or writable up to size" );
@@ -904,16 +909,13 @@ __CPROVER_HIDE:;
904
909
/// \param[in] set Write set to check the deallocation against
905
910
/// \param[in] ptr Deallocated pointer to check set to check the deallocation
906
911
/// against
907
- /// \return True iff \p ptr is contained in \p set->contract_frees or
908
- /// \p set->allocated.
912
+ /// \return True iff deallocation is allowed and \p ptr is contained in
913
+ /// \p set->contract_frees or \p set-> allocated.
909
914
__CPROVER_bool __CPROVER_contracts_write_set_check_deallocate (
910
915
__CPROVER_contracts_write_set_ptr_t set ,
911
916
void * ptr )
912
917
{
913
918
__CPROVER_HIDE :;
914
- #ifdef DFCC_DEBUG
915
- __CPROVER_assert (set -> replacement == 0 , "!replacement" );
916
- #endif
917
919
__CPROVER_size_t object_id = __CPROVER_POINTER_OBJECT (ptr );
918
920
919
921
#ifdef DFCC_DEBUG
@@ -924,16 +926,15 @@ __CPROVER_HIDE:;
924
926
set -> allocated .indexed_by_object_id ,
925
927
"set->allocated is indexed by object id" );
926
928
#endif
927
- return (ptr == 0 ) | (set -> contract_frees .elems [object_id ] == ptr ) |
928
- (set -> allocated .elems [object_id ] == ptr );
929
+ return (set -> allow_deallocate ) &
930
+ ((ptr == 0 ) | (set -> contract_frees .elems [object_id ] == ptr ) |
931
+ (set -> allocated .elems [object_id ] == ptr ));
929
932
}
930
933
931
934
/// \brief Checks the inclusion of the \p candidate->contract_assigns elements
932
935
/// in \p reference->contract_assigns or \p reference->allocated.
933
936
///
934
- /// \pre \p reference must not be in replacement mode.
935
- /// \pre \p candidate must be in replacement mode and \p candidate->allocated
936
- /// must be empty.
937
+ /// \pre \p candidate->allocated must be empty.
937
938
///
938
939
/// \param[in] reference Reference write set from a caller
939
940
/// \param[in] candidate Candidate write set from a contract being replaced
@@ -944,11 +945,6 @@ __CPROVER_bool __CPROVER_contracts_write_set_check_assigns_clause_inclusion(
944
945
__CPROVER_contracts_write_set_ptr_t candidate )
945
946
{
946
947
__CPROVER_HIDE :;
947
- #ifdef DFCC_DEBUG
948
- __CPROVER_assert (
949
- reference -> replacement == 0 , "reference set in !replacement" );
950
- __CPROVER_assert (candidate -> replacement != 0 , "candidate set in replacement" );
951
- #endif
952
948
__CPROVER_bool incl = 1 ;
953
949
__CPROVER_contracts_car_t * current = candidate -> contract_assigns .elems ;
954
950
__CPROVER_size_t idx = candidate -> contract_assigns .max_elems ;
@@ -969,9 +965,7 @@ __CPROVER_HIDE:;
969
965
/// \brief Checks the inclusion of the \p candidate->contract_frees elements
970
966
/// in \p reference->contract_frees or \p reference->allocated.
971
967
///
972
- /// \pre \p reference must not be in replacement mode.
973
- /// \pre \p candidate must be in replacement mode and \p candidate->allocated
974
- /// must be empty.
968
+ /// \pre \p candidate->allocated must be empty.
975
969
///
976
970
/// \param[in] reference Reference write set from a caller
977
971
/// \param[in] candidate Candidate write set from a contract being replaced
@@ -983,9 +977,6 @@ __CPROVER_bool __CPROVER_contracts_write_set_check_frees_clause_inclusion(
983
977
{
984
978
__CPROVER_HIDE :;
985
979
#ifdef DFCC_DEBUG
986
- __CPROVER_assert (
987
- reference -> replacement == 0 , "reference set in !replacement" );
988
- __CPROVER_assert (candidate -> replacement != 0 , "candidate set in replacement" );
989
980
__CPROVER_assert (
990
981
reference -> contract_frees .indexed_by_object_id ,
991
982
"reference->contract_frees is indexed by object id" );
@@ -994,8 +985,8 @@ __CPROVER_HIDE:;
994
985
"reference->allocated is indexed by object id" );
995
986
#endif
996
987
__CPROVER_bool all_incl = 1 ;
997
- void * * current = candidate -> contract_frees_replacement .elems ;
998
- __CPROVER_size_t idx = candidate -> contract_frees_replacement .max_elems ;
988
+ void * * current = candidate -> contract_frees_append .elems ;
989
+ __CPROVER_size_t idx = candidate -> contract_frees_append .max_elems ;
999
990
1000
991
SET_CHECK_FREES_CLAUSE_INCLUSION_LOOP :
1001
992
while (idx != 0 )
@@ -1030,13 +1021,8 @@ void __CPROVER_contracts_write_set_deallocate_freeable(
1030
1021
__CPROVER_contracts_write_set_ptr_t target )
1031
1022
{
1032
1023
__CPROVER_HIDE :;
1033
- #ifdef DFCC_DEBUG
1034
- __CPROVER_assert (set -> replacement == 1 , "set is in replacement" );
1035
- __CPROVER_assert (
1036
- (target == 0 ) | (target -> replacement == 0 ), "target is in !replacement" );
1037
- #endif
1038
- void * * current = set -> contract_frees_replacement .elems ;
1039
- __CPROVER_size_t idx = set -> contract_frees_replacement .max_elems ;
1024
+ void * * current = set -> contract_frees_append .elems ;
1025
+ __CPROVER_size_t idx = set -> contract_frees_append .max_elems ;
1040
1026
SET_DEALLOCATE_FREEABLE_LOOP :
1041
1027
while (idx != 0 )
1042
1028
{
0 commit comments