Skip to content

Commit 67f5d09

Browse files
Merge pull request #6804 from thomasspriggs/tas/object_size_exprt
Add class for object size expressions
2 parents 598c3da + a2fc2ba commit 67f5d09

12 files changed

+146
-45
lines changed

src/ansi-c/c_typecheck_expr.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2363,8 +2363,7 @@ exprt c_typecheck_baset::do_special_functions(
23632363

23642364
typecheck_function_call_arguments(expr);
23652365

2366-
unary_exprt object_size_expr(
2367-
ID_object_size, expr.arguments()[0], size_type());
2366+
object_size_exprt object_size_expr(expr.arguments()[0], size_type());
23682367
object_size_expr.add_source_location() = source_location;
23692368

23702369
return std::move(object_size_expr);

src/ansi-c/goto_check_c.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1476,7 +1476,7 @@ bool goto_check_ct::requires_pointer_primitive_check(const exprt &expr)
14761476
// pointer_object and pointer_offset just extract a subset of bits from the
14771477
// pointer. If that pointer was unconstrained (non-deterministic), the result
14781478
// will equally be non-deterministic.
1479-
return expr.id() == ID_object_size || expr.id() == ID_r_ok ||
1479+
return can_cast_expr<object_size_exprt>(expr) || expr.id() == ID_r_ok ||
14801480
expr.id() == ID_w_ok || expr.id() == ID_rw_ok ||
14811481
expr.id() == ID_is_dynamic_object;
14821482
}

src/solvers/flattening/bv_pointers.cpp

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -700,14 +700,15 @@ bvt bv_pointerst::convert_bitvector(const exprt &expr)
700700
return bv_utils.sign_extension(offset_bv, width);
701701
}
702702
else if(
703-
expr.id() == ID_object_size &&
704-
to_unary_expr(expr).op().type().id() == ID_pointer)
703+
const auto object_size = expr_try_dynamic_cast<object_size_exprt>(expr))
705704
{
706705
// we postpone until we know the objects
707-
std::size_t width=boolbv_width(expr.type());
706+
std::size_t width = boolbv_width(object_size->type());
708707

709708
postponed_list.emplace_back(
710-
prop.new_variables(width), convert_bv(to_unary_expr(expr).op()), expr);
709+
prop.new_variables(width),
710+
convert_bv(object_size->pointer()),
711+
*object_size);
711712

