Skip to content

goto_symex: rename type symbols only when needed [blocks: #3652] #3633

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

Merged
merged 5 commits into from
Jan 24, 2019
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ Test.class
--function Test.main --no-simplify --unwind 10 --show-vcc
^EXIT=0$
^SIGNAL=0$
"java::Impl1" = cast\(\{ \{ "java::Impl1" \}, 0 \}, struct \{ struct \{ string @class_identifier \} @java.lang.Object \}\)\[email protected]\.@class_identifier
"java::Impl1" = cast\(\{ \{ "java::Impl1" \}, 0 \}, struct (\{ struct \{ string @class_identifier \} @java.lang.Object \}|java::Intf)\)\[email protected]\.@class_identifier
--
^warning: ignoring
--
Expand Down
2 changes: 1 addition & 1 deletion jbmc/regression/jbmc/trace_class_identifier/test.desc
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
CORE
TestGenTest.class
--function TestGenTest.f --trace --json-ui
"data": "java::TestGenTest",$
"data": "(java::TestGenTest|TestGenTest@class_model)",$
^EXIT=10$
^SIGNAL=0$
--
Expand Down
51 changes: 51 additions & 0 deletions src/goto-symex/goto_symex_state.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -618,12 +618,63 @@ void goto_symex_statet::rename_address(
}
}

static bool requires_renaming(const typet &type, const namespacet &ns)
{
if(type.id() == ID_array)
{
const auto &array_type = to_array_type(type);
return requires_renaming(array_type.subtype(), ns) ||
!array_type.size().is_constant();
}
else if(
type.id() == ID_struct || type.id() == ID_union || type.id() == ID_class)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think type.id() == ID_class should ever evaluate to true. A class is represented as ID_struct with ID_C_class set to true. If I'm wrong in saying this then we've got a lot more work to do elsewhere.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, these should be cleaned out.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

{
const struct_union_typet &s_u_type = to_struct_union_type(type);
const struct_union_typet::componentst &components = s_u_type.components();

for(auto &component : components)
{
// be careful, or it might get cyclic
if(component.type().id() != ID_pointer)
return requires_renaming(component.type(), ns);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This only looks at the first non-pointer component of the struct, which is strange, but I cannot say whether this is correct because the function is not documented, so please document.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oooh, I missed that, @kroening pretty sure this is a real bug

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(suggests a new test -- AFAIK GCC allows such variable-size structs?)

Copy link
Collaborator

@tautschnig tautschnig Jan 24, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I've found a way to construct a failing test, I'll post a follow-up PR to include a test, a fix, and the suggested documentation.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The failure I thought I had found was one caused by integer overflow - I haven't actually managed to produce a proper failure. See #3918 for my attempt and the cleanup.

}

return false;
}
else if(type.id() == ID_pointer)
{
return requires_renaming(to_pointer_type(type).subtype(), ns);
}
else if(type.id() == ID_symbol_type)
{
const symbolt &symbol = ns.lookup(to_symbol_type(type));
return requires_renaming(symbol.type, ns);
}
else if(type.id() == ID_union_tag)
{
const symbolt &symbol = ns.lookup(to_union_tag_type(type));
return requires_renaming(symbol.type, ns);
}
else if(type.id() == ID_struct_tag)
{
const symbolt &symbol = ns.lookup(to_struct_tag_type(type));
return requires_renaming(symbol.type, ns);
}

return false;
}

