Skip to content
This repository has been archived by the owner on Aug 8, 2023. It is now read-only.

Transition loop and eventual crash at flyTo #5833

Closed
friedbunny opened this issue Jul 29, 2016 · 14 comments
Closed

Transition loop and eventual crash at flyTo #5833

friedbunny opened this issue Jul 29, 2016 · 14 comments
Labels
crash iOS Mapbox Maps SDK for iOS navigation For the Mapbox Navigation SDK for Android or iOS or navigation use cases in general

Comments

@friedbunny
Copy link
Contributor

Mapbox SDK version: iOS v3.3.3 (release branch)

This is fairly silly, but @1ec5 suggested I post it because it represents 1. a crash that should not happen (regardless), and 2. this issue may be illustrative of a larger async/sync animation problem that exists in core.

Steps to trigger behavior

Try to reset the map to north when also using MGLUserTrackingModeFollowWithCourse.

- (void)mapView:(MGLMapView *)mapView regionDidChangeAnimated:(BOOL)animated;
{
    if (mapView.userTrackingMode != MGLUserTrackingModeFollowWithHeading && mapView.direction != 0.0)
    {
        [mapView resetNorth];
    }
}

Expected behavior

The map direction should oscillate between north and the current course.

Actual behavior

-[MGLMapView resetNorth] triggers a loop, wherein _setDirection:animated: calls Map::cancelTransitions() before starting to a new transition (to north). Eventually this finishes (after 70k steps) and _flyToCamera is called... which crashes:

#0  0x000000010ff385d1 in gcd_queue_item_enqueue_hook ()
#1  0x0000000114400bba in _dispatch_introspection_queue_item_enqueue_hook ()
#2  0x00000001143e8046 in _dispatch_barrier_async_f_slow ()
#3  0x000000010ffb6fcd in -[MGLMapView _flyToCamera:edgePadding:withDuration:peakAltitude:completionHandler:]::$_3::operator()() const at /mapbox-gl-native/platform/ios/src/MGLMapView.mm:2503
#4  0x000000010ffb6f2d in decltype(std::__1::forward<-[MGLMapView _flyToCamera:edgePadding:withDuration:peakAltitude:completionHandler:]::$_3&>(fp)(std::__1::forward<>(fp0))) std::__1::__invoke<-[MGLMapView _flyToCamera:edgePadding:withDuration:peakAltitude:completionHandler:]::$_3&>(-[MGLMapView _flyToCamera:edgePadding:withDuration:peakAltitude:completionHandler:]::$_3&&&) [inlined] at /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/__functional_base:416
#5  0x000000010ffb6f1c in void std::__1::__invoke_void_return_wrapper<void>::__call<-[MGLMapView _flyToCamera:edgePadding:withDuration:peakAltitude:completionHandler:]::$_3&>(-[MGLMapView _flyToCamera:edgePadding:withDuration:peakAltitude:completionHandler:]::$_3&&&) at /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/__functional_base:468
#6  0x000000010ffb6d59 in std::__1::__function::__func<-[MGLMapView _flyToCamera:edgePadding:withDuration:peakAltitude:completionHandler:]::$_3, std::__1::allocator<-[MGLMapView _flyToCamera:edgePadding:withDuration:peakAltitude:completionHandler:]::$_3>, void ()>::operator()() at /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/functional:1437
#7  0x000000011047f32c in std::__1::function<void ()>::operator()() const at /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/functional:1817
#8  0x000000011014bbb0 in mbgl::Transform::startTransition(mbgl::CameraOptions const&, mbgl::AnimationOptions const&, std::__1::function<mbgl::Update (double)>, std::__1::chrono::duration<long long, std::__1::ratio<1l, 1000000000l> > const&)::$_4::operator()() const at /mapbox-gl-native/src/mbgl/map/transform.cpp:617
#9  0x000000011014bb1b in decltype(std::__1::forward<mbgl::Transform::startTransition(mbgl::CameraOptions const&, mbgl::AnimationOptions const&, std::__1::function<mbgl::Update (double)>, std::__1::chrono::duration<long long, std::__1::ratio<1l, 1000000000l> > const&)::$_4&>(fp)(std::__1::forward<>(fp0))) std::__1::__invoke<mbgl::Transform::startTransition(mbgl::CameraOptions const&, mbgl::AnimationOptions const&, std::__1::function<mbgl::Update (double)>, std::__1::chrono::duration<long long, std::__1::ratio<1l, 1000000000l> > const&)::$_4&>(mbgl::Transform::startTransition(mbgl::CameraOptions const&, mbgl::AnimationOptions const&, std::__1::function<mbgl::Update (double)>, std::__1::chrono::duration<long long, std::__1::ratio<1l, 1000000000l> > const&)::$_4&&&) [inlined] at /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/__functional_base:416
#10 0x000000011014bb0a in void std::__1::__invoke_void_return_wrapper<void>::__call<mbgl::Transform::startTransition(mbgl::CameraOptions const&, mbgl::AnimationOptions const&, std::__1::function<mbgl::Update (double)>, std::__1::chrono::duration<long long, std::__1::ratio<1l, 1000000000l> > const&)::$_4&>(mbgl::Transform::startTransition(mbgl::CameraOptions const&, mbgl::AnimationOptions const&, std::__1::function<mbgl::Update (double)>, std::__1::chrono::duration<long long, std::__1::ratio<1l, 1000000000l> > const&)::$_4&&&) at /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/__functional_base:468
#11 0x000000011014b787 in std::__1::__function::__func<mbgl::Transform::startTransition(mbgl::CameraOptions const&, mbgl::AnimationOptions const&, std::__1::function<mbgl::Update (double)>, std::__1::chrono::duration<long long, std::__1::ratio<1l, 1000000000l> > const&)::$_4, std::__1::allocator<mbgl::Transform::startTransition(mbgl::CameraOptions const&, mbgl::AnimationOptions const&, std::__1::function<mbgl::Update (double)>, std::__1::chrono::duration<long long, std::__1::ratio<1l, 1000000000l> > const&)::$_4>, void ()>::operator()() at /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/functional:1437
#12 0x000000011047f32c in std::__1::function<void ()>::operator()() const at /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/functional:1817
#13 0x00000001101439c1 in mbgl::Transform::cancelTransitions() at /mapbox-gl-native/src/mbgl/map/transform.cpp:639
#14 0x000000011012f136 in mbgl::Map::cancelTransitions() at /mapbox-gl-native/src/mbgl/map/map.cpp:355
#15 0x000000010ff8c393 in -[MGLMapView _setDirection:animated:] at /mapbox-gl-native/platform/ios/src/MGLMapView.mm:2378
#16 0x000000010ff8c2ee in -[MGLMapView setDirection:animated:] at /mapbox-gl-native/platform/ios/src/MGLMapView.mm:2372
#17 0x000000010ff866fd in -[MGLMapView resetNorthAnimated:] at /mapbox-gl-native/platform/ios/src/MGLMapView.mm:1875
#18 0x000000010ff866b0 in -[MGLMapView resetNorth] at /mapbox-gl-native/platform/ios/src/MGLMapView.mm:1870
#19 0x000000010feaa95f in -[MBXViewController mapView:regionDidChangeAnimated:] at /mapbox-gl-native/platform/ios/app/MBXViewController.m:77
#20 0x000000010ffa843f in -[MGLMapView notifyMapChange:] at /mapbox-gl-native/platform/ios/src/MGLMapView.mm:4467
#21 0x000000010ffbc2bd in MBGLView::notifyMapChange(mbgl::MapChange) at /mapbox-gl-native/platform/ios/src/MGLMapView.mm:4903
#22 0x0000000110136373 in mbgl::Map::Impl::Impl(mbgl::View&, mbgl::FileSource&, mbgl::MapMode, mbgl::GLContextMode, mbgl::ConstrainMode, mbgl::ViewportMode)::$_0::operator()(mbgl::MapChange) const at /mapbox-gl-native/src/mbgl/map/map.cpp:94
#23 0x000000011013630e in std::__1::__invoke<mbgl::Map::Impl::Impl(mbgl::View&, mbgl::FileSource&, mbgl::MapMode, mbgl::GLContextMode, mbgl::ConstrainMode, mbgl::ViewportMode)::$_0&, mbgl::MapChange>(decltype(std::__1::forward<mbgl::Map::Impl::Impl(mbgl::View&, mbgl::FileSource&, mbgl::MapMode, mbgl::GLContextMode, mbgl::ConstrainMode, mbgl::ViewportMode)::$_0&>(fp)(std::__1::forward<mbgl::MapChange>(fp0))), mbgl::Map::Impl::Impl(mbgl::View&, mbgl::FileSource&, mbgl::MapMode, mbgl::GLContextMode, mbgl::ConstrainMode, mbgl::ViewportMode)::$_0&&&, mbgl::MapChange&&) [inlined] at /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/__functional_base:416
#24 0x00000001101362ee in _ZNSt3__128__invoke_void_return_wrapperIvE6__callIJRZN4mbgl3Map4ImplC1ERNS3_4ViewERNS3_10FileSourceENS3_7MapModeENS3_13GLContextModeENS3_13ConstrainModeENS3_12ViewportModeEE3$_0NS3_9MapChangeEEEEvDpOT_ at /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/__functional_base:468
#25 0x0000000110136157 in std::__1::__function::__func<mbgl::Map::Impl::Impl(mbgl::View&, mbgl::FileSource&, mbgl::MapMode, mbgl::GLContextMode, mbgl::ConstrainMode, mbgl::ViewportMode)::$_0, std::__1::allocator<mbgl::Map::Impl::Impl(mbgl::View&, mbgl::FileSource&, mbgl::MapMode, mbgl::GLContextMode, mbgl::ConstrainMode, mbgl::ViewportMode)::$_0>, void (mbgl::MapChange)>::operator()(mbgl::MapChange&&) at /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/functional:1437
#26 0x000000011014bd1c in std::__1::function<void (mbgl::MapChange)>::operator()(mbgl::MapChange) const at /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/functional:1817
#27 0x000000011014bbf7 in mbgl::Transform::startTransition(mbgl::CameraOptions const&, mbgl::AnimationOptions const&, std::__1::function<mbgl::Update (double)>, std::__1::chrono::duration<long long, std::__1::ratio<1l, 1000000000l> > const&)::$_4::operator()() const at /mapbox-gl-native/src/mbgl/map/transform.cpp:620
#28 0x000000011014bb1b in decltype(std::__1::forward<mbgl::Transform::startTransition(mbgl::CameraOptions const&, mbgl::AnimationOptions const&, std::__1::function<mbgl::Update (double)>, std::__1::chrono::duration<long long, std::__1::ratio<1l, 1000000000l> > const&)::$_4&>(fp)(std::__1::forward<>(fp0))) std::__1::__invoke<mbgl::Transform::startTransition(mbgl::CameraOptions const&, mbgl::AnimationOptions const&, std::__1::function<mbgl::Update (double)>, std::__1::chrono::duration<long long, std::__1::ratio<1l, 1000000000l> > const&)::$_4&>(mbgl::Transform::startTransition(mbgl::CameraOptions const&, mbgl::AnimationOptions const&, std::__1::function<mbgl::Update (double)>, std::__1::chrono::duration<long long, std::__1::ratio<1l, 1000000000l> > const&)::$_4&&&) [inlined] at /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/__functional_base:416
#29 0x000000011014bb0a in void std::__1::__invoke_void_return_wrapper<void>::__call<mbgl::Transform::startTransition(mbgl::CameraOptions const&, mbgl::AnimationOptions const&, std::__1::function<mbgl::Update (double)>, std::__1::chrono::duration<long long, std::__1::ratio<1l, 1000000000l> > const&)::$_4&>(mbgl::Transform::startTransition(mbgl::CameraOptions const&, mbgl::AnimationOptions const&, std::__1::function<mbgl::Update (double)>, std::__1::chrono::duration<long long, std::__1::ratio<1l, 1000000000l> > const&)::$_4&&&) at /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/__functional_base:468
#30 0x000000011014b787 in std::__1::__function::__func<mbgl::Transform::startTransition(mbgl::CameraOptions const&, mbgl::AnimationOptions const&, std::__1::function<mbgl::Update (double)>, std::__1::chrono::duration<long long, std::__1::ratio<1l, 1000000000l> > const&)::$_4, std::__1::allocator<mbgl::Transform::startTransition(mbgl::CameraOptions const&, mbgl::AnimationOptions const&, std::__1::function<mbgl::Update (double)>, std::__1::chrono::duration<long long, std::__1::ratio<1l, 1000000000l> > const&)::$_4>, void ()>::operator()() at /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/functional:1437
#31 0x000000011047f32c in std::__1::function<void ()>::operator()() const at /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/functional:1817
#32 0x00000001101439c1 in mbgl::Transform::cancelTransitions() at /mapbox-gl-native/src/mbgl/map/transform.cpp:639
#33 0x000000011012f136 in mbgl::Map::cancelTransitions() at /mapbox-gl-native/src/mbgl/map/map.cpp:355
#34 0x000000010ff8c393 in -[MGLMapView _setDirection:animated:] at /mapbox-gl-native/platform/ios/src/MGLMapView.mm:2378
#35 0x000000010ff8c2ee in -[MGLMapView setDirection:animated:] at /mapbox-gl-native/platform/ios/src/MGLMapView.mm:2372
#36 0x000000010ff866fd in -[MGLMapView resetNorthAnimated:] at /mapbox-gl-native/platform/ios/src/MGLMapView.mm:1875
#37 0x000000010ff866b0 in -[MGLMapView resetNorth] at /mapbox-gl-native/platform/ios/src/MGLMapView.mm:1870
#38 0x000000010feaa95f in -[MBXViewController mapView:regionDidChangeAnimated:] at /mapbox-gl-native/platform/ios/app/MBXViewController.m:77
#39 0x000000010ffa843f in -[MGLMapView notifyMapChange:] at /mapbox-gl-native/platform/ios/src/MGLMapView.mm:4467
#40 0x000000010ffbc2bd in MBGLView::notifyMapChange(mbgl::MapChange) at /mapbox-gl-native/platform/ios/src/MGLMapView.mm:4903
#41 0x0000000110136373 in mbgl::Map::Impl::Impl(mbgl::View&, mbgl::FileSource&, mbgl::MapMode, mbgl::GLContextMode, mbgl::ConstrainMode, mbgl::ViewportMode)::$_0::operator()(mbgl::MapChange) const at /mapbox-gl-native/src/mbgl/map/map.cpp:94
...
#74673  0x0000000110136373 in mbgl::Map::Impl::Impl(mbgl::View&, mbgl::FileSource&, mbgl::MapMode, mbgl::GLContextMode, mbgl::ConstrainMode, mbgl::ViewportMode)::$_0::operator()(mbgl::MapChange) const at /mapbox-gl-native/src/mbgl/map/map.cpp:94
#74674  0x000000011013630e in std::__1::__invoke<mbgl::Map::Impl::Impl(mbgl::View&, mbgl::FileSource&, mbgl::MapMode, mbgl::GLContextMode, mbgl::ConstrainMode, mbgl::ViewportMode)::$_0&, mbgl::MapChange>(decltype(std::__1::forward<mbgl::Map::Impl::Impl(mbgl::View&, mbgl::FileSource&, mbgl::MapMode, mbgl::GLContextMode, mbgl::ConstrainMode, mbgl::ViewportMode)::$_0&>(fp)(std::__1::forward<mbgl::MapChange>(fp0))), mbgl::Map::Impl::Impl(mbgl::View&, mbgl::FileSource&, mbgl::MapMode, mbgl::GLContextMode, mbgl::ConstrainMode, mbgl::ViewportMode)::$_0&&&, mbgl::MapChange&&) [inlined] at /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/__functional_base:416
#74675  0x00000001101362ee in _ZNSt3__128__invoke_void_return_wrapperIvE6__callIJRZN4mbgl3Map4ImplC1ERNS3_4ViewERNS3_10FileSourceENS3_7MapModeENS3_13GLContextModeENS3_13ConstrainModeENS3_12ViewportModeEE3$_0NS3_9MapChangeEEEEvDpOT_ at /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/__functional_base:468
#74676  0x0000000110136157 in std::__1::__function::__func<mbgl::Map::Impl::Impl(mbgl::View&, mbgl::FileSource&, mbgl::MapMode, mbgl::GLContextMode, mbgl::ConstrainMode, mbgl::ViewportMode)::$_0, std::__1::allocator<mbgl::Map::Impl::Impl(mbgl::View&, mbgl::FileSource&, mbgl::MapMode, mbgl::GLContextMode, mbgl::ConstrainMode, mbgl::ViewportMode)::$_0>, void (mbgl::MapChange)>::operator()(mbgl::MapChange&&) at /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/functional:1437
#74677  0x000000011014bd1c in std::__1::function<void (mbgl::MapChange)>::operator()(mbgl::MapChange) const at /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/functional:1817
#74678  0x000000011014bbf7 in mbgl::Transform::startTransition(mbgl::CameraOptions const&, mbgl::AnimationOptions const&, std::__1::function<mbgl::Update (double)>, std::__1::chrono::duration<long long, std::__1::ratio<1l, 1000000000l> > const&)::$_4::operator()() const at /mapbox-gl-native/src/mbgl/map/transform.cpp:620
#74679  0x000000011014bb1b in decltype(std::__1::forward<mbgl::Transform::startTransition(mbgl::CameraOptions const&, mbgl::AnimationOptions const&, std::__1::function<mbgl::Update (double)>, std::__1::chrono::duration<long long, std::__1::ratio<1l, 1000000000l> > const&)::$_4&>(fp)(std::__1::forward<>(fp0))) std::__1::__invoke<mbgl::Transform::startTransition(mbgl::CameraOptions const&, mbgl::AnimationOptions const&, std::__1::function<mbgl::Update (double)>, std::__1::chrono::duration<long long, std::__1::ratio<1l, 1000000000l> > const&)::$_4&>(mbgl::Transform::startTransition(mbgl::CameraOptions const&, mbgl::AnimationOptions const&, std::__1::function<mbgl::Update (double)>, std::__1::chrono::duration<long long, std::__1::ratio<1l, 1000000000l> > const&)::$_4&&&) [inlined] at /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/__functional_base:416
#74680  0x000000011014bb0a in void std::__1::__invoke_void_return_wrapper<void>::__call<mbgl::Transform::startTransition(mbgl::CameraOptions const&, mbgl::AnimationOptions const&, std::__1::function<mbgl::Update (double)>, std::__1::chrono::duration<long long, std::__1::ratio<1l, 1000000000l> > const&)::$_4&>(mbgl::Transform::startTransition(mbgl::CameraOptions const&, mbgl::AnimationOptions const&, std::__1::function<mbgl::Update (double)>, std::__1::chrono::duration<long long, std::__1::ratio<1l, 1000000000l> > const&)::$_4&&&) at /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/__functional_base:468
#74681  0x000000011014b787 in std::__1::__function::__func<mbgl::Transform::startTransition(mbgl::CameraOptions const&, mbgl::AnimationOptions const&, std::__1::function<mbgl::Update (double)>, std::__1::chrono::duration<long long, std::__1::ratio<1l, 1000000000l> > const&)::$_4, std::__1::allocator<mbgl::Transform::startTransition(mbgl::CameraOptions const&, mbgl::AnimationOptions const&, std::__1::function<mbgl::Update (double)>, std::__1::chrono::duration<long long, std::__1::ratio<1l, 1000000000l> > const&)::$_4>, void ()>::operator()() at /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/functional:1437
#74682  0x000000011047f32c in std::__1::function<void ()>::operator()() const at /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/functional:1817
#74683  0x0000000110149f8c in mbgl::Transform::startTransition(mbgl::CameraOptions const&, mbgl::AnimationOptions const&, std::__1::function<mbgl::Update (double)>, std::__1::chrono::duration<long long, std::__1::ratio<1l, 1000000000l> > const&)::$_3::operator()(std::__1::chrono::time_point<std::__1::chrono::steady_clock, std::__1::chrono::duration<long long, std::__1::ratio<1l, 1000000000l> > >) const at /mapbox-gl-native/src/mbgl/map/transform.cpp:602
#74684  0x0000000110149656 in decltype(std::__1::forward<mbgl::Transform::startTransition(mbgl::CameraOptions const&, mbgl::AnimationOptions const&, std::__1::function<mbgl::Update (double)>, std::__1::chrono::duration<long long, std::__1::ratio<1l, 1000000000l> > const&)::$_3&>(fp)(std::__1::forward<std::__1::chrono::time_point<std::__1::chrono::steady_clock, std::__1::chrono::duration<long long, std::__1::ratio<1l, 1000000000l> > > >(fp0))) std::__1::__invoke<mbgl::Transform::startTransition(mbgl::CameraOptions const&, mbgl::AnimationOptions const&, std::__1::function<mbgl::Update (double)>, std::__1::chrono::duration<long long, std::__1::ratio<1l, 1000000000l> > const&)::$_3&, std::__1::chrono::time_point<std::__1::chrono::steady_clock, std::__1::chrono::duration<long long, std::__1::ratio<1l, 1000000000l> > > >(mbgl::Transform::startTransition(mbgl::CameraOptions const&, mbgl::AnimationOptions const&, std::__1::function<mbgl::Update (double)>, std::__1::chrono::duration<long long, std::__1::ratio<1l, 1000000000l> > const&)::$_3&&&, std::__1::chrono::time_point<std::__1::chrono::steady_clock, std::__1::chrono::duration<long long, std::__1::ratio<1l, 1000000000l> > >&&) [inlined] at /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/__functional_base:416
#74685  0x000000011014962e in mbgl::Update std::__1::__invoke_void_return_wrapper<mbgl::Update>::__call<mbgl::Transform::startTransition(mbgl::CameraOptions const&, mbgl::AnimationOptions const&, std::__1::function<mbgl::Update (double)>, std::__1::chrono::duration<long long, std::__1::ratio<1l, 1000000000l> > const&)::$_3&, std::__1::chrono::time_point<std::__1::chrono::steady_clock, std::__1::chrono::duration<long long, std::__1::ratio<1l, 1000000000l> > > >(mbgl::Transform::startTransition(mbgl::CameraOptions const&, mbgl::AnimationOptions const&, std::__1::function<mbgl::Update (double)>, std::__1::chrono::duration<long long, std::__1::ratio<1l, 1000000000l> > const&)::$_3&&&, std::__1::chrono::time_point<std::__1::chrono::steady_clock, std::__1::chrono::duration<long long, std::__1::ratio<1l, 1000000000l> > >&&) at /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/__functional_base:437
#74686  0x00000001101491b7 in std::__1::__function::__func<mbgl::Transform::startTransition(mbgl::CameraOptions const&, mbgl::AnimationOptions const&, std::__1::function<mbgl::Update (double)>, std::__1::chrono::duration<long long, std::__1::ratio<1l, 1000000000l> > const&)::$_3, std::__1::allocator<mbgl::Transform::startTransition(mbgl::CameraOptions const&, mbgl::AnimationOptions const&, std::__1::function<mbgl::Update (double)>, std::__1::chrono::duration<long long, std::__1::ratio<1l, 1000000000l> > const&)::$_3>, mbgl::Update (std::__1::chrono::time_point<std::__1::chrono::steady_clock, std::__1::chrono::duration<long long, std::__1::ratio<1l, 1000000000l> > >)>::operator()(std::__1::chrono::time_point<std::__1::chrono::steady_clock, std::__1::chrono::duration<long long, std::__1::ratio<1l, 1000000000l> > >&&) at /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/functional:1437
#74687  0x000000011014c2ba in std::__1::function<mbgl::Update (std::__1::chrono::time_point<std::__1::chrono::steady_clock, std::__1::chrono::duration<long long, std::__1::ratio<1l, 1000000000l> > >)>::operator()(std::__1::chrono::time_point<std::__1::chrono::steady_clock, std::__1::chrono::duration<long long, std::__1::ratio<1l, 1000000000l> > >) const at /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/functional:1817
#74688  0x0000000110143924 in mbgl::Transform::updateTransitions(std::__1::chrono::time_point<std::__1::chrono::steady_clock, std::__1::chrono::duration<long long, std::__1::ratio<1l, 1000000000l> > > const&) at /mapbox-gl-native/src/mbgl/map/transform.cpp:634
#74689  0x000000011012bb19 in mbgl::Map::render() at /mapbox-gl-native/src/mbgl/map/map.cpp:173
#74690  0x000000010ff794b4 in -[MGLMapView glkView:drawInRect:] at /mapbox-gl-native/platform/ios/src/MGLMapView.mm:857
#74691  0x0000000113b2691a in -[GLKView _display:] ()
#74692  0x000000010ff7a990 in -[MGLMapView updateFromDisplayLink] at /mapbox-gl-native/platform/ios/src/MGLMapView.mm:984
#74693  0x0000000112340bf4 in CA::Display::DisplayLinkItem::dispatch() ()
#74694  0x0000000112340abe in CA::Display::DisplayLink::dispatch_items(unsigned long long, unsigned long long, unsigned long long) ()
#74695  0x000000011167b074 in __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ ()
#74696  0x000000011167ac21 in __CFRunLoopDoTimer ()
#74697  0x000000011163cb11 in __CFRunLoopRun ()
#74698  0x000000011163c0f8 in CFRunLoopRunSpecific ()
#74699  0x000000011842fad2 in GSEventRunModal ()
#74700  0x0000000112464f09 in UIApplicationMain ()
#74701  0x000000010fea587f in main at /mapbox-gl-native/platform/ios/app/main.m:8
#74702  0x000000011443392d in start ()
@friedbunny friedbunny added iOS Mapbox Maps SDK for iOS crash labels Jul 29, 2016
@1ec5 1ec5 added this to the ios-v3.4.0 milestone Jul 29, 2016
@boundsj boundsj added the navigation For the Mapbox Navigation SDK for Android or iOS or navigation use cases in general label Aug 15, 2016
@1ec5
Copy link
Contributor

1ec5 commented Aug 17, 2016

The stack in #5833 (comment) strongly implicates -_setDirection:animated:, but -_flyToCamera:edgePadding:… appeared many times further down on the stack as well. (Do you still have the full stack trace saved off somewhere?) The pattern that emerged was contention between -resetNorthAnimated: and -_flyToCamera:…, likely triggered by a premature call to mbgl::Map::cancelTransitions() even before checking for camera equality. (-_setVisibleCoordinates:…, which we call for targeted course tracking, even lacks a no-op check.)

Here’s a possible scenario that I suspect may lead to a race condition and eventual crash:

  1. In targeted course tracking mode, -didUpdateLocationWithUserTrackingAnimated: calls -didUpdateLocationWithTargetAnimated:
  2. which calls -_setVisibleCoordinates:count:edgePadding:direction:duration:animationTimingFunction:completionHandler:
  3. which before setting up the animation calls mbgl::Map::cancelTransitions()
  4. which calls the previously queued mbgl::Transform::transitionFinishFn

Similarly:

  1. -didUpdateLocationWithTargetAnimated: subsequently calls -unrotateIfNeededAnimated:
  2. which calls -resetNorthAnimated: after a 100-millisecond delay
  3. which calls -_setDirection:animated:
  4. which, if the map is pointing in any direction other than north, again calls mbgl::Map::cancelTransitions()

The transitionFinishFn that -didUpdateLocationWithTargetAnimated: sets doesn’t do much, which explains why we don’t see things immediately grind to a halt as soon as you enter targeted course tracking mode. But transitionFinishFn is set by other MGLMapView methods that the developer could call at any time, including:

  • _setCenterCoordinate:edgePadding:zoomLevel:direction:duration:animationTimingFunction:completionHandler:, which among other things gets called by -didUpdateLocationWithUserTrackingAnimated: in untargeted course tracking mode
  • -_setVisibleCoordinates:count:edgePadding:direction:duration:animationTimingFunction:completionHandler:
  • -setCamera:withDuration:animationTimingFunction:completionHandler:, which is often called for state restoration purposes or when the content insets change (due to top or bottom bars resizing, for instance)
  • -_flyToCamera:edgePadding:withDuration:peakAltitude:completionHandler:

If any of these methods gets called just before a location update in targeted course tracking mode and a nontrivial completion handler is provided, we have everything we need for the recursion seen here.

As part of #5983, @incanus is swapping some equality checks, which should help to avoid this scenario.

@friedbunny
Copy link
Contributor Author

Recreated the crash: https://gist.github.com/friedbunny/1a9faa1666d0446c7c81206fb96b52c0

I appreciate that Xcode doesn’t try to show tens of thousands of lines in the sidebar:

