Remove macOS memory leaks when writing to the clipboard #105
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This PR removes the long-outstanding memory leaks in the macOS clipboard backend. After some experimentation, I found that these methods had leaky implementations:
set_string
set_image
set_html
None of the reading functions had leaks AFAICT.
The root cause of (most) the issues was that several calls to
msg_send!
were not passing their arguments correctly. Instead of passing a pointer to the relevant Objective-C object to a class function, they passed the value itself via move. This worked before since the value could still be read by the system, but it became problematic with memory usage. As the system functions only expected a reference to the data, none of them attempted to free it since this would lead to a use-after-free or double-free in user code. So to Rust's eyes, the value was moved across the FFI boundary and never had their destructors called, essentially the same ifmem::forget
had been used.To resolve these problems, I corrected the callsites to pass a reference/pointer across like the APIs expected.
The other issue was that when creating an
NSImage
class allocation, the previous code was accidentally increasing the reference count after allocating instead of taking ownership. This resulted in an unbalanced retain count that meant the resulting class could never be freed. Allocating a class always has at least one reference, otherwise it would be instantly reclaimed by the runtime. Our user code becomes the object's new owner once the runtime has finished preparing it.Relates to #24