procedure result is not cleaned up if the procedure raises
zerbina opened this issue · comments
Example
type Object = object
has: bool
var wasDestroyed: bool
proc `=destroy`(x: var Object) =
if x.has:
wasDestroyed = true
proc create(doRaise: bool): Object =
result = Object(has: true)
if doRaise:
raise CatchableError.newException("")
proc test() =
try:
var x = create(true)
except:
# the value created in `create` must have been destroyed at this point
doAssert wasDestroyed
test()
Actual Output
The assertion fails.
Expected Output
The program compiles and runs successfully.
Possible Solution
Either the caller or callee needs to destroy the result in case the callee raises. The simplest solution would be wrapping the body of a procedure that can raise in a try
/except
that destroys the result
and re-raises the exception.
Additional Information
This is a problem at the MIR-level, meaning that all backends are affected.
While it's already possible to implement the fix for this bug, I'm first waiting for #1281 to be merged.
At the moment, mirgen
would need to wrap the body of result
having procedures in:
try:
...
except:
`=destroy`(result)
raise
which works, but has a minor overhead due to the re-raise. With the new control-flow primitives, it'll be possible to use a finally
section that only intercepts exceptional control-flow, which has less overhead.