Allow to pass ObjC blocks into folly::Function
authorFelix Leupold <fleupold@fb.com>
Mon, 30 Oct 2017 22:26:55 +0000 (15:26 -0700)
committerFacebook Github Bot <facebook-github-bot@users.noreply.github.com>
Mon, 30 Oct 2017 22:35:22 +0000 (15:35 -0700)
commitd3eb94151a90efced5eb49393d59af59beb39fe1
treefa6e21f368d79c07a98f27e6451f463166b80812
parentffe039c4511c9771974ead5b25762b57955ff1da
Allow to pass ObjC blocks into folly::Function

Summary:
In iOS blocks are initially allocated on the stack and only lazily copied to the heap (e.g when they are assigned to a variable). This means, if you pass a block as an rvalue to a C++ method that keeps moving it around instead of copy assigning it at some point, the block remains on the stack and will get freed once the original method is done (leading to use after free if the block is executed later).

This was mitigated by deleting the conversion from ObjC functions to folly functions. Given that all we need is to make sure that the block is allocated on the heap (that is it is an instance of NSMallocBlock rather than NSStackBlock), it seems drastic to ban the conversion. ObjC developers tend to be more familiar with ObjC blocks and will find it convenient to use this conversion.

This diff insteads implements the constructor and assignment operator by wrapping the ObjC block in a c++ lambda and capturing it by copy. ARC keeps track of the reference count and automatically releases the block when the lambda is deallocated. Moreover, copy only increase the retain count (instead of doing an actual copy) if the block was already stored on the heap (https://www.cocoawithlove.com/2009/10/how-blocks-are-implemented-and.html section NSMallocBlock never actually copies).

Reviewed By: ericniebler

Differential Revision: D6109932

fbshipit-source-id: 48bb446d3a66f46affba774cfe1cfb8a60c661de
folly/Function.h