void goto_symex_statet::rename(
typet &type,
const irep_idt &l1_identifier,
const namespacet &ns,
levelt level)
{
// check whether there are symbol expressions in the type; if not, there
// is no need to expand the struct/union tags in the type
if(!requires_renaming(type, ns))
return; // no action

// rename all the symbols with their last known value
// to the given level

Expand Down
35 changes: 21 additions & 14 deletions src/solvers/strings/string_refinement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,7 @@ static void add_equations_for_symbol_resolution(
continue;
}

if(lhs.type() != rhs.type())
if(!base_type_eq(lhs.type(), rhs.type(), ns))
{
stream << log_message << "non equal types lhs: " << format(lhs)
<< "\n####################### rhs: " << format(rhs) << eom;
Expand All @@ -348,9 +348,9 @@ static void add_equations_for_symbol_resolution(
else if(
lhs.type().id() != ID_pointer && has_char_pointer_subtype(lhs.type(), ns))
{
if(rhs.type().id() == ID_struct)
if(rhs.type().id() == ID_struct || rhs.type().id() == ID_struct_tag)
{
const struct_typet &struct_type = to_struct_type(rhs.type());
const struct_typet &struct_type = to_struct_type(ns.follow(rhs.type()));
for(const auto &comp : struct_type.components())
{
if(is_char_pointer_type(comp.type()))
Expand All @@ -374,20 +374,22 @@ static void add_equations_for_symbol_resolution(
/// This is meant to be used on the lhs of an equation with string subtype.
/// \param lhs: expression which is either of string type, or a symbol
/// representing a struct with some string members
/// \param ns: namespace to resolve type tags
/// \return if lhs is a string return this string, if it is a struct return the
/// members of the expression that have string type.
static std::vector<exprt> extract_strings_from_lhs(const exprt &lhs)
static std::vector<exprt>
extract_strings_from_lhs(const exprt &lhs, const namespacet &ns)
{
std::vector<exprt> result;
if(lhs.type() == string_typet())
result.push_back(lhs);
else if(lhs.type().id() == ID_struct)
else if(lhs.type().id() == ID_struct || lhs.type().id() == ID_struct_tag)
{
const struct_typet &struct_type = to_struct_type(lhs.type());
const struct_typet &struct_type = to_struct_type(ns.follow(lhs.type()));
for(const auto &comp : struct_type.components())
{
const std::vector<exprt> strings_in_comp = extract_strings_from_lhs(
member_exprt(lhs, comp.get_name(), comp.type()));
member_exprt(lhs, comp.get_name(), comp.type()), ns);
result.insert(
result.end(), strings_in_comp.begin(), strings_in_comp.end());
}
Expand All @@ -396,10 +398,12 @@ static std::vector<exprt> extract_strings_from_lhs(const exprt &lhs)
}

/// \param expr: an expression
/// \param ns: namespace to resolve type tags
/// \return all subexpressions of type string which are not if_exprt expressions
/// this includes expressions of the form `e.x` if e is a symbol subexpression
/// with a field `x` of type string
static std::vector<exprt> extract_strings(const exprt &expr)
static std::vector<exprt>
extract_strings(const exprt &expr, const namespacet &ns)
{
std::vector<exprt> result;
for(auto it = expr.depth_begin(); it != expr.depth_end();)
Expand All @@ -411,7 +415,7 @@ static std::vector<exprt> extract_strings(const exprt &expr)
}
else if(it->id() == ID_symbol)
{
for(const exprt &e : extract_strings_from_lhs(*it))
for(const exprt &e : extract_strings_from_lhs(*it, ns))
result.push_back(e);
it.next_sibling_or_parent();
}
Expand All @@ -438,9 +442,12 @@ static void add_string_equation_to_symbol_resolution(
}
else if(has_subtype(eq.lhs().type(), ID_string, ns))
{
if(eq.rhs().type().id() == ID_struct)
if(
eq.rhs().type().id() == ID_struct ||
eq.rhs().type().id() == ID_struct_tag)
{
const struct_typet &struct_type = to_struct_type(eq.rhs().type());
const struct_typet &struct_type =
to_struct_type(ns.follow(eq.rhs().type()));
for(const auto &comp : struct_type.components())
{
const member_exprt lhs_data(eq.lhs(), comp.get_name(), comp.type());
Expand Down Expand Up @@ -484,15 +491,15 @@ union_find_replacet string_identifiers_resolution_from_equations(
if(required_equations.insert(i).second)
equations_to_treat.push(i);

std::vector<exprt> rhs_strings = extract_strings(eq.rhs());
std::vector<exprt> rhs_strings = extract_strings(eq.rhs(), ns);
for(const auto &expr : rhs_strings)
equation_map.add(i, expr);
}
else if(
eq.lhs().type().id() != ID_pointer &&
has_subtype(eq.lhs().type(), ID_string, ns))
{
std::vector<exprt> lhs_strings = extract_strings_from_lhs(eq.lhs());
std::vector<exprt> lhs_strings = extract_strings_from_lhs(eq.lhs(), ns);

for(const auto &expr : lhs_strings)
equation_map.add(i, expr);
Expand All @@ -504,7 +511,7 @@ union_find_replacet string_identifiers_resolution_from_equations(
<< format(eq.lhs().type()) << eom;
}

for(const exprt &expr : extract_strings(eq.rhs()))
for(const exprt &expr : extract_strings(eq.rhs(), ns))
equation_map.add(i, expr);
}
}
Expand Down
4 changes: 4 additions & 0 deletions src/util/expr_util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,10 @@ bool has_subtype(
push_if_not_visited(ns.follow(top));
else if(top.id() == ID_c_enum_tag)
push_if_not_visited(ns.follow_tag(to_c_enum_tag_type(top)));
else if(top.id() == ID_struct_tag)
push_if_not_visited(ns.follow_tag(to_struct_tag_type(top)));
else if(top.id() == ID_union_tag)
push_if_not_visited(ns.follow_tag(to_union_tag_type(top)));
else if(top.id() == ID_struct || top.id() == ID_union)
{
for(const auto &comp : to_struct_union_type(top).components())
Expand Down