-
Notifications
You must be signed in to change notification settings - Fork 280
Object factory: remove type from recursion set on leaving scope #1176
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
CORE | ||
test.class | ||
--function test.main | ||
^EXIT=10$ | ||
^SIGNAL=0$ | ||
VERIFICATION FAILED | ||
assertion at file test\.java line 10 .* FAILURE | ||
-- |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
|
||
public class test { | ||
|
||
public Other o1; | ||
public Other o2; | ||
|
||
public void main() { | ||
if(o1 == null || o2 == null) | ||
return; | ||
assert(false); | ||
} | ||
|
||
} | ||
|
||
class Other { | ||
int x; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
CORE | ||
test.class | ||
--function test.main | ||
^EXIT=10$ | ||
^SIGNAL=0$ | ||
VERIFICATION FAILED | ||
assertion at file test.java line 23 function java::test\.toplevel_pointers_not_null.*: FAILURE | ||
assertion at file test.java line 18 function java::test\.next_pointers_not_null.*: SUCCESS | ||
-- |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
|
||
public class test { | ||
|
||
public Other o1; | ||
public Other o2; | ||
|
||
public void main() { | ||
if(o1 != null && o2 != null) { | ||
if(o1.next != null && o2.next != null) { | ||
next_pointers_not_null(); | ||
} | ||
toplevel_pointers_not_null(); | ||
} | ||
} | ||
|
||
public void next_pointers_not_null() { | ||
// Not currently achievable due to recursive types | ||
assert(false); | ||
} | ||
|
||
public void toplevel_pointers_not_null() { | ||
// Should be possible to hit | ||
assert(false); | ||
} | ||
|
||
} | ||
|
||
class Other { | ||
int x; | ||
Other next; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -389,6 +389,54 @@ void java_object_factoryt::gen_pointer_target_init( | |
} | ||
} | ||
|
||
/// Recursion-set entry owner class. If a recursion-set entry is added | ||
/// in a particular scope, ensures that it is erased on leaving | ||
/// that scope. | ||
class recursion_set_entryt | ||
{ | ||
/// Recursion set to modify | ||
std::unordered_set<irep_idt, irep_id_hash> &recursion_set; | ||
/// Entry to erase on destruction, if non-empty | ||
irep_idt erase_entry; | ||
|
||
public: | ||
/// Initialise a recursion-set entry owner operating on a given set. | ||
/// Initially it does not own any set entry. | ||
/// \param _recursion_set: set to operate on. | ||
recursion_set_entryt(std::unordered_set<irep_idt, irep_id_hash> &_recursion_set): | ||
recursion_set(_recursion_set) | ||
{ } | ||
|
||
/// Removes erase_entry (if set) from the controlled set. | ||
~recursion_set_entryt() | ||
{ | ||
if(erase_entry!=irep_idt()) | ||
recursion_set.erase(erase_entry); | ||
} | ||
|
||
recursion_set_entryt(const recursion_set_entryt &)=delete; | ||
recursion_set_entryt &operator=(const recursion_set_entryt &)=delete; | ||
|
||
/// Try to add an entry to the controlled set. If it is added, own that | ||
/// entry and erase it on destruction; otherwise do nothing. | ||
/// \param entry: entry to add | ||
/// \return true if added to the set (and therefore owned by this object) | ||
bool insert_entry(const irep_idt &entry) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I can see why this isn't part of the constructor as you need to tie the destruction to a different scope to when you know the tag. And I really like using our own stack to ensure correctness for the recursion stack. I do wish there was a way to do this in the constructor though. The only way I can think of is replace the early creation with a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I was initially going to use the constructor, but I thought I'd end up in copy-constructor / move-constructor / assignment-operator / swap-op hell trying to get the pesky thing deleted at the right time. This uncopyable thing seemed like an easier simple sentinel. |
||
{ | ||
INVARIANT( | ||
erase_entry==irep_idt(), | ||
"insert_entry should only be called once"); | ||
INVARIANT(entry!=irep_idt(), "entry should be a struct tag"); | ||
bool ret=recursion_set.insert(entry).second; | ||
if(ret) | ||
{ | ||
// We added something, so erase it when this is destroyed: | ||
erase_entry=entry; | ||
} | ||
return ret; | ||
} | ||
}; | ||
|
||
/// Initialises a primitive or object tree rooted at `expr`, of type pointer. It | ||
/// allocates child objects as necessary and nondet-initialising their members, | ||
/// or if MUST_UPDATE_IN_PLACE is set, re-initialising already-allocated | ||
|
@@ -431,14 +479,18 @@ void java_object_factoryt::gen_nondet_pointer_init( | |
return; | ||
} | ||
|
||
// This deletes the recursion set entry on leaving this function scope, | ||
// if one is set below. | ||
recursion_set_entryt recursion_set_entry(recursion_set); | ||
|
||
const typet &subtype=ns.follow(pointer_type.subtype()); | ||
if(subtype.id()==ID_struct) | ||
{ | ||
const struct_typet &struct_type=to_struct_type(subtype); | ||
const irep_idt &struct_tag=struct_type.get_tag(); | ||
|
||
// If this is a recursive type of some kind, set null. | ||
if(!recursion_set.insert(struct_tag).second) | ||
if(!recursion_set_entry.insert_entry(struct_tag)) | ||
{ | ||
if(update_in_place==update_in_placet::NO_UPDATE_IN_PLACE) | ||
{ | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any reason not to just stick in its own file, given how huge this one already is?
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Only because this is very single-purpose. It's more like a
static
helper function immediately preceding its only user than a global class defn.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Up to you - personally always think 1 class-1 file is best