screen shot 2016-08-17 at 10 27 40 am

@1ec5
Copy link
Contributor

1ec5 commented Aug 17, 2016

OK, so that validates the hypothesis above. To be sure, this particular case can be avoided by putting the call to resetNorth inside a dispatch_async block. Maybe there's a way for the regionDidChange mechanism to put developer- or user-initiated viewport changes inside a dispatch_async block if another animation is already ongoing.

@incanus incanus self-assigned this Aug 18, 2016
@jfirebaugh
Copy link
Contributor

It's not clear to me why the SDK is calling Map::cancelTransitions() in so many places. The only case where Map::cancelTransitions() should need to be called is when you want to cancel the current camera operation and not begin a new one. In cases where you want to replace the current camera operation with a new one, the core camera methods handle cancelling the prior operation automatically.

@jfirebaugh
Copy link
Contributor

I propose we:

  1. Remove the excess calls to cancelTransitions() in the SDK.
  2. Adjust the eventing behavior when you replace an active animation with a new one. The current behavior in this case is to send MapChangeRegionDidChangeAnimated (as a result of cancelling the prior animation) and then MapChangeRegionWillChangeAnimated (as a result of beginning the new animation). Let's instead just have an unbroken sequence of MapChangeRegionIsChanging events. (We can keep the call to the transitionFinishFn of AnimationOptions as a means of being notified when the prior animation is abandoned.)

