-
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
Partially fix unsound join for top
with empty environment in ApronDomain
#1354
Conversation
is_bot returned true for some elements for which is_top_env returned true, leading to too small values being returned.
When changing the Maybe it would be necessary to separate the abstraction for "uninitialized state" and "unreachable state". |
Wit the help of @jerhard we looked at it a bit on Friday and were able to narrow it down a bit. I have dug a bit further now, the problem seems to be the following:
This problem does not surface for other privatizations such |
The remaining tests that fail now are
|
The problem for 46/12 was similar:
The fix is to not consult |
If one adds a |
@jerhard It seems like I cannot request your review as you opened the PR, but it would be great if you can also have a look! |
The CC @stilscher |
(* If no globals are contained here, none need to be published *) | ||
(* https://github.com/goblint/analyzer/pull/1354 *) | ||
if g_vars <> [] then sideg V.mutex_inits rel_side; |
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.
This sounds like some bottom-top confusion again: if there are no globals (i.e. the environment is empty), then don't side-effect (i.e. side-effect bottom) instead of side-effecting top.
Conditionally flipping a top to bottom seems inconsistent with all other values.
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.
I still think it's conceptually the right thing to do and not just a hack.
The thing is that we abuse the presence of globals in the relation as a no-overhead way to track whether one of the threads being joined possibly was in single-threaded mode.
If none of these threads was single-threaded (g_vars = []
), all initial values are guaranteed to have been published and no side -effect is needed.
Does this make sense? If yes, I can write a comment detailing this reasoning.
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.
The thing is that we abuse the presence of globals in the relation as a no-overhead way to track whether one of the threads being joined possibly was in single-threaded mode.
How so? We explicitly check the MustBeSingleThreaded
query right before this. Prior to this, nothing is conditional on g_vars = []
.
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.
This is the case of branched thread creation.
- Case 0: Both ST (single-threaded), nothing to do.
-
Case 1: One thread is ST, and the other one is not. After the join,
Q.MustBeSingleThreaded
is false, and the globals from the single-threaded side of the join need need to be published. In this case, potentially,g_vars <> []
. Ifg_vars = []
there are no globals, and not causing a side-effect is ok. -
Case 2: Both MT, nothing should be done. In this case
g_vars = []
. Earlier$$\bot$$ was side-effected, now$$\top$$ would be side-effected which we need to protect against.
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.
Being multi-threaded doesn't imply g_vars = []
, though.
Special-casing []
to flip the lattice is not a natural extension of the behavior on all other environments. I'm afraid we're setting ourselves up for a similar issue about top-bottom confusion that we're trying to fix here.
Suppose the global unknown has a non-bottom relation
-
$R_{\{x\}} \sqsubseteq R_{\{x\}}$ by reflexivity. -
$\top_\emptyset \sqsubseteq R_{\{x\}}$ because$\emptyset \subseteq \{x\}$ and$\top_\emptyset \sqsubseteq R_{\{x\}}\vert_\emptyset = \top_\emptyset$ by the definition of heterogeneous$\sqsubseteq$ (e.g. see the unassume paper) and reflexivity.
It therefore follows that
So side-effecting
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.
Principled fix is delayed to #1380.
@@ -489,7 +489,11 @@ struct | |||
in | |||
let get_mutex_inits = getg V.mutex_inits in | |||
let get_mutex_inits' = RD.keep_vars get_mutex_inits [g_var] in | |||
RD.join get_mutex_global_g get_mutex_inits' | |||
if not (RD.mem_var get_mutex_inits' g_var) then | |||
(* This is an escaped variable whose value was never side-effected to get_mutex_inits' *) |
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.
Is this not just a workaround for the actual bug? Seems like escapes should also contribute to mutex_inits
.
BasePriv.PerMutexPrivBase
and BasePriv.PerMutexMeetTIDPriv
side-effect escapes to mutex_inits
at least.
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.
Yes, in the base priv this is all not problematic, as it is non-relational. Here, this all becomes fragile, and I think for now we are wise to avoid the set of variables at global unknowns not only shrinking (due to decreasing protection) but also increasing in non-obvious matters due to escapes also being tracked associated with mutex_inits
which is supposed to abstract the state at program start. Maybe this is also something for #1380.
This is because with goblint/gobview#41 changes were made to GobView that rely on the respective changes in Goblint (#1360). Both PRs were already merged, but this PR is based on an older version that does not include the Goblint changes yet. Merging with the master branch should be sufficient to fix it. |
It does not. |
@jerhard @sim642: Anyone opposed to merging this as a stop-gap to at least be sound for the problematic cases reported here and enable experiments for my thesis until we have time to do #1380? @stilscher: With the gobview things, I have no idea how to debug but it should be completely orthogonal: Nothing is touched here that is even used in JS builds. |
I haven't looked, but it might just be crashing during some initialization. For example |
Right on the money! Together with @stilscher we were able to fix it and it was exactly this. I didn't think that the eta expansion was needed, as it was also not done for |
That's odd indeed. By that logic it should've already been failing before. So maybe there's something else going on, like one of them actually getting called from elsewhere during initialization and the other one not. |
I think it could also be an artifact of compilation order or something the like. Given that it works now, I'd suggest to go ahead and merge it. |
Since this isn't the principled fix but still leaves us with a domain that clearly violates basic lattice properties, I think this should go through an sv-benchmarks run. It's not exactly obvious that this cannot expose some issue elsewhere by fixing this one particular sv-benchmark with some special conf. |
Do you currently have capacity in Tartu? Our machines are quite loaded with SOAP benchmarks for the past few weeks. |
I don't have immediately because I'm running SV-COMP 2024 tools on Concrat with 2h time limit, which is going to take a while... |
I started a run on |
The results do not differ much from the last run we did on sv-comp in November (d629d14) which is our official sv-comp release. The new numbers are:
There are four new unsoundnesses (#1385) that are however also present on master. I will also start a diff with the current master to see which of these changes are actually due to this PR, but I think it at least doesn't like this is a huge regression for now. |
Good catch! It looks like it fixes only the issue where both branches are dead that the regression test also addresses. |
W.r.t current master, the only changes with this PR are for unreach_call.zip where 5 tasks fluctuate between Runtimes remain consistent. I would suggest to merge this now, as it fixes known soundness bugs (the one added to the regression tests) and does not deteriorate SV-COMP results. |
top
with empty environment in ApronDomain
top
with empty environment in ApronDomain
The
join
in theApronDomain
behaves incorrectly when given the "Top" element for the empty environment: In that case, it returns the other element. This is because thejoin
checks foris_bot
, which checks for equality withbot
, which is defined as the top element for the empty environment.In the given problematic example, the analysis is context-insensitive and the auto-tuner selected only a subset of the variables to be tracked by the relational analysis. There, such a Top-element in an empty environment would arise, leading to an unsound analysis.
This PR changes the Apron Domain to fix this issue.