-
Notifications
You must be signed in to change notification settings - Fork 76
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
Witness invariants for unrolled loops are incorrect #1225
Comments
I think this less of an issue with the unrolling, but with the witness generation and it's mapping back to program points. |
In a way, it's a matter of what "program point" means for us. There are
Actually, it's not just witness generation that is broken by unrolling, but every "join everything per node" process in Goblint and we have many of those, including:
Having to duplicate some fix for each one is far from elegant and a maintenance nightmare. "Join everything per The AST-based unrolling actually introduces some quadratic unrolling when combined with unique mallocs/thread-creates:
Initially, we didn't have the latter, so node duplication was a way to achieve the same effect "for free". When the latter was added (to have unrolled unique thread IDs without unrolling the entire loop itself), this quadratic behavior arose. I don't think this was intentional, or? So the domain-based unrolling already exists but only in very specific places. It could just work at a higher level and "join over all paths" would simply take care of it. |
As expected, the location ambiguity causes problems. For example, consider this program: int main() {
int i;
for (i = 0; i < 10; i++);
return 0;
} When generating a loop invariant at the beginning of line 3, we get a top invariant (nothing known about That is because the node before When generating loop invariants, we cannot just ignore non-loop-head nodes at the same location because that would again be unsound thanks to the syntactic loop unrolling. The unrolled copies of the loop don't have a loop head in the CFG, only the final unrolled loop head is a loop head according to the CFG. Therefore, to account for all iterations, including the unrolled ones, invariant generation has to join everything at that CIL location. In #1248 I have done so to fix the unsoundness, but this phenomenon is quite counterintuitive:
So syntactic loop unrolling makes our analysis more precise but our witnesses less precise. |
Is there something to be done here, such as marking these nodes somehow during the unrolling? |
CHANGES: Functionally equivalent to Goblint in SV-COMP 2024. * Add termination analysis for loops (goblint/analyzer#1093). * Add memory out-of-bounds analysis (goblint/analyzer#1094, goblint/analyzer#1197). * Add memory leak analysis (goblint/analyzer#1127, goblint/analyzer#1241, goblint/analyzer#1246). * Add SV-COMP `termination`, `valid-memsafety` and `valid-memcleanup` properties support (goblint/analyzer#1220, goblint/analyzer#1228, goblint/analyzer#1201, goblint/analyzer#1199, goblint/analyzer#1259, goblint/analyzer#1262). * Add YAML witness version 2.0 support (goblint/analyzer#1238, goblint/analyzer#1240, goblint/analyzer#1217, goblint/analyzer#1226, goblint/analyzer#1225, goblint/analyzer#1248). * Add final warnings about unsound results (goblint/analyzer#1190, goblint/analyzer#1191). * Add many library function specifications (goblint/analyzer#1167, goblint/analyzer#1174, goblint/analyzer#1203, goblint/analyzer#1205, goblint/analyzer#1212, goblint/analyzer#1220, goblint/analyzer#1239, goblint/analyzer#1242, goblint/analyzer#1244, goblint/analyzer#1254, goblint/analyzer#1269). * Adapt automatic configuration tuning (goblint/analyzer#912, goblint/analyzer#921, goblint/analyzer#987, goblint/analyzer#1168, goblint/analyzer#1214, goblint/analyzer#1234).
CHANGES: Functionally equivalent to Goblint in SV-COMP 2024. * Add termination analysis for loops (goblint/analyzer#1093). * Add memory out-of-bounds analysis (goblint/analyzer#1094, goblint/analyzer#1197). * Add memory leak analysis (goblint/analyzer#1127, goblint/analyzer#1241, goblint/analyzer#1246). * Add SV-COMP `termination`, `valid-memsafety` and `valid-memcleanup` properties support (goblint/analyzer#1220, goblint/analyzer#1228, goblint/analyzer#1201, goblint/analyzer#1199, goblint/analyzer#1259, goblint/analyzer#1262). * Add YAML witness version 2.0 support (goblint/analyzer#1238, goblint/analyzer#1240, goblint/analyzer#1217, goblint/analyzer#1226, goblint/analyzer#1225, goblint/analyzer#1248). * Add final warnings about unsound results (goblint/analyzer#1190, goblint/analyzer#1191). * Add many library function specifications (goblint/analyzer#1167, goblint/analyzer#1174, goblint/analyzer#1203, goblint/analyzer#1205, goblint/analyzer#1212, goblint/analyzer#1220, goblint/analyzer#1239, goblint/analyzer#1242, goblint/analyzer#1244, goblint/analyzer#1254, goblint/analyzer#1269). * Adapt automatic configuration tuning (goblint/analyzer#912, goblint/analyzer#921, goblint/analyzer#987, goblint/analyzer#1168, goblint/analyzer#1214, goblint/analyzer#1234).
Our CIL AST based loop unrolling duplicates nodes for the same program point (in the literal sense). Thus we end up generating witness invariants for each node but the same location, e.g.
i == 0
andi == 15
, which are contradictory:Again, path-sensitivity–based unrolling would automatically avoid this issue because witness invariants are disjunctions over all paths at a node.
The text was updated successfully, but these errors were encountered: