@@ -62,6 +62,15 @@ typedef struct
6262 /// \brief Array of void *pointers, indexed by their object ID
6363 /// or some other order
6464 void * * elems ;
65+ /// \brief Equal to 1 if `fresh_id` is empty, 0 otherwise.
66+ unsigned char fresh_id_empty ;
67+ /// \brief Demonic nondet variable ranging over the set of fresh object IDs.
68+ __CPROVER_size_t fresh_id ;
69+ /// \brief Equal to 1 if `ptr_pred` is empty, 0 otherwise.
70+ unsigned char ptr_pred_empty ;
71+ /// \brief Demonic nondet variable ranging over the set of locations storing
72+ /// pointers on which predicates were assumed/asserted.
73+ void * * ptr_pred ;
6574} __CPROVER_contracts_obj_set_t ;
6675
6776/// \brief Type of pointers to \ref __CPROVER_contracts_car_set_t.
@@ -261,7 +270,11 @@ __CPROVER_HIDE:;
261270 .nof_elems = 0 ,
262271 .is_empty = 1 ,
263272 .indexed_by_object_id = 1 ,
264- .elems = __CPROVER_allocate (nof_objects * sizeof (* (set -> elems )), 1 )};
273+ .elems = __CPROVER_allocate (nof_objects * sizeof (* (set -> elems )), 1 ),
274+ .fresh_id_empty = 1 ,
275+ .fresh_id = 0 ,
276+ .ptr_pred_empty = 1 ,
277+ .ptr_pred = 0 };
265278}
266279
267280/// \brief Initialises a \ref __CPROVER_contracts_obj_set_t object to use it
@@ -285,7 +298,74 @@ __CPROVER_HIDE:;
285298 .nof_elems = 0 ,
286299 .is_empty = 1 ,
287300 .indexed_by_object_id = 0 ,
288- .elems = __CPROVER_allocate (max_elems * sizeof (* (set -> elems )), 1 )};
301+ .elems = __CPROVER_allocate (max_elems * sizeof (* (set -> elems )), 1 ),
302+ .fresh_id_empty = 1 ,
303+ .fresh_id = 0 ,
304+ .ptr_pred_empty = 1 ,
305+ .ptr_pred = 0 };
306+ }
307+
308+ __CPROVER_bool __CPROVER_contracts_not_seen_is_fresh (
309+ __CPROVER_contracts_obj_set_ptr_t set ,
310+ void * ptr )
311+ {
312+ __CPROVER_HIDE :;
313+ return set -> fresh_id_empty || __CPROVER_POINTER_OBJECT (ptr ) != set -> fresh_id ;
314+ }
315+
316+ void __CPROVER_contracts_record_fresh_id (
317+ __CPROVER_contracts_obj_set_ptr_t set ,
318+ void * ptr )
319+ {
320+ __CPROVER_HIDE :;
321+ if (set -> fresh_id_empty )
322+ {
323+ set -> fresh_id_empty = 0 ;
324+ set -> fresh_id = __CPROVER_POINTER_OBJECT (ptr );
325+ }
326+ else
327+ {
328+ set -> fresh_id = __VERIFIER_nondet___CPROVER_bool ()
329+ ? __CPROVER_POINTER_OBJECT (ptr )
330+ : set -> fresh_id ;
331+ }
332+ }
333+
334+ __CPROVER_bool __CPROVER_contracts_check_ptr_not_in_ptr_pred (
335+ __CPROVER_contracts_obj_set_ptr_t set ,
336+ void * * ptr )
337+ {
338+ __CPROVER_HIDE :;
339+ return set -> ptr_pred_empty || ptr != set -> ptr_pred ;
340+ }
341+
342+ /// \brief Resets the nondet tracker for pointer predicates in \p set.
343+ /// Invoked right before evaluating contract ensures clauses. Since functions
344+ /// are allowed to modify the program state, resetting the tracker allows
345+ /// ensures clauses to establish a different pointer predicate on a pointer that
346+ /// was already targeted by the requires clause.
347+ void __CPROVER_contracts_obj_set_reset_ptr_pred (
348+ __CPROVER_contracts_obj_set_ptr_t set )
349+ {
350+ __CPROVER_HIDE :;
351+ set -> ptr_pred_empty = 1 ;
352+ set -> ptr_pred = 0 ;
353+ }
354+
355+ void __CPROVER_contracts_record_ptr_in_ptr_pred (
356+ __CPROVER_contracts_obj_set_ptr_t set ,
357+ void * * ptr )
358+ {
359+ __CPROVER_HIDE :;
360+ if (set -> ptr_pred_empty )
361+ {
362+ set -> ptr_pred_empty = 0 ;
363+ set -> ptr_pred = ptr ;
364+ }
365+ else
366+ {
367+ set -> ptr_pred = __VERIFIER_nondet___CPROVER_bool () ? ptr : set -> ptr_pred ;
368+ }
289369}
290370
291371/// @brief Releases resources used by \p set.
@@ -1202,7 +1282,13 @@ __CPROVER_HIDE:;
12021282 }
12031283 __CPROVER_assert (
12041284 (ptr2 == 0 ) || __CPROVER_r_ok (ptr2 , 0 ),
1205- "pointer_equals is only called with valid pointers" );
1285+ "__CPROVER_pointer_equals is only called with valid pointers" );
1286+ __CPROVER_assert (
1287+ __CPROVER_contracts_check_ptr_not_in_ptr_pred (
1288+ write_set -> linked_is_fresh , ptr1 ),
1289+ "__CPROVER_pointer_equals does not conflict with other predicate" );
1290+ __CPROVER_contracts_record_ptr_in_ptr_pred (
1291+ write_set -> linked_is_fresh , ptr1 );
12061292 * ptr1 = ptr2 ;
12071293 return 1 ;
12081294 }
@@ -1211,11 +1297,21 @@ __CPROVER_HIDE:;
12111297 void * derefd = * ptr1 ;
12121298 __CPROVER_assert (
12131299 (derefd == 0 ) || __CPROVER_r_ok (derefd , 0 ),
1214- "pointer_equals is only called with valid pointers" );
1300+ "__CPROVER_pointer_equals is only called with valid pointers" );
12151301 __CPROVER_assert (
12161302 (ptr2 == 0 ) || __CPROVER_r_ok (ptr2 , 0 ),
1217- "pointer_equals is only called with valid pointers" );
1218- return derefd == ptr2 ;
1303+ "__CPROVER_pointer_equals is only called with valid pointers" );
1304+ if (derefd != ptr2 )
1305+ {
1306+ return 0 ;
1307+ }
1308+ __CPROVER_assert (
1309+ __CPROVER_contracts_check_ptr_not_in_ptr_pred (
1310+ write_set -> linked_is_fresh , ptr1 ),
1311+ "__CPROVER_pointer_equals does not conflict with other predicate" );
1312+ __CPROVER_contracts_record_ptr_in_ptr_pred (
1313+ write_set -> linked_is_fresh , ptr1 );
1314+ return 1 ;
12191315 }
12201316}
12211317
@@ -1294,9 +1390,15 @@ __CPROVER_HIDE:;
12941390 __CPROVER_contracts_make_invalid_pointer (elem );
12951391 return 0 ;
12961392 }
1297-
12981393 void * ptr = __CPROVER_allocate (size , 0 );
12991394 * elem = ptr ;
1395+ __CPROVER_assert (
1396+ __CPROVER_contracts_check_ptr_not_in_ptr_pred (
1397+ write_set -> linked_is_fresh , elem ),
1398+ "__CPROVER_is_fresh does not conflict with other predicate" );
1399+ __CPROVER_contracts_record_ptr_in_ptr_pred (
1400+ write_set -> linked_is_fresh , elem );
1401+ __CPROVER_contracts_record_fresh_id (write_set -> linked_is_fresh , ptr );
13001402
13011403 // record the object size for non-determistic bounds checking
13021404 __CPROVER_bool record_malloc = __VERIFIER_nondet___CPROVER_bool ();
@@ -1308,18 +1410,6 @@ __CPROVER_HIDE:;
13081410 // __CPROVER_bool record_may_leak = __VERIFIER_nondet___CPROVER_bool();
13091411 // __CPROVER_memory_leak = record_may_leak ? ptr : __CPROVER_memory_leak;
13101412
1311- #ifdef __CPROVER_DFCC_DEBUG_LIB
1312- // manually inlined below
1313- __CPROVER_contracts_obj_set_add (write_set -> linked_is_fresh , ptr );
1314- #else
1315- __CPROVER_size_t object_id = __CPROVER_POINTER_OBJECT (ptr );
1316- write_set -> linked_is_fresh -> nof_elems =
1317- (write_set -> linked_is_fresh -> elems [object_id ] != 0 )
1318- ? write_set -> linked_is_fresh -> nof_elems
1319- : write_set -> linked_is_fresh -> nof_elems + 1 ;
1320- write_set -> linked_is_fresh -> elems [object_id ] = ptr ;
1321- write_set -> linked_is_fresh -> is_empty = 0 ;
1322- #endif
13231413 return 1 ;
13241414 }
13251415 else if (write_set -> assume_ensures_ctx )
@@ -1357,6 +1447,13 @@ __CPROVER_HIDE:;
13571447
13581448 void * ptr = __CPROVER_allocate (size , 0 );
13591449 * elem = ptr ;
1450+ __CPROVER_assert (
1451+ __CPROVER_contracts_check_ptr_not_in_ptr_pred (
1452+ write_set -> linked_is_fresh , elem ),
1453+ "__CPROVER_is_fresh does not conflict with other predicate" );
1454+ __CPROVER_contracts_record_ptr_in_ptr_pred (
1455+ write_set -> linked_is_fresh , elem );
1456+ __CPROVER_contracts_record_fresh_id (write_set -> linked_is_fresh , ptr );
13601457
13611458 // record the object size for non-determistic bounds checking
13621459 __CPROVER_bool record_malloc = __VERIFIER_nondet___CPROVER_bool ();
@@ -1369,17 +1466,6 @@ __CPROVER_HIDE:;
13691466 __CPROVER_bool record_may_leak = __VERIFIER_nondet___CPROVER_bool ();
13701467 __CPROVER_memory_leak = record_may_leak ? ptr : __CPROVER_memory_leak ;
13711468
1372- #ifdef __CPROVER_DFCC_DEBUG_LIB
1373- __CPROVER_contracts_obj_set_add (write_set -> linked_allocated , ptr );
1374- #else
1375- __CPROVER_size_t object_id = __CPROVER_POINTER_OBJECT (ptr );
1376- write_set -> linked_allocated -> nof_elems =
1377- (write_set -> linked_allocated -> elems [object_id ] != 0 )
1378- ? write_set -> linked_allocated -> nof_elems
1379- : write_set -> linked_allocated -> nof_elems + 1 ;
1380- write_set -> linked_allocated -> elems [object_id ] = ptr ;
1381- write_set -> linked_allocated -> is_empty = 0 ;
1382- #endif
13831469 return 1 ;
13841470 }
13851471 else if (write_set -> assert_requires_ctx | write_set -> assert_ensures_ctx )
@@ -1390,34 +1476,22 @@ __CPROVER_HIDE:;
13901476 (write_set -> assume_ensures_ctx == 0 ),
13911477 "only one context flag at a time" );
13921478#endif
1393- __CPROVER_contracts_obj_set_ptr_t seen = write_set -> linked_is_fresh ;
13941479 void * ptr = * elem ;
1395- // null pointers or already seen pointers are not fresh
1396- #ifdef __CPROVER_DFCC_DEBUG_LIB
1397- // manually inlined below
1398- if ((ptr == 0 ) || (__CPROVER_contracts_obj_set_contains (seen , ptr )))
1399- return 0 ;
1400- #else
1401- if (ptr == 0 )
1402- return 0 ;
1403-
1404- __CPROVER_size_t object_id = __CPROVER_POINTER_OBJECT (ptr );
1405-
1406- if (seen -> elems [object_id ] != 0 )
1407- return 0 ;
1408- #endif
1409-
1410- #ifdef __CPROVER_DFCC_DEBUG_LIB
1411- // manually inlined below
1412- __CPROVER_contracts_obj_set_add (seen , ptr );
1413- #else
1414- seen -> nof_elems =
1415- (seen -> elems [object_id ] != 0 ) ? seen -> nof_elems : seen -> nof_elems + 1 ;
1416- seen -> elems [object_id ] = ptr ;
1417- seen -> is_empty = 0 ;
1418- #endif
1419- // check size
1420- return __CPROVER_r_ok (ptr , size );
1480+ if (
1481+ ptr != (void * )0 &&
1482+ __CPROVER_contracts_not_seen_is_fresh (write_set -> linked_is_fresh , ptr ) &&
1483+ __CPROVER_r_ok (ptr , size ))
1484+ {
1485+ __CPROVER_assert (
1486+ __CPROVER_contracts_check_ptr_not_in_ptr_pred (
1487+ write_set -> linked_is_fresh , elem ),
1488+ "__CPROVER_is_fresh does not conflict with other predicate" );
1489+ __CPROVER_contracts_record_ptr_in_ptr_pred (
1490+ write_set -> linked_is_fresh , elem );
1491+ __CPROVER_contracts_record_fresh_id (write_set -> linked_is_fresh , ptr );
1492+ return 1 ;
1493+ }
1494+ return 0 ;
14211495 }
14221496 else
14231497 {
@@ -1484,13 +1558,33 @@ __CPROVER_HIDE:;
14841558 __CPROVER_size_t max_offset = ub_offset - lb_offset ;
14851559 __CPROVER_assume (offset <= max_offset );
14861560 * ptr = (char * )lb + offset ;
1561+ __CPROVER_assert (
1562+ __CPROVER_contracts_check_ptr_not_in_ptr_pred (
1563+ write_set -> linked_is_fresh , ptr ),
1564+ "__CPROVER_pointer_in_range_dfcc does not conflict with other predicate" );
1565+ __CPROVER_contracts_record_ptr_in_ptr_pred (write_set -> linked_is_fresh , ptr );
14871566 return 1 ;
14881567 }
14891568 else /* write_set->assert_requires_ctx | write_set->assert_ensures_ctx */
14901569 {
14911570 __CPROVER_size_t offset = __CPROVER_POINTER_OFFSET (* ptr );
1492- return __CPROVER_same_object (lb , * ptr ) && lb_offset <= offset &&
1493- offset <= ub_offset ;
1571+ if (
1572+ __CPROVER_same_object (lb , * ptr ) && lb_offset <= offset &&
1573+ offset <= ub_offset )
1574+ {
1575+ __CPROVER_assert (
1576+ __CPROVER_contracts_check_ptr_not_in_ptr_pred (
1577+ write_set -> linked_is_fresh , ptr ),
1578+ "__CPROVER_pointer_in_range_dfcc does not conflict with other "
1579+ "predicate" );
1580+ __CPROVER_contracts_record_ptr_in_ptr_pred (
1581+ write_set -> linked_is_fresh , ptr );
1582+ return 1 ;
1583+ }
1584+ else
1585+ {
1586+ return 0 ;
1587+ }
14941588 }
14951589}
14961590
0 commit comments