Skip to content

Value-set supported simplifier: add object_size, is_invalid_pointer #8704

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
115 changes: 112 additions & 3 deletions src/goto-symex/simplify_expr_with_value_set.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Author: Michael Tautschnig

#include <util/expr_util.h>
#include <util/pointer_expr.h>
#include <util/pointer_offset_size.h>
#include <util/simplify_expr.h>
#include <util/ssa_expr.h>

Expand Down Expand Up @@ -188,11 +189,23 @@ simplify_expr_with_value_sett::simplify_inequality_pointer_object(
objects.clear();
break;
}

objects.insert(
to_object_descriptor_expr(value_set_element).root_object());
else if(value_set_element.id() == ID_null_object)
{
// make sure all NULL objects being considered look the same
objects.insert(exprt{ID_null_object, empty_typet{}});
}
else
{
objects.insert(
to_object_descriptor_expr(value_set_element).root_object());
}
}
}
else if(
pointer.is_constant() && to_constant_expr(pointer).is_null_pointer())
{
objects.insert(exprt{ID_null_object, empty_typet{}});
}
return objects;
};

Expand Down Expand Up @@ -281,3 +294,99 @@ simplify_expr_with_value_sett::simplify_pointer_offset(
return changed(
simplify_rec(typecast_exprt::conditional_cast(*offset, expr.type())));
}

simplify_exprt::resultt<> simplify_expr_with_value_sett::simplify_object_size(
const object_size_exprt &expr)
{
const exprt &ptr = expr.pointer();

if(ptr.type().id() != ID_pointer)
return unchanged(expr);

const ssa_exprt *ssa_symbol_expr = expr_try_dynamic_cast<ssa_exprt>(ptr);

if(!ssa_symbol_expr)
return simplify_exprt::simplify_object_size(expr);

ssa_exprt l1_expr{*ssa_symbol_expr};
l1_expr.remove_level_2();
const std::vector<exprt> value_set_elements =
value_set.get_value_set(l1_expr, ns);

std::optional<exprt> object_size;

for(const auto &value_set_element : value_set_elements)
{
if(
value_set_element.id() == ID_unknown ||
value_set_element.id() == ID_invalid ||
is_failed_symbol(
to_object_descriptor_expr(value_set_element).root_object()) ||
to_object_descriptor_expr(value_set_element).offset().id() == ID_unknown)
{
object_size.reset();
break;
}

auto this_object_size_opt = size_of_expr(
to_object_descriptor_expr(value_set_element).root_object().type(), ns);
if(
!this_object_size_opt.has_value() ||
(object_size.has_value() && *this_object_size_opt != *object_size))
{
object_size.reset();
break;
}
else if(!object_size.has_value())
{
object_size = this_object_size_opt;
}
}

if(!object_size.has_value())
return simplify_exprt::simplify_object_size(expr);

return changed(
simplify_rec(typecast_exprt::conditional_cast(*object_size, expr.type())));
}

simplify_exprt::resultt<>
simplify_expr_with_value_sett::simplify_is_invalid_pointer(
const unary_exprt &expr)
{
const exprt &ptr = expr.op();

if(ptr.type().id() != ID_pointer)
return unchanged(expr);

const ssa_exprt *ssa_symbol_expr = expr_try_dynamic_cast<ssa_exprt>(ptr);

if(!ssa_symbol_expr)
return simplify_exprt::simplify_is_invalid_pointer(expr);

ssa_exprt l1_expr{*ssa_symbol_expr};
l1_expr.remove_level_2();
const std::vector<exprt> value_set_elements =
value_set.get_value_set(l1_expr, ns);

bool all_valid = !value_set_elements.empty();

for(const auto &value_set_element : value_set_elements)
{
if(
value_set_element.id() == ID_unknown ||
value_set_element.id() == ID_invalid ||
is_failed_symbol(
to_object_descriptor_expr(value_set_element).root_object()) ||
to_object_descriptor_expr(value_set_element).offset().id() == ID_unknown)
{
all_valid = false;
break;
}
}

if(all_valid)
return changed(static_cast<exprt>(false_exprt{}));
else
return simplify_exprt::simplify_is_invalid_pointer(expr);
}
4 changes: 4 additions & 0 deletions src/goto-symex/simplify_expr_with_value_set.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ class simplify_expr_with_value_sett : public simplify_exprt
[[nodiscard]] resultt<>
simplify_inequality_pointer_object(const binary_relation_exprt &) override;
[[nodiscard]] resultt<>
simplify_is_invalid_pointer(const unary_exprt &) override;
[[nodiscard]] resultt<>
simplify_object_size(const object_size_exprt &) override;
[[nodiscard]] resultt<>
simplify_pointer_offset(const pointer_offset_exprt &) override;

protected:
Expand Down
6 changes: 4 additions & 2 deletions src/util/simplify_expr_class.h
Original file line number Diff line number Diff line change
Expand Up @@ -193,9 +193,11 @@ class simplify_exprt
[[nodiscard]] resultt<> simplify_pointer_object(const pointer_object_exprt &);
[[nodiscard]] resultt<>
simplify_unary_pointer_predicate_preorder(const unary_exprt &);
[[nodiscard]] resultt<> simplify_object_size(const object_size_exprt &);
[[nodiscard]] virtual resultt<>
simplify_object_size(const object_size_exprt &);
[[nodiscard]] resultt<> simplify_is_dynamic_object(const unary_exprt &);
[[nodiscard]] resultt<> simplify_is_invalid_pointer(const unary_exprt &);
[[nodiscard]] virtual resultt<>
simplify_is_invalid_pointer(const unary_exprt &);
[[nodiscard]] resultt<> simplify_object(const exprt &);
[[nodiscard]] resultt<> simplify_unary_minus(const unary_minus_exprt &);
[[nodiscard]] resultt<> simplify_unary_plus(const unary_plus_exprt &);
Expand Down
Loading