@incanus
Copy link
Contributor

incanus commented Aug 22, 2016

I agree that we need more core discipline here.

The MapChangeRegionWillChangeAnimated and MapChangeRegionDidChangeAnimated events are modeled after MapKit, though; specifically, -[MKMapViewDelegate mapView:regionWillChangeAnimated:] and -[MKMapViewDelegate mapView:regionDidChangeAnimated:], which are important for coordinating other UI elements. It is important that they each be sent once at the start & end of a viewport change sequence. Having MapChangeRegionIsChanging is nice gravy also, and keeps in line with an extra bonus our raster iOS SDK had.

@1ec5
Copy link
Contributor

1ec5 commented Aug 22, 2016

Remove the excess calls to cancelTransitions() in the SDK.

These calls are partly cargo-cult programming, but they stem from #2313 and #3086, in which we were trying to serialize viewport changes and ensure the consistent notifications @incanus refers to above. (The Android SDK did something similar with #2296, and naturally the macOS SDK is canceling transitions too.)

I’m all in favor of an approach where mbgl::Transform just does the right thing so the SDK doesn’t have to worry about canceling transitions. Who knows, someday we might even get #3625 along with ponies and rainbows. 🌈

Let's instead just have an unbroken sequence of MapChangeRegionIsChanging events. (We can keep the call to the transitionFinishFn of AnimationOptions as a means of being notified when the prior animation is abandoned.)

