Closed jennalwise closed 2 years ago
I implemented a solution in these commits: https://github.com/gradual-verification/silicon-gv/commit/efda394f8e691f7b09749c71d16219a283d175e2, https://github.com/gradual-verification/silicon-gv/commit/9123fd1dcc47f901a6596d7588690aea9830d804, and https://github.com/gradual-verification/silicon-gv/commit/46727a02b50fe5a535799af79eaaf9cc85ba9fba .
The solution is to keep consumption the same, but collect the frame of the arguments in the predicate and produce those into the optimistic heap after consumption. This is sound, because the optimistic heap is allowed to have duplicate permissions to the heap (which will contain the predicate's body after the unfold and the body may overlap with the frame), and access to those heap locations are either exposed by the predicate body and can therefore be used or are part of the frame and can continue to be used despite the unfold. In contrast, fold statements are hiding heap locations from the verifier, so if the argument frame overlaps with the predicate body the verifier should not have access to the argument frame after the fold even in the optimistic heap (this is unsound).
Something to think about: a similar problem might appear at method calls with the frame of arguments to the method, at folds (which the above solution is unsound for) for arguments to the predicate, and field assigns where consumption of the field being assigned to happens. The above solution is likely unsound for the aforementioned areas, so optimizing them must be either unsound or a new solution need to be thought of and applied for them. On a positive note, the unfold optimization has a significant impact on AVL's static performance such that the aforementioned areas are fine as is. Also, figuring out joins for pure branches and improving the expressiveness of our static specification language will help with this without any special optimizations in the aforementioned areas.
Fixed in this closed pull request: https://github.com/gradual-verification/silicon-gv/pull/43
Problem
The partial specification (recreated_2583.c0) of the AVL benchmark given at the end of this comment/issue is running extremely slow in silicon-gv (not finishing static verification after 20+mins and sometimes failing with out of memory errors). The issue is at unfold statements. If the predicate that is consumed is not in the current imprecise symbolic state, then the verifier conservatively removes all heap chunks from the heap and optimistic heap because they may alias with the predicate's body. However, this removes heap chunks that frame arguments to the predicate, meaning that the information produced into the state from the predicate body is dropped on the floor. In recreated_2583.c0, this results in a blow up in branching due to lost information. This blow-up is extremely large and fast, in the middle of a large computation one unfold statement was being executed 24 times down 24 paths and the rest of the computation would result in a few more branches meaning 48 then 96 etc branches of execution.
More details about the issue can be found here (towards the end of the file), including a simple example illustrating the problem: https://docs.google.com/document/d/1wYQohrMH1uWMQD6rYjjSLD210w-zYfdJK63mYWdmxYA/edit?pli=1# .
recreated_2583.c0