Skip to content

VSD: Simplifying abstract_objectt::write, collapsing inheritance hierarchy #5755

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 49 commits into from
Jan 28, 2021

Conversation

jezhiggins
Copy link
Contributor

@jezhiggins jezhiggins commented Jan 16, 2021

This PR simplifies the write member function implementation in abstract_objectt subclasses. It collapses the inheritance hierarchy for classes modelling aggregate values (arrays, structs, unions), eliminating duplication.

Several classes were named to better reflect their purpose - eg union_abstract_objectt became two_value_union_abstract_objectt, and some new classes introduced to in place of a previously existing base class, eg two_value_array_abstract_objectt in place of the eliminated array_abtract_objectt.

This allowed further work to combine interval_array_abstract_objectt and constant_array_abstract_objectt together. The combined implementation has been renamed full_array_abstract_objectt, and the implementation refactored for reading comprehension.

This PR is behaviour preserving. No need functionality is introduced.

@jezhiggins jezhiggins force-pushed the vsd-merge-and-eval branch 6 times, most recently from ec33346 to b27896b Compare January 17, 2021 17:30
@codecov
Copy link

codecov bot commented Jan 17, 2021

Codecov Report

Merging #5755 (d9f7b72) into develop (f2fafac) will increase coverage by 0.02%.
The diff coverage is 88.20%.

Impacted file tree graph

@@             Coverage Diff             @@
##           develop    #5755      +/-   ##
===========================================
+ Coverage    69.64%   69.67%   +0.02%     
===========================================
  Files         1248     1242       -6     
  Lines       100911   100875      -36     
===========================================
- Hits         70284    70282       -2     
+ Misses       30627    30593      -34     
Flag Coverage Δ
cproversmt2 43.36% <ø> (ø)
regression 66.63% <83.77%> (+<0.01%) ⬆️
unit 32.30% <57.52%> (+0.11%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Impacted Files Coverage Δ
...alyses/variable-sensitivity/abstract_environment.h 100.00% <ø> (ø)
...rc/analyses/variable-sensitivity/abstract_object.h 88.46% <ø> (-2.97%) ⬇️
...s/variable-sensitivity/pointer_abstract_object.cpp 85.71% <ø> (ø)
...-sensitivity/value_set_pointer_abstract_object.cpp 60.00% <ø> (+26.66%) ⬆️
...le-sensitivity/value_set_pointer_abstract_object.h 0.00% <ø> (ø)
...variable-sensitivity/variable_sensitivity_domain.h 100.00% <ø> (ø)
...-sensitivity/variable_sensitivity_object_factory.h 100.00% <ø> (ø)
...es/variable-sensitivity/write_location_context.cpp 96.82% <ø> (ø)
.../analyses/variable-sensitivity/write_stack_entry.h 100.00% <ø> (ø)
...riable-sensitivity/full_struct_abstract_object.cpp 81.90% <63.63%> (+2.46%) ⬆️
... and 30 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update f2fafac...d9f7b72. Read the comment docs.

@jezhiggins jezhiggins force-pushed the vsd-merge-and-eval branch 2 times, most recently from 3c4977a to 5a328d4 Compare January 17, 2021 20:28
@jezhiggins jezhiggins marked this pull request as ready for review January 17, 2021 22:04
Copy link
Collaborator

@martin-cs martin-cs left a comment

Choose a reason for hiding this comment

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

I don't see any immediate show stoppers but this is quite a substantial refactor and it would be good to work through the code-base with you before we merge this PR.

else if(
simplified_id == ID_array || simplified_id == ID_struct ||
simplified_id == ID_constant)
simplified_id == ID_constant || simplified_id == ID_address_of)
Copy link
Collaborator

Choose a reason for hiding this comment

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

It is true that it is handled the same but it is for quite different reasons. This is not necessarily a problem, but it is something to be aware of.


class member_exprt;

template<class aggregate_typet, class aggregate_traitst>
Copy link
Collaborator

Choose a reason for hiding this comment

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

This is probably a bit more template-y than we normally write but under the circumstances I can see this reduces an amount of duplication.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's compile type polymorphism rather than run-time. We don't need, actually don't want, run-time polymorphism here.

merging_write);
}
else if(
if(
!index_interval.is_top() && !index_interval.is_bottom() &&
index_interval.get_lower().id() != ID_min &&
index_interval.get_upper().id() != ID_max)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Although not touched by this PR, this case really should result in the interval being top.

}
};

#endif
Copy link
Collaborator

Choose a reason for hiding this comment

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

New line?


#include <analyses/variable-sensitivity/abstract_object.h>

class abstract_value_tag { };
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'm not sure I follow why this is needed...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'd initially expected abstract_value_objectt to be a template in a similar way to abstract_aggregate_objectt. Didn't turn out that way, although may yet with the next bit of work. Happy to remove this now if you'd prefer.

if (is_top() || is_bottom() || interval.is_top() || interval.is_bottom())
return std::make_shared<empty_index_ranget>();
if (interval.get_lower().id() == ID_min || interval.get_upper().id() == ID_max)
return std::make_shared<empty_index_ranget>();
Copy link
Collaborator

Choose a reason for hiding this comment

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

I get that if the interval is bottom you should get an empty range but I'm not sure I get why this is the case for top or if the interval is open at one end.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It doesn't make sense to me either, but this is the existing behaviour.

@@ -40,14 +40,18 @@ SCENARIO(
}
}

GIVEN("a top constant's range is empty")
GIVEN("a top constant's range is has a single nil expression")
Copy link
Collaborator

Choose a reason for hiding this comment

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

If it tis top then it should be everything so this is definitely an improvement but I'm not quite sure what the nil is supposed to describe.

Copy link
Contributor Author

@jezhiggins jezhiggins Jan 19, 2021

Choose a reason for hiding this comment

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

The index_range is only used to during array access, and this supports the existing behaviour. Returning a nil expression here takes us down to https://github.com/jezhiggins/cbmc/blob/b618d2e3703434aa0cfb4d1c991c867b1dea9955/src/analyses/variable-sensitivity/full_array_abstract_object.cpp#L298
It is a special case, but it's isolated here rather than having to be explicitly handed in potentially several places elsewhere. As we look to expand other value representations, the more we can keep within those representations, the better.

@@ -443,18 +443,6 @@ class abstract_objectt : public std::enable_shared_from_this<abstract_objectt>
/// abstraction anyway
bool should_use_base_meet(const abstract_object_pointert &other) const;

template <class keyt>
Copy link
Collaborator

Choose a reason for hiding this comment

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

Good tidy up.

@@ -272,113 +270,137 @@ abstract_object_pointert full_array_abstract_objectt::write_element(
environment, ns, stack, expr, value, merging_write);
}

if(!stack.empty())
Copy link
Collaborator

Choose a reason for hiding this comment

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

It's not entirely clear to me why this is needed. Can't you just delegate the write to the relevant abstract_object and then update the relevant entry with whatever it returns?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No, because once we get to the end of the stack we need to worry about whether it's a merging write or not. Higher up the stack, we don't need to do that.

We have a similar decision point in full_struct_abstract_objectt, and I assume we'll have one in our union representation when we fill that out. When we get there, it's entirely possible we'll be able to collapse the implementations.

@@ -376,13 +376,10 @@ abstract_object_pointert full_array_abstract_objectt::write_leaf_element(
}
else
{
auto const old_value = result->map.find(index_value);
auto old_value = result->map.find(index_value);
if(old_value.has_value())
Copy link
Collaborator

Choose a reason for hiding this comment

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

It may not change the value that is stored but breaking sharing is a serious concern. Please check that the sharing map does actually handle that case correctly.

@martin-cs
Copy link
Collaborator

I've had a discussion with @jezhiggins and I am in favour of merging this because:

  1. It is at least an intermediate step towards sorting this code out.
  2. It is code that I requested we merge "to be improved in tree".
  3. It makes things simpler.
  4. It is a pure refactoring. Jez has very intentionally preserved functionality, even when questionable.

@jezhiggins jezhiggins force-pushed the vsd-merge-and-eval branch 3 times, most recently from d134e80 to 6c5f28a Compare January 22, 2021 18:35
@martin-cs
Copy link
Collaborator

@tautschnig @peterschrammel This is part of the refactor and tidy up of VSD. I don't expect you to look at that part of the commit, i think it is a net improvement and there is more to do. Please could you have a look at the changes in other parts of the tree, notably `util/' which are blocking the merge.

Copy link
Collaborator

@tautschnig tautschnig left a comment

Choose a reason for hiding this comment

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

Some administrative comments only, I have browsed (but not properly reviewed) the code in analyses/ and focussed on the single change in src/util/ only.

#include <util/pointer_expr.h>
#include <language_util.h>
Copy link
Collaborator

Choose a reason for hiding this comment

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

Seems surprising?

@@ -14,7 +14,7 @@
#include <analyses/variable-sensitivity/two_value_struct_abstract_object.h>
#include <analyses/variable-sensitivity/variable_sensitivity_object_factory.h>
#include <util/pointer_expr.h>
#include <language_util.h>
#include <langapi/language_util.h>
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why is this file being included?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good question - looking at now, I probably included for some debug/dev code which didn't need to be committed. I'll tidy this up.

@@ -0,0 +1,53 @@
#include <analyses/variable-sensitivity/abstract_environment.h>
Copy link
Collaborator

Choose a reason for hiding this comment

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

Quoting CODING_GUIDELINES.md: "Each source and header file must start with a comment block stating the author."

@@ -0,0 +1,47 @@
#include <analyses/variable-sensitivity/abstract_value_object.h>
Copy link
Collaborator

Choose a reason for hiding this comment

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

See earlier comment: please make sure all files include a header stating the author.

@@ -14,6 +14,12 @@

#include "full_array_abstract_object.h"

bool eval_index(
Copy link
Collaborator

Choose a reason for hiding this comment

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

Should likely be static as only required within this file.

Comment on lines +458 to +467
sorted_viewt get_sorted_view() const
{
sorted_viewt result;
get_view(result);
return result;
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Would you mind adding documentation? It may be ok to put the three methods in a group, but there should be some sort of documentation.

Comment on lines 261 to 263
static abstract_object_pointert merge(
abstract_object_pointert op1,
abstract_object_pointert op2);
Copy link
Collaborator

Choose a reason for hiding this comment

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

How about changing the interface to make merge return a pair?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I did try it, but it didn't really make the code any clearer. If structured bindings were available, I'd absolutely have gone for it.

Reduced visibility, collapses common implementations, added factory
methods.
Array representation is now independent of value representation.
Renamed constant_array_abstract_object to full_array_abstract_object.
Eliminated interval_array_abstract_object.
Not used in the code, and in any case now redundant as full_array_
works happily with value-sets.
 if(value != abstract_object_pointert{old_value.value()})

I don't see that this test can ever fail, and even if it does the
operation we're guarding against is benign
@martin-cs martin-cs merged commit a6a0729 into diffblue:develop Jan 28, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants