{"action":"created","issue":{"url":"https://api.github.com/repos/tangrams/tangram-es/issues/709","repository_url":"https://api.github.com/repos/tangrams/tangram-es","labels_url":"https://api.github.com/repos/tangrams/tangram-es/issues/709/labels{/name}","comments_url":"https://api.github.com/repos/tangrams/tangram-es/issues/709/comments","events_url":"https://api.github.com/repos/tangrams/tangram-es/issues/709/events","html_url":"https://github.com/tangrams/tangram-es/pull/709","id":151739387,"number":709,"title":"Fix tile manager crash on app exit","user":{"login":"karimnaaji","id":7061573,"avatar_url":"https://avatars.githubusercontent.com/u/7061573?v=3","gravatar_id":"","url":"https://api.github.com/users/karimnaaji","html_url":"https://github.com/karimnaaji","followers_url":"https://api.github.com/users/karimnaaji/followers","following_url":"https://api.github.com/users/karimnaaji/following{/other_user}","gists_url":"https://api.github.com/users/karimnaaji/gists{/gist_id}","starred_url":"https://api.github.com/users/karimnaaji/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/karimnaaji/subscriptions","organizations_url":"https://api.github.com/users/karimnaaji/orgs","repos_url":"https://api.github.com/users/karimnaaji/repos","events_url":"https://api.github.com/users/karimnaaji/events{/privacy}","received_events_url":"https://api.github.com/users/karimnaaji/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/tangrams/tangram-es/labels/bug","name":"bug","color":"fc2929"},{"url":"https://api.github.com/repos/tangrams/tangram-es/labels/ready%20for%20review","name":"ready for review","color":"0052cc"}],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":2,"created_at":"2016-04-28T20:46:52Z","updated_at":"2016-04-29T11:27:24Z","closed_at":null,"pull_request":{"url":"https://api.github.com/repos/tangrams/tangram-es/pulls/709","html_url":"https://github.com/tangrams/tangram-es/pull/709","diff_url":"https://github.com/tangrams/tangram-es/pull/709.diff","patch_url":"https://github.com/tangrams/tangram-es/pull/709.patch"},"body":"Storing the workers as reference within the Tile Manager is not entirely safe when the workers get deleted in the following scenario:\r\n- Data source runs a network request\r\n- App exits\r\n- Tile worker gets dereferenced from main thread and deallocated\r\n- Data source callback gets invoked, and tries to enqueue on null reference worker\r\n\r\nA solution to fix this is to store the tile worker as a pointer, and test its validity before enqueue the worker task when the callback gets invoked.\r\n\r\nBacktrace of crash (not main thread):\r\n```\r\n(lldb) bt\r\n* thread #2: tid = 0x3d65a4, 0x00000001002a8ad8 tangram`Tangram::TileManager::TileManager(this=0x0000700000199808, task=std::__1::shared_ptr<Tangram::TileTask>::element_type @ 0x00006000000eb618 strong=1 weak=1)::$_0::operator()(std::__1::shared_ptr<Tangram::TileTask>&&) const + 72 at tileManager.cpp:23, queue = 'NSOperationQueue 0x60000003c1c0 :: NSOperation 0x6100000438a0 (QOS: LEGACY)', stop reason = EXC_BAD_ACCESS (code=EXC_I386_GPFLT)\r\n  * frame #0: 0x00000001002a8ad8 tangram`Tangram::TileManager::TileManager(this=0x0000700000199808, task=std::__1::shared_ptr<Tangram::TileTask>::element_type @ 0x00006000000eb618 strong=1 weak=1)::$_0::operator()(std::__1::shared_ptr<Tangram::TileTask>&&) const + 72 at tileManager.cpp:23\r\n    frame #1: 0x00000001002a8a7d tangram`_ZNSt3__128__invoke_void_return_wrapperIvE6__callIJRZN7Tangram11TileManagerC1ERNS3_13TileTaskQueueEE3$_0NS_10shared_ptrINS3_8TileTaskEEEEEEvDpOT_ [inlined] std::__1::__invoke<Tangram::TileManager::TileManager(Tangram::TileTaskQueue&)::$_0&, std::__1::shared_ptr<Tangram::TileTask> >(__f=0x0000700000199808, __args=std::__1::shared_ptr<Tangram::TileTask>::element_type @ 0x00006000000eb618 strong=1 weak=1)::$_0&>(fp)(std::__1::forward<std::__1::shared_ptr<Tangram::TileTask> >(fp0))), Tangram::TileManager::TileManager(Tangram::TileTaskQueue&)::$_0&&&, std::__1::shared_ptr<Tangram::TileTask>&&) + 77 at __functional_base:415\r\n    frame #2: 0x00000001002a8a60 tangram`_ZNSt3__128__invoke_void_return_wrapperIvE6__callIJRZN7Tangram11TileManagerC1ERNS3_13TileTaskQueueEE3$_0NS_10shared_ptrINS3_8TileTaskEEEEEEvDpOT_(__args=0x0000700000199808, __args=std::__1::shared_ptr<Tangram::TileTask>::element_type @ 0x00006000000eb618 strong=1 weak=1) + 48 at __functional_base:440\r\n    frame #3: 0x00000001002a895c tangram`std::__1::__function::__func<Tangram::TileManager::TileManager(Tangram::TileTaskQueue&)::$_0, std::__1::allocator<Tangram::TileManager::TileManager(Tangram::TileTaskQueue&)::$_0>, void (std::__1::shared_ptr<Tangram::TileTask>&&)>::operator(this=0x0000700000199800, __arg=std::__1::shared_ptr<Tangram::TileTask>::element_type @ 0x00006000000eb618 strong=1 weak=1)(std::__1::shared_ptr<Tangram::TileTask>&&) + 60 at functional:1407\r\n    frame #4: 0x00000001000134f7 tangram`std::__1::function<void (std::__1::shared_ptr<Tangram::TileTask>&&)>::operator(this=0x0000700000199800, __arg=std::__1::shared_ptr<Tangram::TileTask>::element_type @ 0x00006000000eb618 strong=1 weak=1)(std::__1::shared_ptr<Tangram::TileTask>&&) const + 151 at functional:1793\r\n    frame #5: 0x000000010002c076 tangram`Tangram::DataSource::onTileLoaded(this=0x00006000000a0840, _rawData=size=0, _task=std::__1::shared_ptr<Tangram::TileTask>::element_type @ 0x00006000000eb618 strong=1 weak=1, _cb=TileTaskCb @ 0x0000700000199800) + 662 at dataSource.cpp:145\r\n    frame #6: 0x0000000100036e7e tangram`void std::__1::__invoke_void_return_wrapper<void>::__call<std::__1::__bind<void (Tangram::DataSource::*)(std::__1::vector<char, std::__1::allocator<char> >&&, std::__1::shared_ptr<Tangram::TileTask>&, Tangram::TileTaskCb), Tangram::DataSource*, std::__1::placeholders::__ph<1>&, std::__1::shared_ptr<Tangram::TileTask>, Tangram::TileTaskCb&>&, std::__1::vector<char, std::__1::allocator<char> > >(std::__1::__bind<void (Tangram::DataSource::*)(std::__1::vector<char, std::__1::allocator<char> >&&, std::__1::shared_ptr<Tangram::TileTask>&, Tangram::TileTaskCb), Tangram::DataSource*, std::__1::placeholders::__ph<1>&, std::__1::shared_ptr<Tangram::TileTask>, Tangram::TileTaskCb&>&&&, std::__1::vector<char, std::__1::allocator<char> >&&) [inlined] decltype(__f=0x00006000000c1b30, __a0=0x00006000000c1b40, __args=size=0, __args=std::__1::shared_ptr<Tangram::TileTask>::element_type @ 0x00006000000eb618 strong=1 weak=1, __args=0x00006000000c1b60)).*fp(std::__1::forward<std::__1::vector<char, std::__1::allocator<char> >, std::__1::shared_ptr<Tangram::TileTask>&, Tangram::TileTaskCb&>(fp1))) std::__1::__invoke<void (Tangram::DataSource::*&)(std::__1::vector<char, std::__1::allocator<char> >&&, std::__1::shared_ptr<Tangram::TileTask>&, Tangram::TileTaskCb), Tangram::DataSource*&, std::__1::vector<char, std::__1::allocator<char> >, std::__1::shared_ptr<Tangram::TileTask>&, Tangram::TileTaskCb&, void>(void (Tangram::DataSource::*&&&)(std::__1::vector<char, std::__1::allocator<char> >&&, std::__1::shared_ptr<Tangram::TileTask>&, Tangram::TileTaskCb), Tangram::DataSource*&&&, std::__1::vector<char, std::__1::allocator<char> >&&, std::__1::shared_ptr<Tangram::TileTask>&&&, Tangram::TileTaskCb&&&) + 253 at __functional_base:382\r\n    frame #7: 0x0000000100036d81 tangram`void std::__1::__invoke_void_return_wrapper<void>::__call<std::__1::__bind<void (Tangram::DataSource::*)(std::__1::vector<char, std::__1::allocator<char> >&&, std::__1::shared_ptr<Tangram::TileTask>&, Tangram::TileTaskCb), Tangram::DataSource*, std::__1::placeholders::__ph<1>&, std::__1::shared_ptr<Tangram::TileTask>, Tangram::TileTaskCb&>&, std::__1::vector<char, std::__1::allocator<char> > >(std::__1::__bind<void (Tangram::DataSource::*)(std::__1::vector<char, std::__1::allocator<char> >&&, std::__1::shared_ptr<Tangram::TileTask>&, Tangram::TileTaskCb), Tangram::DataSource*, std::__1::placeholders::__ph<1>&, std::__1::shared_ptr<Tangram::TileTask>, Tangram::TileTaskCb&>&&&, std::__1::vector<char, std::__1::allocator<char> >&&) [inlined] std::__1::__bind_return<void (Tangram::DataSource::*)(std::__1::vector<char, std::__1::allocator<char> >&&, std::__1::shared_ptr<Tangram::TileTask>&, Tangram::TileTaskCb), std::__1::tuple<Tangram::DataSource*, std::__1::placeholders::__ph<1>, std::__1::shared_ptr<Tangram::TileTask>, Tangram::TileTaskCb>, std::__1::tuple<std::__1::vector<char, std::__1::allocator<char> >&&>, _is_valid_bind_return<void (Tangram::DataSource::*)(std::__1::vector<char, std::__1::allocator<char> >&&, std::__1::shared_ptr<Tangram::TileTask>&, Tangram::TileTaskCb), std::__1::tuple<Tangram::DataSource*, std::__1::placeholders::__ph<1>, std::__1::shared_ptr<Tangram::TileTask>, Tangram::TileTaskCb>, std::__1::tuple<std::__1::vector<char, std::__1::allocator<char> >&&> >::value>::type std::__1::__apply_functor<void (__f=0x00006000000c1b30, __bound_args=0x00006000000c1b40, (null)=__tuple_indices<0, 1, 2, 3> @ 0x0000700000199628, __args=0x00007000001995e8)(std::__1::vector<char, std::__1::allocator<char> >&&, std::__1::shared_ptr<Tangram::TileTask>&, Tangram::TileTaskCb), std::__1::tuple<Tangram::DataSource*, std::__1::placeholders::__ph<1>, std::__1::shared_ptr<Tangram::TileTask>, Tangram::TileTaskCb>, 0ul, 1ul, 2ul, 3ul, std::__1::tuple<std::__1::vector<char, std::__1::allocator<char> >&&> >(void (Tangram::DataSource::*&)(std::__1::vector<char, std::__1::allocator<char> >&&, std::__1::shared_ptr<Tangram::TileTask>&, Tangram::TileTaskCb), std::__1::tuple<Tangram::DataSource*, std::__1::placeholders::__ph<1>, std::__1::shared_ptr<Tangram::TileTask>, Tangram::TileTaskCb>&, std::__1::__tuple_indices<0ul, 1ul, 2ul, 3ul>, std::__1::tuple<std::__1::vector<char, std::__1::allocator<char> >&&>&&) + 281 at functional:2060\r\n    frame #8: 0x0000000100036c68 tangram`void std::__1::__invoke_void_return_wrapper<void>::__call<std::__1::__bind<void (Tangram::DataSource::*)(std::__1::vector<char, std::__1::allocator<char> >&&, std::__1::shared_ptr<Tangram::TileTask>&, Tangram::TileTaskCb), Tangram::DataSource*, std::__1::placeholders::__ph<1>&, std::__1::shared_ptr<Tangram::TileTask>, Tangram::TileTaskCb&>&, std::__1::vector<char, std::__1::allocator<char> > >(std::__1::__bind<void (Tangram::DataSource::*)(std::__1::vector<char, std::__1::allocator<char> >&&, std::__1::shared_ptr<Tangram::TileTask>&, Tangram::TileTaskCb), Tangram::DataSource*, std::__1::placeholders::__ph<1>&, std::__1::shared_ptr<Tangram::TileTask>, Tangram::TileTaskCb&>&&&, std::__1::vector<char, std::__1::allocator<char> >&&) [inlined] std::__1::__bind_return<void (Tangram::DataSource::*)(std::__1::vector<char, std::__1::allocator<char> >&&, std::__1::shared_ptr<Tangram::TileTask>&, Tangram::TileTaskCb), std::__1::tuple<Tangram::DataSource*, std::__1::placeholders::__ph<1>, std::__1::shared_ptr<Tangram::TileTask>, Tangram::TileTaskCb>, std::__1::tuple<std::__1::vector<char, std::__1::allocator<char> >&&>, _is_valid_bind_return<void (Tangram::DataSource::*)(std::__1::vector<char, std::__1::allocator<char> >&&, std::__1::shared_ptr<Tangram::TileTask>&, Tangram::TileTaskCb), std::__1::tuple<Tangram::DataSource*, std::__1::placeholders::__ph<1>, std::__1::shared_ptr<Tangram::TileTask>, Tangram::TileTaskCb>, std::__1::tuple<std::__1::vector<char, std::__1::allocator<char> >&&> >::value>::type std::__1::__bind<void (this=0x00006000000c1b30, __args=size=0)(std::__1::vector<char, std::__1::allocator<char> >&&, std::__1::shared_ptr<Tangram::TileTask>&, Tangram::TileTaskCb), Tangram::DataSource*, std::__1::placeholders::__ph<1>&, std::__1::shared_ptr<Tangram::TileTask>, Tangram::TileTaskCb&>::operator()<std::__1::vector<char, std::__1::allocator<char> > >(std::__1::vector<char, std::__1::allocator<char> >&&) + 156 at functional:2123\r\n    frame #9: 0x0000000100036bcc tangram`void std::__1::__invoke_void_return_wrapper<void>::__call<std::__1::__bind<void (Tangram::DataSource::*)(std::__1::vector<char, std::__1::allocator<char> >&&, std::__1::shared_ptr<Tangram::TileTask>&, Tangram::TileTaskCb), Tangram::DataSource*, std::__1::placeholders::__ph<1>&, std::__1::shared_ptr<Tangram::TileTask>, Tangram::TileTaskCb&>&, std::__1::vector<char, std::__1::allocator<char> > >(std::__1::__bind<void (Tangram::DataSource::*)(std::__1::vector<char, std::__1::allocator<char> >&&, std::__1::shared_ptr<Tangram::TileTask>&, Tangram::TileTaskCb), Tangram::DataSource*, std::__1::placeholders::__ph<1>&, std::__1::shared_ptr<Tangram::TileTask>, Tangram::TileTaskCb&>&&&, std::__1::vector<char, std::__1::allocator<char> >&&) [inlined] decltype(__f=0x00006000000c1b30, __args=size=0)(std::__1::vector<char, std::__1::allocator<char> >&&, std::__1::shared_ptr<Tangram::TileTask>&, Tangram::TileTaskCb), Tangram::DataSource*, std::__1::placeholders::__ph<1>&, std::__1::shared_ptr<Tangram::TileTask>, Tangram::TileTaskCb&>&>(fp)(std::__1::forward<std::__1::vector<char, std::__1::allocator<char> > >(fp0))) std::__1::__invoke<std::__1::__bind<void (Tangram::DataSource::*)(std::__1::vector<char, std::__1::allocator<char> >&&, std::__1::shared_ptr<Tangram::TileTask>&, Tangram::TileTaskCb), Tangram::DataSource*, std::__1::placeholders::__ph<1>&, std::__1::shared_ptr<Tangram::TileTask>, Tangram::TileTaskCb&>&, std::__1::vector<char, std::__1::allocator<char> > >(std::__1::__bind<void (Tangram::DataSource::*)(std::__1::vector<char, std::__1::allocator<char> >&&, std::__1::shared_ptr<Tangram::TileTask>&, Tangram::TileTaskCb), Tangram::DataSource*, std::__1::placeholders::__ph<1>&, std::__1::shared_ptr<Tangram::TileTask>, Tangram::TileTaskCb&>&&&, std::__1::vector<char, std::__1::allocator<char> >&&) + 46 at __functional_base:415\r\n    frame #10: 0x0000000100036b9e tangram`void std::__1::__invoke_void_return_wrapper<void>::__call<std::__1::__bind<void (__args=0x00006000000c1b30, __args=size=0)(std::__1::vector<char, std::__1::allocator<char> >&&, std::__1::shared_ptr<Tangram::TileTask>&, Tangram::TileTaskCb), Tangram::DataSource*, std::__1::placeholders::__ph<1>&, std::__1::shared_ptr<Tangram::TileTask>, Tangram::TileTaskCb&>&, std::__1::vector<char, std::__1::allocator<char> > >(std::__1::__bind<void (Tangram::DataSource::*)(std::__1::vector<char, std::__1::allocator<char> >&&, std::__1::shared_ptr<Tangram::TileTask>&, Tangram::TileTaskCb), Tangram::DataSource*, std::__1::placeholders::__ph<1>&, std::__1::shared_ptr<Tangram::TileTask>, Tangram::TileTaskCb&>&&&, std::__1::vector<char, std::__1::allocator<char> >&&) + 78 at __functional_base:440\r\n    frame #11: 0x00000001000363fc tangram`std::__1::__function::__func<std::__1::__bind<void (Tangram::DataSource::*)(std::__1::vector<char, std::__1::allocator<char> >&&, std::__1::shared_ptr<Tangram::TileTask>&, Tangram::TileTaskCb), Tangram::DataSource*, std::__1::placeholders::__ph<1>&, std::__1::shared_ptr<Tangram::TileTask>, Tangram::TileTaskCb&>, std::__1::allocator<std::__1::__bind<void (Tangram::DataSource::*)(std::__1::vector<char, std::__1::allocator<char> >&&, std::__1::shared_ptr<Tangram::TileTask>&, Tangram::TileTaskCb), Tangram::DataSource*, std::__1::placeholders::__ph<1>&, std::__1::shared_ptr<Tangram::TileTask>, Tangram::TileTaskCb&> >, void (std::__1::vector<char, std::__1::allocator<char> >&&)>::operator(this=0x00006000000c1b20, __arg=size=0)(std::__1::vector<char, std::__1::allocator<char> >&&) + 60 at functional:1407\r\n    frame #12: 0x000000010000b437 tangram`std::__1::function<void (std::__1::vector<char, std::__1::allocator<char> >&&)>::operator(this=0x000060000009a010, __arg=size=0)(std::__1::vector<char, std::__1::allocator<char> >&&) const + 151 at functional:1793\r\n    frame #13: 0x000000010000ac53 tangram`___Z15startUrlRequestRKNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEENS_8functionIFvONS_6vectorIcS4_EEEEE_block_invoke(.block_descriptor=<unavailable>, data=100060 bytes, response=0x00006000002201e0, error=0x0000000000000000) + 371 at platform_osx.mm:145\r\n    frame #14: 0x00007fff95bf4dd1 CFNetwork`__75-[__NSURLSessionLocal taskForClass:request:uploadFile:bodyData:completion:]_block_invoke + 21\r\n    frame #15: 0x00007fff95bf469f CFNetwork`__49-[__NSCFLocalSessionTask _task_onqueue_didFinish]_block_invoke + 302\r\n    frame #16: 0x00007fff884a129c Foundation`__NSBLOCKOPERATION_IS_CALLING_OUT_TO_A_BLOCK__ + 7\r\n    frame #17: 0x00007fff884a100c Foundation`-[NSBlockOperation main] + 100\r\n    frame #18: 0x00007fff884a02fb Foundation`-[__NSOperationInternal _start:] + 654\r\n    frame #19: 0x00007fff8849fde7 Foundation`__NSOQSchedule_f + 194\r\n    frame #20: 0x0000000100a90bf9 libdispatch.dylib`_dispatch_client_callout + 8\r\n    frame #21: 0x0000000100a96046 libdispatch.dylib`_dispatch_queue_drain + 351\r\n    frame #22: 0x0000000100a9dd58 libdispatch.dylib`_dispatch_queue_invoke + 557\r\n    frame #23: 0x0000000100a94cdf libdispatch.dylib`_dispatch_root_queue_drain + 1226\r\n    frame #24: 0x0000000100a947d9 libdispatch.dylib`_dispatch_worker_thread3 + 106\r\n    frame #25: 0x0000000100af3458 libsystem_pthread.dylib`_pthread_wqthread + 1129\r\n    frame #26: 0x0000000100af0fad libsystem_pthread.dylib`start_wqthread + 13\r\n```"},"comment":{"url":"https://api.github.com/repos/tangrams/tangram-es/issues/comments/215688361","html_url":"https://github.com/tangrams/tangram-es/pull/709#issuecomment-215688361","issue_url":"https://api.github.com/repos/tangrams/tangram-es/issues/709","id":215688361,"user":{"login":"hjanetzek","id":1747,"avatar_url":"https://avatars.githubusercontent.com/u/1747?v=3","gravatar_id":"","url":"https://api.github.com/users/hjanetzek","html_url":"https://github.com/hjanetzek","followers_url":"https://api.github.com/users/hjanetzek/followers","following_url":"https://api.github.com/users/hjanetzek/following{/other_user}","gists_url":"https://api.github.com/users/hjanetzek/gists{/gist_id}","starred_url":"https://api.github.com/users/hjanetzek/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/hjanetzek/subscriptions","organizations_url":"https://api.github.com/users/hjanetzek/orgs","repos_url":"https://api.github.com/users/hjanetzek/repos","events_url":"https://api.github.com/users/hjanetzek/events{/privacy}","received_events_url":"https://api.github.com/users/hjanetzek/received_events","type":"User","site_admin":false},"created_at":"2016-04-29T11:27:24Z","updated_at":"2016-04-29T11:27:24Z","body":"What if the DataSource download callback comes after the TileManager got destructed? One needs to make sure that the download threads are shut down before the tangram.cpp instances get destructed. (This is done for the linux application)\r\n"}}