If I’m not mistaken, the Android SDK relies on MapChangeRegionDidChangeAnimated for its completion handler analogue. The Android SDK doesn’t use transitionFinishFn at all.

/cc @tobrun

@1ec5
Copy link
Contributor

1ec5 commented Jan 24, 2017

I’m moving this issue to v3.5.0, because a complete fix will require beta testing and possibly changes to mbgl. However, note that #7125 remains on the milestone, and #7724 has landed.

@1ec5 1ec5 modified the milestones: ios-v3.5.0, ios-v3.4.1 Jan 24, 2017
@1ec5 1ec5 modified the milestones: ios-v3.5.0, ios-v3.6.0 Mar 10, 2017
@boundsj boundsj modified the milestones: ios-future, ios-v3.6.0 Apr 5, 2017
@brunoabinader
Copy link
Member

Can we test this again after #9381 got merged?

@1ec5
Copy link
Contributor

1ec5 commented Jul 3, 2017

Sure, we should double-check this crash. However, I don’t think the infinite recursion is related to #9381; flyTo() would only be incidental here.

@friedbunny
Copy link
Contributor Author

friedbunny commented Jul 6, 2017

As of 06a0c4a, this still recurses and crashes:

#0	0x000000018bcd8d6c in -[CALayer setTransform:] ()
#1	0x0000000108a79aa8 in __clang_call_terminate ()
#2	0x000000018bcd8ea8 in -[CALayer setAffineTransform:] ()
#3	0x000000018eb08a50 in -[UIView setTransform:] ()
#4	0x00000001007a5f6c in ::-[MGLMapView updateCompass]() at /mapbox-gl-native/platform/ios/src/MGLMapView.mm:5250
#5	0x00000001007a2a1c in ::-[MGLMapView cameraDidChangeAnimated:](BOOL) at /mapbox-gl-native/platform/ios/src/MGLMapView.mm:4864
#6	0x00000001007a9fb0 in MBGLView::onCameraDidChange(mbgl::MapObserver::CameraChangeMode) at /mapbox-gl-native/platform/ios/src/MGLMapView.mm:5450
#7	0x00000001007aadd0 in non-virtual thunk to MBGLView::onCameraDidChange(mbgl::MapObserver::CameraChangeMode) ()
#8	0x0000000100a0ed44 in mbgl::Transform::startTransition(mbgl::CameraOptions const&, mbgl::AnimationOptions const&, std::__1::function<void (double)>, std::__1::chrono::duration<long long, std::__1::ratio<1l, 1000000000l> > const&)::$_3::operator()() const at /mapbox-gl-native/src/mbgl/map/transform.cpp:589
#9	0x0000000100a0ecb4 in decltype(std::__1::forward<mbgl::Transform::startTransition(mbgl::CameraOptions const&, mbgl::AnimationOptions const&, std::__1::function<void (double)>, std::__1::chrono::duration<long long, std::__1::ratio<1l, 1000000000l> > const&)::$_3&>(fp)(std::__1::forward<>(fp0))) std::__1::__invoke<mbgl::Transform::startTransition(mbgl::CameraOptions const&, mbgl::AnimationOptions const&, std::__1::function<void (double)>, std::__1::chrono::duration<long long, std::__1::ratio<1l, 1000000000l> > const&)::$_3&>(mbgl::Transform::startTransition(mbgl::CameraOptions const&, mbgl::AnimationOptions const&, std::__1::function<void (double)>, std::__1::chrono::duration<long long, std::__1::ratio<1l, 1000000000l> > const&)::$_3&&&) [inlined] at /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/__functional_base:416
#10	0x0000000100a0eca4 in void std::__1::__invoke_void_return_wrapper<void>::__call<mbgl::Transform::startTransition(mbgl::CameraOptions const&, mbgl::AnimationOptions const&, std::__1::function<void (double)>, std::__1::chrono::duration<long long, std::__1::ratio<1l, 1000000000l> > const&)::$_3&>(mbgl::Transform::startTransition(mbgl::CameraOptions const&, mbgl::AnimationOptions const&, std::__1::function<void (double)>, std::__1::chrono::duration<long long, std::__1::ratio<1l, 1000000000l> > const&)::$_3&&&) at /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/__functional_base:468
#11	0x0000000100a0e9b4 in std::__1::__function::__func<mbgl::Transform::startTransition(mbgl::CameraOptions const&, mbgl::AnimationOptions const&, std::__1::function<void (double)>, std::__1::chrono::duration<long long, std::__1::ratio<1l, 1000000000l> > const&)::$_3, std::__1::allocator<mbgl::Transform::startTransition(mbgl::CameraOptions const&, mbgl::AnimationOptions const&, std::__1::function<void (double)>, std::__1::chrono::duration<long long, std::__1::ratio<1l, 1000000000l> > const&)::$_3>, void ()>::operator()() at /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/functional:1437
#12	0x0000000100864084 in std::__1::function<void ()>::operator()() const at /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/functional:1817
#13	0x0000000100a08974 in mbgl::Transform::cancelTransitions() at /mapbox-gl-native/src/mbgl/map/transform.cpp:609
#14	0x00000001009faf2c in mbgl::Map::cancelTransitions() at /mapbox-gl-native/src/mbgl/map/map.cpp:332
#15	0x000000010078932c in ::-[MGLMapView _setDirection:animated:](CLLocationDirection, BOOL) at /mapbox-gl-native/platform/ios/src/MGLMapView.mm:2681
#16	0x0000000100789294 in ::-[MGLMapView setDirection:animated:](CLLocationDirection, BOOL) at /mapbox-gl-native/platform/ios/src/MGLMapView.mm:2675
#17	0x0000000100783de0 in ::-[MGLMapView resetNorthAnimated:](BOOL) at /mapbox-gl-native/platform/ios/src/MGLMapView.mm:2126
#18	0x0000000100783d9c in ::-[MGLMapView resetNorth]() at /mapbox-gl-native/platform/ios/src/MGLMapView.mm:2121
#19	0x00000001000909bc in -[MBXViewController mapView:regionDidChangeAnimated:] at /mapbox-gl-native/platform/ios/app/MBXViewController.m:1926
...

@julianrex
Copy link
Contributor

FYI PR #11614 should address the infinite recursion stack crasher (I'm adding a test for this case).

@julianrex
Copy link
Contributor

#11614 fixes the stack crasher. But I believe we still need to address the larger issue of how we handle chained transitions (and what happens about cancelling previous ones, and comparing new ones to existing ones).

@julianrex
Copy link
Contributor

julianrex commented Jun 21, 2018

Closing, since #11614 addresses the crash. Any deeper refactoring is a longer-term issue.

EDIT: /cc @pozdnyakov for visibility on the refactoring we have discussed recently.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
crash iOS Mapbox Maps SDK for iOS navigation For the Mapbox Navigation SDK for Android or iOS or navigation use cases in general
Projects
None yet
Development

No branches or pull requests

8 participants