<html><head><meta http-equiv="Content-Type" content="text/html charset=us-ascii"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><br class=""><div><blockquote type="cite" class=""><div class="">On Oct 9, 2014, at 09:47, David Blaikie <<a href="mailto:dblaikie@gmail.com" class="">dblaikie@gmail.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><br class="Apple-interchange-newline"><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><div class="gmail_quote" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;">On Thu, Oct 9, 2014 at 12:11 AM, Jared Grubb<span class="Apple-converted-space"> </span><span dir="ltr" class=""><<a href="mailto:jared.grubb@gmail.com" target="_blank" class="">jared.grubb@gmail.com</a>></span><span class="Apple-converted-space"> </span>wrote:<br class=""><blockquote class="gmail_quote" style="margin: 0px 0px 0px 0.8ex; border-left-width: 1px; border-left-color: rgb(204, 204, 204); border-left-style: solid; padding-left: 1ex;"><div style="word-wrap: break-word;" class=""><br class=""><div class=""><span class=""><blockquote type="cite" class=""><div class="">On Oct 3, 2014, at 14:50, David Blaikie <<a href="mailto:dblaikie@gmail.com" target="_blank" class="">dblaikie@gmail.com</a>> wrote:</div><div class=""><div dir="ltr" class=""><div class="gmail_extra"><div class="gmail_quote">On Fri, Oct 3, 2014 at 12:55 PM, Jared Grubb<span class="Apple-converted-space"> </span><span dir="ltr" class=""><<a href="mailto:jared.grubb@gmail.com" target="_blank" class="">jared.grubb@gmail.com</a>></span><span class="Apple-converted-space"> </span>wrote:<br class=""><blockquote class="gmail_quote" style="margin: 0px 0px 0px 0.8ex; border-left-width: 1px; border-left-color: rgb(204, 204, 204); border-left-style: solid; padding-left: 1ex;"><div style="word-wrap: break-word;" class=""><div class="">I spoke with Marshall briefly about this at CppCon. My suggestion is that std::function should either:</div><div class=""> * correctly capture blocks and just work (as this patch does)</div><div class=""> * compile with error if you try it (and also maybe add a convenience adaptor like you suggest to allow it to manually work)</div><div class=""><br class=""></div><div class="">The current problem is that if you write something like this:</div><div class="">   template <typename F> doSomething(F&& functor) { std::function<...> capturing = std::forward<F>(functor); ... }</div><div class="">This works great for lambdas. For blocks, it compiles just fine but has runtime issues.</div></div></blockquote><div class=""><br class=""></div><div class="">What runtime issues are you referring to? Could you provide a simple standalone complete example?</div></div></div></div></div></blockquote><div class=""><br class=""></div></span><div class=""><div class=""><div class=""><div class="">Here's an example.</div><div class=""><br class=""></div></div></div><blockquote style="margin: 0px 0px 0px 40px; border: none; padding: 0px;" class=""><div class=""><div class=""><div class=""><div class=""><div class=""><div class=""><div class="">int main(int argc, const char**) {</div><div class="">   <span class="Apple-converted-space"> </span>std::function<void()> f;</div><div class=""><br class=""></div><div class=""><div class="">   <span class="Apple-converted-space"> </span>std::vector<int> vec = {1, 2, 3};</div><div class="">   <span class="Apple-converted-space"> </span>if (argc == 1) {</div><div class="">       <span class="Apple-converted-space"> </span>f = ^{ std::cout << vec.size() << " (block)\n"; };</div><div class="">   <span class="Apple-converted-space"> </span>} else {</div><div class="">       <span class="Apple-converted-space"> </span>f = [=]{ std::cout << vec.size() << " (lambda)\n"; };</div><div class="">   <span class="Apple-converted-space"> </span>}</div><div class=""><br class=""></div></div><div class="">   <span class="Apple-converted-space"> </span>f();</div><div class="">}</div><div class=""><br class=""></div></div></div></div></div></div></div></blockquote><div class="">On my machine, it doesnt crash, but the block part is definitely broken:</div></div></div></div></blockquote><div class=""><br class=""></div><div class="">Fair enough.</div><div class=""> </div><blockquote class="gmail_quote" style="margin: 0px 0px 0px 0.8ex; border-left-width: 1px; border-left-color: rgb(204, 204, 204); border-left-style: solid; padding-left: 1ex;"><div style="word-wrap: break-word;" class=""><div class=""><div class=""><div class="">$ ./a.out</div><div class=""><div class="">0 (block)</div><div class="">$ ./a.out 1</div><div class="">3 (lambda)</div><div class=""><br class=""></div><div class="">Other examples, especially multithreaded ones, will crash and behave in undefined ways.</div></div></div></div></div></blockquote><div class=""><br class=""></div><div class="">Hmm - which kind of multithreading do you have in mind? I'm not sure why that'd be a particular problem.</div></div></div></blockquote><div><br class=""></div><div>Most of my uses of blocks are in multi-threading cases, where we throw blocks across threads (or dispatch_queues in OSX). Capturing blocks on one thread stack and running them on another stack exacerbates the core problem of "bad pointer to stack".</div><br class=""><blockquote type="cite" class=""><div class="gmail_quote" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><blockquote class="gmail_quote" style="margin: 0px 0px 0px 0.8ex; border-left-width: 1px; border-left-color: rgb(204, 204, 204); border-left-style: solid; padding-left: 1ex;"><div style="word-wrap: break-word;" class=""><div class=""><div class=""><div class=""><span class=""><blockquote type="cite" class=""><div dir="ltr" class=""><div class="gmail_extra"><div class="gmail_quote"><div class="">I assume the issue is that std::function will capture the block's (presumably raw) pointer by value but do none of the increment/decrement.</div></div></div></div></blockquote><div class=""><br class=""></div></span><div class="">Yes.</div></div></div></div></div></blockquote><div class=""><br class=""></div><div class="">Would it be possible/reasonable to warn/error on copying the raw block pointer? (passing it to any function at all) std::function isn't the only entity that could cause this kind of dangling block pointer bug & it might be nicer to fix it in the language for all such cases, than fix one (albeit common/easily triggered) case in the library?<br class=""><br class="">I assume I could write the same bug with something like:<br class=""><br class="">T *t; // not sure what 'T' is, but I imagine it's writeable?<br class="">if (x) {<br class="">  t = ^{ std::cout << vec.size() << " (block)\n"; };<br class="">}<br class="">t(); </div></div></blockquote><div><br class=""></div><div>You make a great point here, and I think such a warning would be amazing. Block assignments that span different scopes have problems for all the reasons we're describing.</div><div><br class=""></div><div>But I think that warning is orthogonal to this patch. Another example that I'm hoping to solve with this patch is something like this, where 'callback' is a std::function:</div><div><br class=""></div><div>template <typename F></div><div>void Foo::setCallback(F&& functor) {</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>this->callback = std::forward<F>(functor);</div><div>}</div><div><br class=""></div><div>Without this patch, you need to either overload for blocks, or use some sort of "make_function" helper that overloads on blocks.</div><div><br class=""></div><div>My goal with this patch is to just make std::function accept block types correctly; it already captures them, it just does it incorrectly.</div><br class=""><blockquote type="cite" class=""><div class=""><div class="gmail_quote" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><blockquote class="gmail_quote" style="margin: 0px 0px 0px 0.8ex; border-left-width: 1px; border-left-color: rgb(204, 204, 204); border-left-style: solid; padding-left: 1ex;"><div style="word-wrap: break-word;" class=""><div class=""><div class=""><div class=""><span class=""><br class=""><blockquote type="cite" class=""><div dir="ltr" class=""><div class="gmail_extra"><div class="gmail_quote"><div class="">This doesn't seem necessarily broken & I'm not sure (for myself) it merits library support to protect.</div></div></div></div></blockquote><blockquote type="cite" class=""><div dir="ltr" class=""><div class="gmail_extra"><div class="gmail_quote"><div class=""><br class="">This would be the same behavior as any other lifetime issues with pointer captures.<br class=""><br class=""> <span class="Apple-converted-space"> </span>std::function<...> func() {<br class="">   <span class="Apple-converted-space"> </span>int i;<br class="">   <span class="Apple-converted-space"> </span>int *j = &i;<br class="">   <span class="Apple-converted-space"> </span>return [=j] () { ... }; // captured j by value, but it points to something that goes out of scope at the end of the function. Bad.<br class=""> <span class="Apple-converted-space"> </span>}<br class=""><br class="">But similar code isn't a problem at all:<br class=""><br class=""></div><div class=""> <span class="Apple-converted-space"> </span>void func(std::function<...>); // func calls the std::function, maybe copies it around, but doesn't copy it to global storage/anywhere that outlives the <br class=""> <span class="Apple-converted-space"> </span>...<br class=""> <span class="Apple-converted-space"> </span>int i;<br class=""> <span class="Apple-converted-space"> </span>int *j = &i;<br class=""> <span class="Apple-converted-space"> </span>func([=j]() { ... });<br class=""></div></div></div></div></blockquote><div class=""><br class=""></div></span><div class="">You're right that it's the same "bad pointer to stack" issue, but the problem is at a different level. In the example above, the closures themselves are perfectly fine. The problem is that std::function captures the closure incorrectly. That's why I think it's a library issue.</div><span class=""><font color="#888888" class=""><div class=""><br class=""></div><div class="">Jared</div></font></span></div></div></div></div></blockquote></div></div></blockquote></div><br class=""></body></html>