712713
return postponed_list.back().bv;
713714
}
@@ -935,10 +936,11 @@ void bv_pointerst::do_postponed(
935936
prop.l_set_to_true(prop.limplies(l1, l2));
936937
}
937938
}
938-
else if(postponed.expr.id()==ID_object_size)
939+
else if(
940+
const auto postponed_object_size =
941+
expr_try_dynamic_cast<object_size_exprt>(postponed.expr))
939942
{
940-
const auto &type =
941-
to_pointer_type(to_unary_expr(postponed.expr).op().type());
943+
const auto &type = to_pointer_type(postponed_object_size->pointer().type());
942944
const auto &objects = pointer_logic.objects;
943945
std::size_t number=0;
944946

@@ -955,7 +957,7 @@ void bv_pointerst::do_postponed(
955957
continue;
956958

957959
const exprt object_size = typecast_exprt::conditional_cast(
958-
size_expr.value(), postponed.expr.type());
960+
size_expr.value(), postponed_object_size->type());
959961

960962
// only compare object part
961963
pointer_typet pt = pointer_type(expr.type());

src/solvers/smt2/smt2_conv.cpp

Lines changed: 14 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ Author: Daniel Kroening, [email protected]
2525
#include <util/invariant.h>
2626
#include <util/mathematical_expr.h>
2727
#include <util/namespace.h>
28-
#include <util/pointer_expr.h>
2928
#include <util/pointer_offset_size.h>
3029
#include <util/pointer_predicates.h>
3130
#include <util/prefix.h>
@@ -233,10 +232,9 @@ void smt2_convt::write_footer()
233232

234233
void smt2_convt::define_object_size(
235234
const irep_idt &id,
236-
const exprt &expr)
235+
const object_size_exprt &expr)
237236
{
238-
PRECONDITION(expr.id() == ID_object_size);
239-
const exprt &ptr = to_unary_expr(expr).op();
237+
const exprt &ptr = expr.pointer();
240238
std::size_t size_width = boolbv_width(expr.type());
241239
std::size_t pointer_width = boolbv_width(ptr.type());
242240
std::size_t number = 0;
@@ -2018,9 +2016,10 @@ void smt2_convt::convert_expr(const exprt &expr)
20182016

20192017
out << ")"; // mk-... or concat
20202018
}
2021-
else if(expr.id()==ID_object_size)
2019+
else if(
2020+
const auto object_size = expr_try_dynamic_cast<object_size_exprt>(expr))
20222021
{
2023-
out << "|" << object_sizes[expr] << "|";
2022+
out << "|" << object_sizes[*object_size] << "|";
20242023
}
20252024
else if(expr.id()==ID_let)
20262025
{
@@ -4848,22 +4847,18 @@ void smt2_convt::find_symbols(const exprt &expr)
48484847
defined_expressions[expr]=id;
48494848
}
48504849
}
4851-
else if(expr.id() == ID_object_size)
4850+
else if(
4851+
const auto object_size = expr_try_dynamic_cast<object_size_exprt>(expr))
48524852
{
4853-
const exprt &op = to_unary_expr(expr).op();
4854-
4855-
if(op.type().id()==ID_pointer)
4853+
if(object_sizes.find(*object_size) == object_sizes.end())
48564854
{
4857-
if(object_sizes.find(expr)==object_sizes.end())
4858-
{
4859-
const irep_idt id =
4860-
"object_size." + std::to_string(object_sizes.size());
4861-
out << "(declare-fun |" << id << "| () ";
4862-
convert_type(expr.type());
4863-
out << ")" << "\n";
4855+
const irep_idt id = "object_size." + std::to_string(object_sizes.size());
4856+
out << "(declare-fun |" << id << "| () ";
4857+
convert_type(object_size->type());
4858+
out << ")"
4859+
<< "\n";
48644860

4865-
object_sizes[expr]=id;
4866-
}
4861+
object_sizes[*object_size] = id;
48674862
}
48684863
}
48694864
// clang-format off

src/solvers/smt2/smt2_conv.h

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,14 @@ Author: Daniel Kroening, [email protected]
1010
#ifndef CPROVER_SOLVERS_SMT2_SMT2_CONV_H
1111
#define CPROVER_SOLVERS_SMT2_SMT2_CONV_H
1212

13+
#include <util/pointer_expr.h>
14+
#include <util/std_expr.h>
15+
#include <util/threeval.h>
16+
1317
#include <map>
1418
#include <set>
1519
#include <sstream>
1620

17-
#include <util/std_expr.h>
18-
#include <util/threeval.h>
19-
2021
#if !HASH_CODE
2122
# include <util/irep_hash_container.h>
2223
#endif
@@ -216,7 +217,7 @@ class smt2_convt : public stack_decision_proceduret
216217
void convert_address_of_rec(
217218
const exprt &expr, const pointer_typet &result_type);
218219

219-
void define_object_size(const irep_idt &id, const exprt &expr);
220+
void define_object_size(const irep_idt &id, const object_size_exprt &expr);
220221

221222
// keeps track of all non-Boolean symbols and their value
222223
struct identifiert
@@ -256,7 +257,7 @@ class smt2_convt : public stack_decision_proceduret
256257
/// smt2 formula.
257258
std::unordered_map<irep_idt, bool> set_values;
258259

259-
defined_expressionst object_sizes;
260+
std::map<object_size_exprt, irep_idt> object_sizes;
260261

261262
typedef std::set<std::string> smt2_identifierst;
262263
smt2_identifierst smt2_identifiers;

