@@ -1524,11 +1524,40 @@ goto_programt assigns_clauset::havoc_code(
1524
1524
goto_programt havoc_statements;
1525
1525
for (assigns_clause_targett *target : targets)
1526
1526
{
1527
+ // (1) If the assigned target is not a dereference,
1528
+ // only include the havoc_statement
1529
+
1530
+ // (2) If the assigned target is a dereference, do the following:
1531
+
1532
+ // if(!__CPROVER_w_ok(target, 0)) goto z;
1533
+ // havoc_statements
1534
+ // z: skip
1535
+
1536
+ // create the z label
1537
+ goto_programt tmp_z;
1538
+ goto_programt::targett z = tmp_z.add (goto_programt::make_skip (location));
1539
+
1540
+ const auto &target_ptr = target->get_direct_pointer ();
1541
+ if (to_address_of_expr (target_ptr).object ().id () == ID_dereference)
1542
+ {
1543
+ // create the condition
1544
+ exprt condition =
1545
+ not_exprt (w_ok_exprt (target_ptr, from_integer (0 , integer_typet ())));
1546
+ havoc_statements.add (goto_programt::make_goto (z, condition, location));
1547
+ }
1548
+
1549
+ // create havoc_statements
1527
1550
for (goto_programt::instructiont instruction :
1528
1551
target->havoc_code (location).instructions )
1529
1552
{
1530
1553
havoc_statements.add (std::move (instruction));
1531
1554
}
1555
+
1556
+ if (to_address_of_expr (target_ptr).object ().id () == ID_dereference)
1557
+ {
1558
+ // add the z label instruction
1559
+ havoc_statements.destructive_append (tmp_z);
1560
+ }
1532
1561
}
1533
1562
return havoc_statements;
1534
1563
}
@@ -1577,8 +1606,28 @@ exprt assigns_clauset::compatible_expression(
1577
1606
{
1578
1607
if (first_iter)
1579
1608
{
1580
- current_target_compatible =
1581
- target->compatible_expression (*called_target);
1609
+ // TODO: Optimize the validation below and remove code duplication
1610
+ // See GitHub issue #6105 for further details
1611
+
1612
+ // Validating the called target through __CPROVER_w_ok() is
1613
+ // only useful when the called target is a dereference
1614
+ const auto &called_target_ptr = called_target->get_direct_pointer ();
1615
+ if (
1616
+ to_address_of_expr (called_target_ptr).object ().id () == ID_dereference)
1617
+ {
1618
+ // or_exprt is short-circuited, therefore
1619
+ // target->compatible_expression(*called_target) would not be
1620
+ // checked on invalid called_targets.
1621
+ current_target_compatible = or_exprt (
1622
+ not_exprt (
1623
+ w_ok_exprt (called_target_ptr, from_integer (0 , integer_typet ()))),
1624
+ target->compatible_expression (*called_target));
1625
+ }
1626
+ else
1627
+ {
1628
+ current_target_compatible =
1629
+ target->compatible_expression (*called_target);
1630
+ }
1582
1631
first_iter = false ;
1583
1632
}
1584
1633
else
0 commit comments