-
Notifications
You must be signed in to change notification settings - Fork 178
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
fix: don't allow lambdas to leak captures #1440
base: master
Are you sure you want to change the base?
Conversation
When lambdas close over some external environment variable, if that variable is a linear value, their environment becomes the owner of the captured value and the value will be freed with the environment. If the lambda moves this variable out of its own scope, however, e.g. by returning it in its body, both the caller and the lambda environment will wind up owning the value, resulting in double frees. For now, we prevent this scenario by simply disallowing functions to leak variables captured from another scope. Doing so is now an error. Of course, one can still copy these values without issue. We achieve this through set operations. If the memory state loses the fake deleters for the set of a lambdas captured bindings after its body is evaluated, we've encountered an ownership leak, and report an error. ```clojure (defn example [] (let [capture @"" lambda (fn [] capture)])) ;; this is now an error (defn example [] (let [capture @"" lambda (fn [] @&capture)])) ;; this is still OK ``` fixes carp-lang#1040
Note: here's an example of what the error currently looks like:
fairly unhelpful function name b/c we check this after the lambda has been lifted. I'll tackle this as a later improvement. I gotta add an error test as well. |
op, looks like there are some regressions I'll have to take care of first |
Adds tests to ensure lambdas do not leak ownership of their captured variables. In addition, the nested lambda test now needs to accept a reference to a function instead of a function value (otherwise an ownership leak occurs).
Note: MacOS failures are due to new github runner images which have a new version of clang that throws a waring that our generated C has triggered. I'll open a separate PR to fix this. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems like a good way to do this!
At some point (I believe version 13.0.0?) clang added a warning that catches variables that were assigned but unused. This version of clang (or later) is now bundled w/ github's macos images and is causing our tests to fail in continuous integration. We can currently generate C code that trips this warning, so for now I've disabled it as we do some other warnings related to variable usages.
oh no... looks like the clang version diffs on different platforms are leading to problems. Linux and Nix CI images are using older clang versions which means the recent macOS CI fix breaks them. I guess we need to fix this on the CI side instead of baking in warning flag options into default Carp projects. |
Dang... perhaps the cleanest thing would be to check for clang version in dynamic carp and add the warning flag there (while loading core) if it is needed. Or can you think of an easier way? |
It looks like github has other images of linux at least that have later versions of clang, so we might be able to fix our CI issues just by figuring out how to use those images instead. As for the more general problem of default project settings--checking the compiler version dynamically seems like a good idea. The ultimate fix would be to make our generated code At the moment, it seems like the only thing we'd have to implement is some check in the emitter that drops unused variables and remove some self-assigns. Not sure how much work that will be. Another hacky fix would be to remove the |
When lambdas close over some external environment variable, if that variable is a linear value, their environment becomes the owner of the captured value and the value will be freed with the environment. If the lambda moves this variable out of its own scope, however, e.g. by returning it in its body, both the caller and the lambda environment will wind up owning the value, resulting in double frees.
For now, we prevent this scenario by simply disallowing functions to leak variables captured from another scope. Doing so is now an error. Of course, one can still copy these values without issue.
We achieve this through set operations. If the memory state loses the fake deleters for the set of a lambdas captured bindings after its body is evaluated, we've encountered an ownership leak, and report an error.
fixes #1040