src/solvers/smt2_incremental/convert_expr_to_smt.cpp

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1192,6 +1192,15 @@ static smt_termt convert_expr_to_smt(
11921192
"Generation of SMT formula for vector expression: " + vector.pretty());
11931193
}
11941194

1195+
static smt_termt convert_expr_to_smt(
1196+
const object_size_exprt &object_size,
1197+
const sub_expression_mapt &converted)
1198+
{
1199+
UNIMPLEMENTED_FEATURE(
1200+
"Generation of SMT formula for object_size expression: " +
1201+
object_size.pretty());
1202+
}
1203+
11951204
static smt_termt
11961205
convert_expr_to_smt(const let_exprt &let, const sub_expression_mapt &converted)
11971206
{
@@ -1530,12 +1539,10 @@ static smt_termt dispatch_expr_to_smt_conversion(
15301539
{
15311540
return convert_expr_to_smt(*vector, converted);
15321541
}
1533-
#if 0
1534-
else if(expr.id()==ID_object_size)
1542+
if(const auto object_size = expr_try_dynamic_cast<object_size_exprt>(expr))
15351543
{
1536-
out << "|" << object_sizes[expr] << "|";
1544+
return convert_expr_to_smt(*object_size, converted);
15371545
}
1538-
#endif
15391546
if(const auto let = expr_try_dynamic_cast<let_exprt>(expr))
15401547
{
15411548
return convert_expr_to_smt(*let, converted);

src/util/pointer_expr.h

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -989,4 +989,39 @@ inline pointer_object_exprt &to_pointer_object_expr(exprt &expr)
989989
return ret;
990990
}
991991

992+
/// Expression for finding the size (in bytes) of the object a pointer points
993+
/// to.
994+
class object_size_exprt : public unary_exprt
995+
{
996+
public:
997+
explicit object_size_exprt(exprt pointer, typet type)
998+
: unary_exprt(ID_object_size, std::move(pointer), std::move(type))
999+
{
1000+
}
1001+
1002+
exprt &pointer()
1003+
{
1004+
return op();
1005+
}
1006+
1007+
const exprt &pointer() const
1008+
{
1009+
return op();
1010+
}
1011+
};
1012+
1013+
template <>
1014+
inline bool can_cast_expr<object_size_exprt>(const exprt &base)
1015+
{
1016+
return base.id() == ID_object_size;
1017+
}
1018+
1019+
inline void validate_expr(const object_size_exprt &value)
1020+
{
1021+
validate_operands(value, 1, "Object size expression must have one operand.");
1022+
DATA_INVARIANT(
1023+
can_cast_type<pointer_typet>(value.pointer().type()),
1024+
"Object size expression must have pointer typed operand.");
1025+
}
1026+
9921027
#endif // CPROVER_UTIL_POINTER_EXPR_H

src/util/pointer_predicates.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ exprt same_object(const exprt &p1, const exprt &p2)
3232

3333
exprt object_size(const exprt &pointer)
3434
{
35-
return unary_exprt(ID_object_size, pointer, size_type());
35+
return object_size_exprt(pointer, size_type());
3636
}
3737

3838
exprt pointer_offset(const exprt &pointer)

src/util/simplify_expr.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2398,9 +2398,10 @@ simplify_exprt::resultt<> simplify_exprt::simplify_node(exprt node)
23982398
{
23992399
r = simplify_is_invalid_pointer(to_unary_expr(expr));
24002400
}
2401-
else if(expr.id()==ID_object_size)
2401+
else if(
2402+
const auto object_size = expr_try_dynamic_cast<object_size_exprt>(expr))
24022403
{
2403-
r = simplify_object_size(to_unary_expr(expr));
2404+
r = simplify_object_size(*object_size);
24042405
}
24052406
else if(expr.id()==ID_good_pointer)
24062407
{

src/util/simplify_expr_class.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ class multi_ary_exprt;
5858
class mult_exprt;
5959
class namespacet;
6060
class not_exprt;
61+
class object_size_exprt;
6162
class plus_exprt;
6263
class pointer_object_exprt;
6364
class pointer_offset_exprt;
@@ -173,7 +174,7 @@ class simplify_exprt
173174
NODISCARD resultt<> simplify_byte_update(const byte_update_exprt &);
174175
NODISCARD resultt<> simplify_byte_extract(const byte_extract_exprt &);
175176
NODISCARD resultt<> simplify_pointer_object(const pointer_object_exprt &);
176-
NODISCARD resultt<> simplify_object_size(const unary_exprt &);
177+
NODISCARD resultt<> simplify_object_size(const object_size_exprt &);
177178
NODISCARD resultt<> simplify_is_dynamic_object(const unary_exprt &);
178179
NODISCARD resultt<> simplify_is_invalid_pointer(const unary_exprt &);
179180
NODISCARD resultt<> simplify_good_pointer(const unary_exprt &);

src/util/simplify_expr_pointer.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -640,11 +640,11 @@ simplify_exprt::simplify_is_invalid_pointer(const unary_exprt &expr)
640640
}
641641

642642
simplify_exprt::resultt<>
643-
simplify_exprt::simplify_object_size(const unary_exprt &expr)
643+
simplify_exprt::simplify_object_size(const object_size_exprt &expr)
644644
{
645645
auto new_expr = expr;
646646
bool no_change = true;
647-
exprt &op = new_expr.op();
647+
exprt &op = new_expr.pointer();
648648
auto op_result = simplify_object(op);
649649

650650
if(op_result.has_changed())

unit/util/pointer_expr.cpp

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,3 +122,63 @@ TEST_CASE("pointer_object_exprt", "[core][util]")
122122
}
123123
}
124124
}
125+
126+
TEST_CASE("object_size_exprt", "[core][util]")
127+
{
128+
const exprt pointer = symbol_exprt{"foo", pointer_type(void_type())};
129+
const object_size_exprt object_size{pointer, size_type()};
130+
SECTION("Is equivalent to free function.")
131+
{
132+
CHECK(::object_size(pointer) == object_size);
133+
}
134+
SECTION("Result type")
135+
{
136+
CHECK(object_size.type() == size_type());
137+
}
138+
SECTION("Pointer operand accessor")
139+
{
140+
CHECK(object_size.pointer() == pointer);
141+
}
142+
SECTION("Downcasting")
143+
{
144+
const exprt &upcast = object_size;
145+
CHECK(expr_try_dynamic_cast<object_size_exprt>(upcast));
146+
CHECK_FALSE(expr_try_dynamic_cast<pointer_object_exprt>(upcast));
147+
SECTION("Validation")
148+
{
149+
SECTION("Invalid operand")
150+
{
151+
unary_exprt invalid_type = object_size;
152+
invalid_type.op().type() = bool_typet{};
153+
const cbmc_invariants_should_throwt invariants_throw;
154+
REQUIRE_THROWS_MATCHES(
155+
expr_try_dynamic_cast<object_size_exprt>(invalid_type),
156+
invariant_failedt,
157+
invariant_failure_containing(
158+
"Object size expression must have pointer typed operand."));
159+
}
160+
SECTION("Missing operand")
161+
{
162+
exprt missing_operand = object_size;
163+
missing_operand.operands().clear();
164+
const cbmc_invariants_should_throwt invariants_throw;
165+
REQUIRE_THROWS_MATCHES(
166+
expr_try_dynamic_cast<object_size_exprt>(missing_operand),
167+
invariant_failedt,
168+
invariant_failure_containing(
169+
"Object size expression must have one operand"));
170+
}
171+
SECTION("Too many operands")
172+
{
173+
exprt two_operands = object_size;
174+
two_operands.operands().push_back(pointer);
175+
const cbmc_invariants_should_throwt invariants_throw;
176+
REQUIRE_THROWS_MATCHES(
177+
expr_try_dynamic_cast<object_size_exprt>(two_operands),
178+
invariant_failedt,
179+
invariant_failure_containing(
180+
"Object size expression must have one operand"));
181+
}
182+
}
183+
}
184+
}

0 commit comments

Comments
 (0)