-
Notifications
You must be signed in to change notification settings - Fork 38
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix wrong cursor inference in the context of loops (#1388)
## Summary * fix cursor inference bug where variables were erroneously inferred as cursors, leading to use-after-free issues * improve cursor inference. `var`/`let` bindings are now inferred to be cursors more reliably Fixes #1385 ## Details For `var`/`let` bindings defined in loops, the `aliveEnd` is now only updated during the first analysis of the loop. This ensures that variables defined outside the loop, but only assigned to within the loop, always have longer alive times than variables defined within loops, thus preventing outer variables borrowing from inner variables (cursorfication cannot happen when a variable outlives its assignment source). This fix also renders the `isConditionallyReassigned` heuristic obsolete, which was used to fix a more specific case of the same bug. The heuristic disabled cursorfication for all variables of which re-assignments are enclosed by a loop and `if`/`else`/`elif`/`of`, which also applied to, e.g.: ```nim while cond: if cond: var a = newString(...) var b = newString(...) var x: string x = a x = b # this assignment disabled `x` being turned into a cursor discard a ``` With the heuristic removed, in the above example, `x` is now turned into a cursor, matching what would happen when there is no enclosing loop or `if`.
- Loading branch information
Showing
3 changed files
with
93 additions
and
19 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
discard """ | ||
description: ''' | ||
Ensure that outer variables don't borrow from locals within loops, when not | ||
safe | ||
''' | ||
matrix: "--showir:mir_in:test --hints:off" | ||
action: compile | ||
nimoutFull: true | ||
nimout: '''-- MIR: test | ||
scope: | ||
def x: Object | ||
scope: | ||
while true: | ||
scope: | ||
scope: | ||
def _3: bool = not(arg cond) | ||
if _3: | ||
scope: | ||
goto [L2] | ||
def y: Object = () | ||
def_cursor _5: Object = x | ||
use(arg _5) -> [L3, L4, Resume] | ||
x = sink y | ||
goto [L3, L5] | ||
finally (L3): | ||
destroy y | ||
continue {L4, L5} | ||
L5: | ||
L2: | ||
goto [L4, L6] | ||
finally (L4): | ||
destroy x | ||
continue {L6} | ||
L6: | ||
-- end | ||
''' | ||
""" | ||
|
||
type Object = object | ||
|
||
# make Object a type that's eligible for cursor inference | ||
proc `=destroy`(x: var Object) = | ||
discard | ||
|
||
proc use(x: Object) = | ||
discard | ||
|
||
proc test(cond: bool) = | ||
var x: Object | ||
while cond: | ||
var y = Object() | ||
use x | ||
# if `x` were a cursor, the above usage would observe a stale value, | ||
# as the value assigned below went out of scope already | ||
x = y | ||
|
||
test(false) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters