-
Notifications
You must be signed in to change notification settings - Fork 89
Static check for zero_alloc: ignore allocation that lead to exceptional return #1157
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
Conversation
Co-authored-by: Xavier Clerc <[email protected]>
I am not sure I understand the semantics of
|
This example is accepted when we pass
The dependency on a seemingly unrelated compiler flag is quite annoying for testing, but allocations depend on compiler configuration and optimization flags. |
Noted; here is another example I don't think I understand
It works if |
I am not sure whether it is related to the previous
while the following is rejected:
|
Back to #1157 (comment), it seems to fail if |
I can write the code for correctly handling delayed try-with in Regarding this PR, the problem is quite tricky and I think this PR comes short in a few places. exception E
let rec f x b =
if b then (g x; raise E)
else ()
and g y = ignore (y, y) (* Allocating *) With a fixpoint computation, we should be able to infer that More problematic, the handling of exception paths looks weird. I think this is because the allocation check is naturally expressed as a forward dataflow analysis, but you're trying to use the backwards one. It should be possible to make it work anyway, but it doesn't look obvious when looking at your code that it is correct (the fine details around the handling of Divergence can be handled relatively easily in both forward and backward analyses. For the backwards one, I think it can be done by specifying a |
This reverts commit f2dfe50.
Co-authored-by: Xavier Clerc <[email protected]>
The following is really a corner case, and quite
It fails because the |
(Actually, proper support for "forward" references |
I don't think so, there is no call to the helper function. It's a bug - the annotation should not be on the helper function. |
Oh, indeed I misread the output of |
(And to be clear, as far as I can see the annotation |
Ah, yes, you are right about it! so, it's not a bug, good. |
I think this is one of those cases where mutable patterns cause functions to have different arities than expected. In this case, we end up with |
…flambda-backend into alloc-check-exn-threevalued
Two usability quibbles, for a follow-up PR:
|
@xclerc ah these are tricky, but I'll look into it.
it's not clear to me how to do it in a low-overhead way for the relaxed propery, because some of the encountered allocation sites would later be discarded. I think the best way to do it would be editor ui integrtion for inspecting the intermediate represetnation of this analysis alongside the source.
looks like this information is no longer available at lambda, even when the function is not anonymous. |
I was thinking maybe the debuginfo, For the name, that would indeed Anyway, what would go into a |
@lthls do you have any other comments about this version? (A follow up PR will do the outer fixpoint on function summaries, lifted from |
I don't have anything new to add, for me this PR can go forward. |
a7d005a flambda-backend: Lazy deserialization of cmi files (oxcaml#1322) aa83fa3 flambda-backend: Reinstate previous API for Env.lookup_value (oxcaml#1323) e4007a4 flambda-backend: Lazy substitution into value_declaration (oxcaml#1320) 634b607 flambda-backend: Merge Types.* and Subst.Lazy.* types (oxcaml#1312) cf82708 flambda-backend: Bump magic numbers for 4.14.1-7 (oxcaml#1317) 6470400 flambda-backend: zero_alloc attribute payload "assert all" and "ignore" (oxcaml#1296) bba5248 flambda-backend: Teach `ocamldep` about all the language extensions (oxcaml#1303) 33e97b0 flambda-backend: Change Includemod to work on lazy modtypes (oxcaml#1228) 16e5002 flambda-backend: zero_alloc new warning for unchecked functions (oxcaml#1302) 36b4626 flambda-backend: Attribute [@@@zero_alloc check] to turn the check on (oxcaml#1294) 3b524c6 flambda-backend: Cmm.value_kind cleanup (oxcaml#1091) ec99505 flambda-backend: Fix failure of `check_all_arches` on RISCV (oxcaml#1300) 450bc58 flambda-backend: Backend changes for multiple returns (oxcaml#1268) 84a7a26 flambda-backend: Static check for zero_alloc: ignore allocation that lead to exceptional return (oxcaml#1157) 1723728 flambda-backend: Re-enable parallel build of the runtime (oxcaml#1287) 26ea7f3 flambda-backend: Fix closure marshalling when not in NNP mode (oxcaml#1286) 9b91f2e flambda-backend: Reduce number of caml_apply functions taking/returning "I" and "V" (oxcaml#1272) 1686928 flambda-backend: Restore Cmm unboxing behaviour inside regions (oxcaml#1285) cf9be42 flambda-backend: Fix all the no-naked-pointers problems (oxcaml#1282) 8fe089e flambda-backend: Unrevert oxcaml#1131 and fix a Cmm unboxing bug (oxcaml#1284) c4143c3 flambda-backend: Revert "Make Selectgen treat region boundaries more precisely" (oxcaml#1283) 2078dce flambda-backend: Add some -dtimings output for the typechecker (oxcaml#1245) 273a7f9 flambda-backend: Make Selectgen treat region boundaries more precisely (oxcaml#1131) 47610e6 flambda-backend: Bump magic numbers for 4.14.1-6 (oxcaml#1274) fd53d38 flambda-backend: Generate *.cms files for merlin (oxcaml#1232) 853f95f flambda-backend: Add tail_mod_const to builtin_attrs (oxcaml#1265) f9ef051 flambda-backend: Fix issue caused by effects of gadt expansion in mode cross check (oxcaml#1263) e9ffcf8 flambda-backend: Fix dependencies for regenerating Flambda2 parser, tests (oxcaml#1255) 6f1cd1f flambda-backend: Restore a lost location, needed for merlin (oxcaml#1242) 009332b flambda-backend: Fix merge from ocaml-jst git-subtree-dir: ocaml git-subtree-split: a7d005a
a7d005a flambda-backend: Lazy deserialization of cmi files (oxcaml#1322) aa83fa3 flambda-backend: Reinstate previous API for Env.lookup_value (oxcaml#1323) e4007a4 flambda-backend: Lazy substitution into value_declaration (oxcaml#1320) 634b607 flambda-backend: Merge Types.* and Subst.Lazy.* types (oxcaml#1312) cf82708 flambda-backend: Bump magic numbers for 4.14.1-7 (oxcaml#1317) 6470400 flambda-backend: zero_alloc attribute payload "assert all" and "ignore" (oxcaml#1296) bba5248 flambda-backend: Teach `ocamldep` about all the language extensions (oxcaml#1303) 33e97b0 flambda-backend: Change Includemod to work on lazy modtypes (oxcaml#1228) 16e5002 flambda-backend: zero_alloc new warning for unchecked functions (oxcaml#1302) 36b4626 flambda-backend: Attribute [@@@zero_alloc check] to turn the check on (oxcaml#1294) 3b524c6 flambda-backend: Cmm.value_kind cleanup (oxcaml#1091) ec99505 flambda-backend: Fix failure of `check_all_arches` on RISCV (oxcaml#1300) 450bc58 flambda-backend: Backend changes for multiple returns (oxcaml#1268) 84a7a26 flambda-backend: Static check for zero_alloc: ignore allocation that lead to exceptional return (oxcaml#1157) 1723728 flambda-backend: Re-enable parallel build of the runtime (oxcaml#1287) 26ea7f3 flambda-backend: Fix closure marshalling when not in NNP mode (oxcaml#1286) 9b91f2e flambda-backend: Reduce number of caml_apply functions taking/returning "I" and "V" (oxcaml#1272) 1686928 flambda-backend: Restore Cmm unboxing behaviour inside regions (oxcaml#1285) cf9be42 flambda-backend: Fix all the no-naked-pointers problems (oxcaml#1282) 8fe089e flambda-backend: Unrevert oxcaml#1131 and fix a Cmm unboxing bug (oxcaml#1284) c4143c3 flambda-backend: Revert "Make Selectgen treat region boundaries more precisely" (oxcaml#1283) 2078dce flambda-backend: Add some -dtimings output for the typechecker (oxcaml#1245) 273a7f9 flambda-backend: Make Selectgen treat region boundaries more precisely (oxcaml#1131) 47610e6 flambda-backend: Bump magic numbers for 4.14.1-6 (oxcaml#1274) fd53d38 flambda-backend: Generate *.cms files for merlin (oxcaml#1232) 853f95f flambda-backend: Add tail_mod_const to builtin_attrs (oxcaml#1265) f9ef051 flambda-backend: Fix issue caused by effects of gadt expansion in mode cross check (oxcaml#1263) e9ffcf8 flambda-backend: Fix dependencies for regenerating Flambda2 parser, tests (oxcaml#1255) 6f1cd1f flambda-backend: Restore a lost location, needed for merlin (oxcaml#1242) 009332b flambda-backend: Fix merge from ocaml-jst git-subtree-dir: ocaml git-subtree-split: a7d005a
A new version of #864 + #863 + #870.
Best reviewed commit by commit.
I can try to split them into separate PRs, but it is quite tricky to get the separate PRs to build and pass the tests on their own.
The main change: abstract domain is a triple
{ nor; exn; div; }
where each of the components represents different paths through the function: paths to normal return, paths to exception return, and diverging paths that never retrun, resp. Each component can have one of the following values:Bot
for unreachable (empty set of paths),Safe
for "guaranteed to not allocate on any of the relevant paths", andTop
for arbitray allocation on the relevant paths.The "strict" check requires no allocation on any path. The "relaxed" check, which is the defaul, allows allocation on paths that lead to exceptional return from the function (i.e.,
exn
can beTop
in the summary of the function), but not on normal return or infinite loops. Allocatins on paths that end in a call to an external function that never returns, such asexit
, are not ignored in "relaxed" mode (it was simpler to implement).Checkmach
usesbackend/dataflow.ml
which is essentially a copy of the upstream backwards dataflow analysis. Thediv
component is computed as a postprocessing step using another run of the same dataflow analysis, after the other components are computed. To make this postprocessing faster and simpler to implement, there is a small change to the interface ofDataflow
to expose the mapping of labels to abstract value.Attrbutes are now named
[@zero_alloc]
and[@zero_alloc strict]
with the corresponding[@zero_alloc assume]
and[@zero_alloc strict assume]
. The internal representation of these attributes has been reworked to make it easier to parse them and extend the static checker with other properties in the future. This involves changes throughout the compilation pipeline to propagate the new representation of these attributes all the way to the backend. Currently, this is in 3 separate separate commits. I can split this out as a separate PR, but it would mean fixing the existingcheckmach.ml
, which is substantially modified in the following steps.Better user-error messages: locations when check fails point to the attribute instead of the entire body of the function.
Location.t
is passed all the way to the backend.Refactor cmx format representation of the results of the static checker: move
Checks
module out ofCmx_format
into a separate module. Decomple the representation of function summaries used inCompilenv
from the "raw" version saved to cmx. Change the "raw" representation from maps to lists. Should it use arrays? It is now easy to change.Flambda2: results may be unsound in the presence of Delayed Try-with that cannot be represented as a Regular Try-with. I can make the analysis conservatively sound, but it causes the CI tests to fail, and there is no easy way to distinguish flambda2 in dune tests. Also I am not sure if the current optimizatons in flambda2 generate the cases. We need to fix
backend/dataflow.ml
to support them and maybe updatebackend/liveness.ml
to use this dataflow as well. Separate PRs.There are several ways in which the current analysis can be optimized to use less memory and finish early when a function is established to be allocating. I am leaving them for later as it makes it harder to reason about soundness.