Skip to content

Commit b7559c6

Browse files
committed
Add class for object size expression
So that these kinds of expressions can be handled in a more type safe fashion.
1 parent 598c3da commit b7559c6

File tree

2 files changed

+95
-0
lines changed

2 files changed

+95
-0
lines changed

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

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)