Skip to content

Commit 2d5a8b2

Browse files
author
Remi Delmas
committed
Use demonic tracking for fresh ID set, checking ptr predicate uniqueness
Replaces the array used to track fresh object IDs with a single nondet variable. Add another nondet variable to track locations that store pointers on which some pointer predicate was assumed or successfully asserted, and ensures that at most one pointer predicate is established at any time.
1 parent 0b1231c commit 2d5a8b2

File tree

1 file changed

+140
-59
lines changed

1 file changed

+140
-59
lines changed

Diff for: src/ansi-c/library/cprover_contracts.c

+140-59
Original file line numberDiff line numberDiff line change
@@ -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,61 @@ __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+
void __CPROVER_contracts_record_ptr_in_ptr_pred(
343+
__CPROVER_contracts_obj_set_ptr_t set,
344+
void **ptr)
345+
{
346+
__CPROVER_HIDE:;
347+
if(set->ptr_pred_empty)
348+
{
349+
set->ptr_pred_empty = 0;
350+
set->ptr_pred = ptr;
351+
}
352+
else
353+
{
354+
set->ptr_pred = __VERIFIER_nondet___CPROVER_bool() ? ptr : set->ptr_pred;
355+
}
289356
}
290357

291358
/// @brief Releases resources used by \p set.
@@ -1202,7 +1269,13 @@ __CPROVER_HIDE:;
12021269
}
12031270
__CPROVER_assert(
12041271
(ptr2 == 0) || __CPROVER_r_ok(ptr2, 0),
1205-
"pointer_equals is only called with valid pointers");
1272+
"__CPROVER_pointer_equals is only called with valid pointers");
1273+
__CPROVER_assert(
1274+
__CPROVER_contracts_check_ptr_not_in_ptr_pred(
1275+
write_set->linked_is_fresh, ptr1),
1276+
"__CPROVER_pointer_equals does not conflict with other predicate");
1277+
__CPROVER_contracts_record_ptr_in_ptr_pred(
1278+
write_set->linked_is_fresh, ptr1);
12061279
*ptr1 = ptr2;
12071280
return 1;
12081281
}
@@ -1211,11 +1284,21 @@ __CPROVER_HIDE:;
12111284
void *derefd = *ptr1;
12121285
__CPROVER_assert(
12131286
(derefd == 0) || __CPROVER_r_ok(derefd, 0),
1214-
"pointer_equals is only called with valid pointers");
1287+
"__CPROVER_pointer_equals is only called with valid pointers");
12151288
__CPROVER_assert(
12161289
(ptr2 == 0) || __CPROVER_r_ok(ptr2, 0),
1217-
"pointer_equals is only called with valid pointers");
1218-
return derefd == ptr2;
1290+
"__CPROVER_pointer_equals is only called with valid pointers");
1291+
if(derefd != ptr2)
1292+
{
1293+
return 0;
1294+
}
1295+
__CPROVER_assert(
1296+
__CPROVER_contracts_check_ptr_not_in_ptr_pred(
1297+
write_set->linked_is_fresh, ptr1),
1298+
"__CPROVER_pointer_equals does not conflict with other predicate");
1299+
__CPROVER_contracts_record_ptr_in_ptr_pred(
1300+
write_set->linked_is_fresh, ptr1);
1301+
return 1;
12191302
}
12201303
}
12211304

@@ -1294,9 +1377,15 @@ __CPROVER_HIDE:;
12941377
__CPROVER_contracts_make_invalid_pointer(elem);
12951378
return 0;
12961379
}
1297-
12981380
void *ptr = __CPROVER_allocate(size, 0);
12991381
*elem = ptr;
1382+
__CPROVER_assert(
1383+
__CPROVER_contracts_check_ptr_not_in_ptr_pred(
1384+
write_set->linked_is_fresh, elem),
1385+
"__CPROVER_is_fresh does not conflict with other predicate");
1386+
__CPROVER_contracts_record_ptr_in_ptr_pred(
1387+
write_set->linked_is_fresh, elem);
1388+
__CPROVER_contracts_record_fresh_id(write_set->linked_is_fresh, ptr);
13001389

13011390
// record the object size for non-determistic bounds checking
13021391
__CPROVER_bool record_malloc = __VERIFIER_nondet___CPROVER_bool();
@@ -1308,18 +1397,6 @@ __CPROVER_HIDE:;
13081397
// __CPROVER_bool record_may_leak = __VERIFIER_nondet___CPROVER_bool();
13091398
// __CPROVER_memory_leak = record_may_leak ? ptr : __CPROVER_memory_leak;
13101399

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
13231400
return 1;
13241401
}
13251402
else if(write_set->assume_ensures_ctx)
@@ -1357,6 +1434,13 @@ __CPROVER_HIDE:;
13571434

