Assume having the following setup:
type My is new Integer;
type My_Acc is access My;
procedure Replace(Self : in out My_Acc; New_Int : Integer)
with Pre => New_Int /= Self.all, Post => Self'Old.all /= Self.all;
Note: Code above might not be fully valid, but I hope the concept is understandable.
Now what happens if Unchecked_Deallocation() is used on Self inside Replace
and a new Integer is allocated and set to Self (This should result in Self'Old pointing to a now invalid memory location)?
Does Ada keep kind of a snapshot where Self'Old points to the previous memory location, but before Unchecked_Deallocation() is executed?
If Self'Old would get invalid for use in the Post contract, how could you still access the previous value? Is it possible to create a manual snapshot in the Pre contract that can then be used in Post? Maybe it can be achieved using Ghost_Code?
I want to make everything in Spark, in case that changes something.
Edit: Fixed Self to in out as mentioned by Simon Wright.
Edit: Fixed type of Self to allow null
In ARM 6.1.1(26ff) it says
... in other words, nothing fancy is expected, just a straight copy of (in this case)
Self: notSelf.all.So, if your
ReplacedeallocatesSelf, thenSelf’Oldis a dangling reference, and erroneous.I suggested previously that changing the postcondition to
would be safe; why wouldn’t that meet your requirements? is there something going on you haven’t told us about?
Note the subtle difference between
Self’Old.allandSelf.all’Old. The first one takes a copy ofSelfas it was before the call, which gets dereferenced after the call (by which time it’s pointing into hyperspace), while the second one dereferences the priorSelfand copies the integer value it finds there; on return that’s still valid.