nim-works / nimskull

An in development statically typed systems programming language; with sustainability at its core. We, the community of users, maintain it.

Home Page:https://nim-works.github.io/nimskull/index.html

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

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.