You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: book/src/rules/loans.md
+92-9Lines changed: 92 additions & 9 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -2,25 +2,25 @@
2
2
3
3
Loan analysis is the heart of the borrow checker, and will compute:
4
4
- illegal access errors: an action on a loan, that is illegal to perform
5
-
- illegal subset relationships errors: missing relationships between placeholder origins
5
+
- illegal subset relations errors: missing relationships between placeholder origins
6
6
7
7
This is done in multiple variants, whose goals are different: performance, readability, tests and validation.
8
8
9
9
Broadly speaking, the goals of the analysis are 1) to track loans:
10
10
- from the point and origin in which they are issued, to the points where they are invalidated
11
11
- flowing from origin to origin at a single point, via their `subset` relationships
12
-
- flowing from point to point in the CFG, according to the origins' liveness (stopping at points where a loan is killed)
12
+
- flowing from point to point in the CFG, according to the origins' liveness (stopping at points where a loan is killed)
13
13
14
14
And 2) to track undeclared relationships between placeholder origins.
15
15
16
-
Any live loan which is invalidated will be an illegal access error, any placeholder which flows into another placeholder unexpectedly will be an illegal subset relationship error.
16
+
Any live loan which is invalidated will be an illegal access error, any placeholder which flows into another placeholder unexpectedly will be an illegal subset relation error.
17
17
18
18
### Inputs
19
19
20
20
The input relations will be described below, but the [dedicated page](./relations.md) will have more information about them.
21
21
22
22
```prolog
23
-
// Indicates that the `loan` was "issued" at the given `point`, creating a
23
+
// Indicates that the `loan` was "issued" at the given `point`, creating a
24
24
// reference with the `origin`. Effectively, `origin` may refer to data from
25
25
// `loan` starting at `point` (this is usually the point *after* a borrow rvalue).
The rules below compute what loans are contained in which origins, at given points of the CFG: starting from the "issuing point and origin", a loan is propagated via the subsets computed above, at a given point in the CFG. Liveness is then taken into account to propagate these loans along the CFG: if a loan is contained in an origin at a given point, and that the origin is live at the successor points, the loan is propagated to the successor points. A subtlety here is that there are points in the CFG where a loan can be killed, and that will stop propagation. Rule 6 uses both liveness and kill points to know whether the loan should be propagated further in the CFG.
95
+
The rules below compute what loans are contained in which origins, at given points of the CFG: starting from the "issuing point and origin", a loan is propagated via the subsets computed above, at a given point in the CFG. Liveness is then taken into account to propagate these loans along the CFG: if a loan is contained in an origin at a given point, and that the origin is live at the successor points, the loan is propagated to the successor points. A subtlety here is that there are points in the CFG where a loan can be killed, and that will stop propagation. Rule 6 uses both liveness and kill points to decide whether the loan should be propagated further in the CFG.
### Placeholder subsets, and illegal subset relationships errors
138
+
### Placeholder subsets, and illegal subset relations errors
139
139
140
140
These errors can be computed differently depending on the variant, but the goal is the same: if the analysis detects that a placeholder origin ultimately flows into another placeholder origin, that relationship needs to be declared or it is an error.
The rules above document the `Naive` variant of loan analysis, as it is conceptually simple and describes all the important parts computed by the Polonius model. This variant is "naive" in the sense that to stay clear and simple, the rules compute more things than strictly required. In particular, it computes the complete transitive subsets of all origins, as well as the loans contained by each origin at every point of the CFG.
159
+
160
+
In practice, different "grades" of borrow-checking can be useful: each with different levels of precision in what it accepts and with different computational complexity requirements. The lowest of such grades, the `LocationInsensitive` variant, trades off precision for speed by ignoring both the location where subsets happen, and the origins' contents at the CFG points. The idea is: if an analysis would find no error when ignoring path- and flow-sensitivity, then the full analysis would find no error either. If it does find potential errors, then the full analysis will find a subset of these location-insensitive errors.
161
+
162
+
This can be used as a quick pre-pass: if there a no errors, a full, expensive, analysis does not need to run, otherwise, only the loans where potential errors occur would need to be fully checked to remove false positives.
163
+
164
+
The inputs are the same as the `Naive` variant, but remove the CFG points from the `subset`s. Subsets are not tracked, and are used to approximate loan propagation inside origins (regardless of liveness and location-sensitivity) in `origin_contains_loan`:
165
+
166
+
```prolog
167
+
.decl subset(Origin1:origin, Origin2:origin)
168
+
169
+
// R1: the subsets are the non-transitive `subset_base` static input,
// R5b: Compute potential illegal access errors, i.e. invalidations
201
+
// of live loans.
202
+
potential_errors(Loan, Point) :-
203
+
loan_invalidated_at(Loan, Point),
204
+
loan_live_at(Loan, Point).
205
+
```
206
+
207
+
Note: rules "5a" and "5b" above are named to match [the implementation](https://github.com/rust-lang/polonius/blob/master/polonius-engine/src/output/location_insensitive.rs) which computes `potential_errors` as a single "rule 5" without materializing the `loan_live_at` intermediate relation of "rule 5a".
208
+
209
+
Illegal subset relation errors (which are by definition about "subsets") can still be computed by propagating the placeholder loans, and detecting when they unexpectedly flow into another placeholder origin: one where this specific relationship between the two placeholders was not declared.
// R6: compute potential illegal subset relations errors, i.e. the
215
+
// placeholder loans which ultimately flowed into another placeholder
216
+
// origin unexpectedly.
217
+
potential_subset_errors(Origin1, Origin2) :-
218
+
placeholder(Origin1, Loan1),
219
+
placeholder(Origin2, _),
220
+
origin_contains_loan(Origin2, Loan1),
221
+
!placeholder_known_to_contain(Origin2, Loan1).
222
+
```
223
+
224
+
This requires a simple input equivalent to the transitive closure of `known_placeholder_subset`, tracking the placeholder loans a given placeholder origin is known to contain instead, and is computed like so:
A more detailed description of the rules in the `LocationInsensitive` and `Opt` variants will be added later but they compute the same things described above:
159
-
- the `LocationInsensitive` variant tries to quickly find "potential errors" in a path- and flow-insensitive manner: if there are no errors, we don't need to do the full analysis. If there are potential errors, they could be false positives or real errors: the interesting thing is that only these loans and origins need to be checked by the full analysis.
160
-
- the `Opt` variant limits where the subset transitive closure is computed: some origins are short-lived, or part of a subsection of the subset graph into which no loan ever flows, etc. These cases don't contribute to errors or loan propagation and are not useful to track.
239
+
In the current implementation, this quick `LocationInsensitive` filter is used as a pre-pass to another optimized variant, as part of [the `Hybrid` algorithm](https://github.com/rust-lang/polonius/blob/2cf8336f7ff9932270160a392ca5be3c804b7f41/polonius-engine/src/output/mod.rs#L42).
240
+
241
+
A more detailed description of the rules in this `Opt` variant will be added later but it computes the same data as the `Naive` variant described above, more efficiently, by limiting where the subset transitive closure is computed: some origins are short-lived, or part of a subsection of the subset graph into which no loan ever flows, and therefore don't contribute to errors or loan propagation. There's no need to track these specific cases.
242
+
243
+
In the meantime, [the implementation](https://github.com/rust-lang/polonius/blob/master/polonius-engine/src/output/datafrog_opt.rs) documents the relations and rules it uses in its computation.
0 commit comments