13581435
void *ptr = __CPROVER_allocate(size, 0);
13591436
*elem = ptr;
1437+
__CPROVER_assert(
1438+
__CPROVER_contracts_check_ptr_not_in_ptr_pred(
1439+
write_set->linked_is_fresh, elem),
1440+
"__CPROVER_is_fresh does not conflict with other predicate");
1441+
__CPROVER_contracts_record_ptr_in_ptr_pred(
1442+
write_set->linked_is_fresh, elem);
1443+
__CPROVER_contracts_record_fresh_id(write_set->linked_is_fresh, ptr);
13601444

13611445
// record the object size for non-determistic bounds checking
13621446
__CPROVER_bool record_malloc = __VERIFIER_nondet___CPROVER_bool();
@@ -1369,17 +1453,6 @@ __CPROVER_HIDE:;
13691453
__CPROVER_bool record_may_leak = __VERIFIER_nondet___CPROVER_bool();
13701454
__CPROVER_memory_leak = record_may_leak ? ptr : __CPROVER_memory_leak;
13711455

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
13831456
return 1;
13841457
}
13851458
else if(write_set->assert_requires_ctx | write_set->assert_ensures_ctx)
@@ -1390,34 +1463,22 @@ __CPROVER_HIDE:;
13901463
(write_set->assume_ensures_ctx == 0),
13911464
"only one context flag at a time");
13921465
#endif
1393-
__CPROVER_contracts_obj_set_ptr_t seen = write_set->linked_is_fresh;
13941466
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);
1467+
if(
1468+
ptr != (void *)0 &&
1469+
__CPROVER_contracts_not_seen_is_fresh(write_set->linked_is_fresh, ptr) &&
1470+
__CPROVER_r_ok(ptr, size))
1471+
{
1472+
__CPROVER_assert(
1473+
__CPROVER_contracts_check_ptr_not_in_ptr_pred(
1474+
write_set->linked_is_fresh, elem),
1475+
"__CPROVER_is_fresh does not conflict with other predicate");
1476+
__CPROVER_contracts_record_ptr_in_ptr_pred(
1477+
write_set->linked_is_fresh, elem);
1478+
__CPROVER_contracts_record_fresh_id(write_set->linked_is_fresh, ptr);
1479+
return 1;
1480+
}
1481+
return 0;
14211482
}
14221483
else
14231484
{
@@ -1484,13 +1545,33 @@ __CPROVER_HIDE:;
14841545
__CPROVER_size_t max_offset = ub_offset - lb_offset;
14851546
__CPROVER_assume(offset <= max_offset);
14861547
*ptr = (char *)lb + offset;
1548+
__CPROVER_assert(
1549+
__CPROVER_contracts_check_ptr_not_in_ptr_pred(
1550+
write_set->linked_is_fresh, ptr),
1551+
"__CPROVER_pointer_in_range_dfcc does not conflict with other predicate");
1552+
__CPROVER_contracts_record_ptr_in_ptr_pred(write_set->linked_is_fresh, ptr);
14871553
return 1;
14881554
}
14891555
else /* write_set->assert_requires_ctx | write_set->assert_ensures_ctx */
14901556
{
14911557
__CPROVER_size_t offset = __CPROVER_POINTER_OFFSET(*ptr);
1492-
return __CPROVER_same_object(lb, *ptr) && lb_offset <= offset &&
1493-
offset <= ub_offset;
1558+
if(
1559+
__CPROVER_same_object(lb, *ptr) && lb_offset <= offset &&
1560+
offset <= ub_offset)
1561+
{
1562+
__CPROVER_assert(
1563+
__CPROVER_contracts_check_ptr_not_in_ptr_pred(
1564+
write_set->linked_is_fresh, ptr),
1565+
"__CPROVER_pointer_in_range_dfcc does not conflict with other "
1566+
"predicate");
1567+
__CPROVER_contracts_record_ptr_in_ptr_pred(
1568+
write_set->linked_is_fresh, ptr);
1569+
return 1;
1570+
}
1571+
else
1572+
{
1573+
return 0;
1574+
}
14941575
}
14951576
}
14961577

0 commit comments

Comments
 (0)