Crash in CAKeyframeAnimation to animate a view along a path

I have code for animating a UIView: reduce it when animating along the way.

It crashes with the error below (reproducible: always):

CoreGraphics`CG::Path::apply(void*, void (*)(void*, CGPathElementType, CGPoint const*)) const: 0x1055c06: pushl %ebp 0x1055c07: movl %esp, %ebp 0x1055c09: subl $24, %esp 0x1055c0c: movl 8(%ebp), %eax 0x1055c0f: movl (%eax), %ecx 0x1055c11: movl (%ecx), %eax 0x1055c13: movl 16(%ebp), %edx 0x1055c16: movl %edx, 8(%esp) 0x1055c1a: movl 12(%ebp), %edx 0x1055c1d: movl %edx, 4(%esp) 0x1055c21: movl %ecx, (%esp) 0x1055c24: calll *64(%eax) 0x1055c27: addl $24, %esp 0x1055c2a: popl %ebp 0x1055c2b: ret 

I think this comes from the method below ( pathAnimationWithStartPoint: , as if I are not adding the CAKeyframeAnimation returned by it, i.e. simply:

 [group setAnimations:@[ zoomAnimation ]]; 

instead

 [group setAnimations:@[ zoomAnimation, pathAnimation ]]; 

It works without a glitch.

 - (CAKeyframeAnimation *) pathAnimationWithStartPoint:(CGPoint) startPoint { CGPoint endPoint = self.showApplicationTourButton.center; CGFloat xDistanceBetweenStartAndEndPoints = abs(startPoint.x - endPoint.x); CGFloat yOfHighestPointOfCurvePath = endPoint.y - 250; CGPoint controlPoint1 = CGPointMake(startPoint.x + 1.0f / 3.0f * xDistanceBetweenStartAndEndPoints, yOfHighestPointOfCurvePath); CGPoint controlPoint2 = CGPointMake(startPoint.x + 2.0f / 3.0f * xDistanceBetweenStartAndEndPoints, yOfHighestPointOfCurvePath); CGMutablePathRef curvedPath = CGPathCreateMutable(); CGPathMoveToPoint(curvedPath, NULL, startPoint.x, startPoint.y); CGPathAddCurveToPoint(curvedPath, NULL, controlPoint1.x, controlPoint1.y, controlPoint2.x, controlPoint2.y, endPoint.x, endPoint.y); CAKeyframeAnimation *pathAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"]; pathAnimation.path = curvedPath; CGPathRelease(curvedPath); pathAnimation.calculationMode = kCAAnimationPaced; pathAnimation.fillMode = kCAFillModeForwards; pathAnimation.removedOnCompletion = NO; return pathAnimation; } 

Backtrace:

 * thread #1: tid = 0x1a03, 0x01055c11 CoreGraphics`CG::Path::apply(void*, void (*)(void*, CGPathElementType, CGPoint const*)) const + 11, stop reason = EXC_BAD_ACCESS (code=2, address=0x0) frame #0: 0x01055c11 CoreGraphics`CG::Path::apply(void*, void (*)(void*, CGPathElementType, CGPoint const*)) const + 11 frame #1: 0x00f5d090 CoreGraphics`CGPathApply + 64 frame #2: 0x01838c68 QuartzCore`CA::Render::Path::new_path(CGPath const*, bool) + 158 frame #3: 0x018c3493 QuartzCore`-[CAKeyframeAnimation _setCARenderAnimation:layer:] + 176 frame #4: 0x018c3b2c QuartzCore`-[CAKeyframeAnimation _copyRenderAnimationForLayer:] + 68 frame #5: 0x018c6f12 QuartzCore`-[CAAnimationGroup _copyRenderAnimationForLayer:] + 241 frame #6: 0x018df547 QuartzCore`CA::Layer::commit_animations(CA::Transaction*, double (*)(CA::Layer*, double, void*), void (*)(CA::Layer*, CA::Render::Animation*, void*), void (*)(CA::Layer*, void**, void*), void*) + 641 frame #7: 0x01855520 QuartzCore`CA::Context::commit_layer(CA::Layer*, unsigned int, unsigned int, void*) + 94 frame #8: 0x018d87fa QuartzCore`CA::Layer::commit_if_needed(CA::Transaction*, void (*)(CA::Layer*, unsigned int, unsigned int, void*), void*) + 330 frame #9: 0x018d877e QuartzCore`CA::Layer::commit_if_needed(CA::Transaction*, void (*)(CA::Layer*, unsigned int, unsigned int, void*), void*) + 206 frame #10: 0x01856667 QuartzCore`CA::Context::commit_transaction(CA::Transaction*) + 1775 frame #11: 0x01857227 QuartzCore`CA::Transaction::commit() + 395 frame #12: 0x018f9b17 QuartzCore`+[CATransaction commit] + 52 frame #13: 0x000399bf MyApp`-[HomeViewController catchTourScrollViewScreenshotViewAndAnimateItToButton](self=0x0b4e5210, _cmd=0x006f381a) + 1903 at HomeViewController.m:197 frame #14: 0x0391f663 libobjc.A.dylib`-[NSObject performSelector:] + 62 frame #15: 0x0003c383 MyApp`-[NSObject(self=0x0b4e5210, _cmd=0x006ef5ad, selector=0x006f381a) performSelectorIfRespondsToIt:] + 243 at NSObject+PerformSelectorIfRespondsToIt.m:22 frame #16: 0x00042506 MyApp`__44-[TourViewController closeTourWithAnimation]_block_invoke268(.block_descriptor=0x0b6985a0, finished='\x01') + 86 at TourViewController.m:419 frame #17: 0x01af0df6 UIKit`-[UIViewAnimationBlockDelegate _didEndBlockAnimation:finished:context:] + 223 frame #18: 0x01ae3d66 UIKit`-[UIViewAnimationState sendDelegateAnimationDidStop:finished:] + 237 frame #19: 0x01ae3f04 UIKit`-[UIViewAnimationState animationDidStop:finished:] + 68 frame #20: 0x12b6ff28 UIKit`-[UIViewAnimationStateAccessibility(SafeCategory) animationDidStop:finished:] + 66 frame #21: 0x018df7d8 QuartzCore`CA::Layer::run_animation_callbacks(void*) + 284 frame #22: 0x03a90014 libdispatch.dylib`_dispatch_client_callout + 14 frame #23: 0x03a807d5 libdispatch.dylib`_dispatch_main_queue_callback_4CF + 296 frame #24: 0x03f3eaf5 CoreFoundation`__CFRunLoopRun + 1925 frame #25: 0x03f3df44 CoreFoundation`CFRunLoopRunSpecific + 276 frame #26: 0x03f3de1b CoreFoundation`CFRunLoopRunInMode + 123 frame #27: 0x044c67e3 GraphicsServices`GSEventRunModal + 88 frame #28: 0x044c6668 GraphicsServices`GSEventRun + 104 frame #29: 0x01aa5ffc UIKit`UIApplicationMain + 1211 frame #30: 0x0000285d MyApp`main(argc=1, argv=0xbffff3f4) + 141 at main.m:16 frame #31: 0x00002785 MyApp`start + 53 * thread #1: tid = 0x1a03, 0x01055c11 CoreGraphics`CG::Path::apply(void*, void (*)(void*, CGPathElementType, CGPoint const*)) const + 11, stop reason = EXC_BAD_ACCESS (code=2, address=0x0) frame #0: 0x01055c11 CoreGraphics`CG::Path::apply(void*, void (*)(void*, CGPathElementType, CGPoint const*)) const + 11 frame #1: 0x00f5d090 CoreGraphics`CGPathApply + 64 frame #2: 0x01838c68 QuartzCore`CA::Render::Path::new_path(CGPath const*, bool) + 158 frame #3: 0x018c3493 QuartzCore`-[CAKeyframeAnimation _setCARenderAnimation:layer:] + 176 frame #4: 0x018c3b2c QuartzCore`-[CAKeyframeAnimation _copyRenderAnimationForLayer:] + 68 frame #5: 0x018c6f12 QuartzCore`-[CAAnimationGroup _copyRenderAnimationForLayer:] + 241 frame #6: 0x018df547 QuartzCore`CA::Layer::commit_animations(CA::Transaction*, double (*)(CA::Layer*, double, void*), void (*)(CA::Layer*, CA::Render::Animation*, void*), void (*)(CA::Layer*, void**, void*), void*) + 641 frame #7: 0x01855520 QuartzCore`CA::Context::commit_layer(CA::Layer*, unsigned int, unsigned int, void*) + 94 frame #8: 0x018d87fa QuartzCore`CA::Layer::commit_if_needed(CA::Transaction*, void (*)(CA::Layer*, unsigned int, unsigned int, void*), void*) + 330 frame #9: 0x018d877e QuartzCore`CA::Layer::commit_if_needed(CA::Transaction*, void (*)(CA::Layer*, unsigned int, unsigned int, void*), void*) + 206 frame #10: 0x01856667 QuartzCore`CA::Context::commit_transaction(CA::Transaction*) + 1775 frame #11: 0x01857227 QuartzCore`CA::Transaction::commit() + 395 frame #12: 0x018f9b17 QuartzCore`+[CATransaction commit] + 52 frame #13: 0x000399bf MyApp`-[HomeViewController catchTourScrollViewScreenshotViewAndAnimateItToButton](self=0x0b4e5210, _cmd=0x006f381a) + 1903 at HomeViewController.m:197 frame #14: 0x0391f663 libobjc.A.dylib`-[NSObject performSelector:] + 62 frame #15: 0x0003c383 MyApp`-[NSObject(self=0x0b4e5210, _cmd=0x006ef5ad, selector=0x006f381a) performSelectorIfRespondsToIt:] + 243 at NSObject+PerformSelectorIfRespondsToIt.m:22 frame #16: 0x00042506 MyApp`__44-[TourViewController closeTourWithAnimation]_block_invoke268(.block_descriptor=0x0b6985a0, finished='\x01') + 86 at TourViewController.m:419 frame #17: 0x01af0df6 UIKit`-[UIViewAnimationBlockDelegate _didEndBlockAnimation:finished:context:] + 223 frame #18: 0x01ae3d66 UIKit`-[UIViewAnimationState sendDelegateAnimationDidStop:finished:] + 237 frame #19: 0x01ae3f04 UIKit`-[UIViewAnimationState animationDidStop:finished:] + 68 frame #20: 0x12b6ff28 UIKit`-[UIViewAnimationStateAccessibility(SafeCategory) animationDidStop:finished:] + 66 frame #21: 0x018df7d8 QuartzCore`CA::Layer::run_animation_callbacks(void*) + 284 frame #22: 0x03a90014 libdispatch.dylib`_dispatch_client_callout + 14 frame #23: 0x03a807d5 libdispatch.dylib`_dispatch_main_queue_callback_4CF + 296 frame #24: 0x03f3eaf5 CoreFoundation`__CFRunLoopRun + 1925 frame #25: 0x03f3df44 CoreFoundation`CFRunLoopRunSpecific + 276 frame #26: 0x03f3de1b CoreFoundation`CFRunLoopRunInMode + 123 frame #27: 0x044c67e3 GraphicsServices`GSEventRunModal + 88 frame #28: 0x044c6668 GraphicsServices`GSEventRun + 104 frame #29: 0x01aa5ffc UIKit`UIApplicationMain + 1211 frame #30: 0x0000285d MyApp`main(argc=1, argv=0xbffff3f4) + 141 at main.m:16 frame #31: 0x00002785 MyApp`start + 53 

Enabling NSZombie does not provide more useful debugging information.

The same code that was used before upgrading to Xcode 4.6.3 (4H1503). It should be noted: in the simulator, the animation sometimes paused, and clicking on it resumed it. This strange artifact was a sign that something was wrong, but I did not know it yet.

Did I miss something?
If this is a known bug, is there a workaround?


Some research notes: A similar question was asked on SO , but the accepted answer is simply to “fix” the problem by changing the animation of the path to linear translation.

My problem is also very similar to a blog post: http://www.blogosfera.co.uk/2013/08/exc_bad_access-while-using-coreanimation/

+4
source share
1 answer

It really isn’t so many answers, but more an attempt to give you a tool to find more clues. Hope someone with a bigger key than I will call.

  • Enable malloc stack logging.
  • Reproduce the failure.
  • Check registers; if $ r0 or $ r1 looks like heap allocations, then get the malloc history of the specified address (s).

If the last event is either FREE , then the data buffer (or object) is freed prematurely. (see http://lldb.llvm.org/lldb-gdb.html for information on capturing the malloc story).

Now this may not really help you, even if it confirms that it is premature release. What will he tell you, if so, then this is a race condition. Unfortunately, a fix is ​​actually impossible, but a workaround may be. If you can figure out which object you control that could allocate the premature free() d buffer, then you should be able to maintain a strong reference to the specified object until the animation is completely complete.

And report the error by adding your emergency binary.


Also enable malloc scribble. This ensures that the freed memory is immediately erased after being freed, which should lead to a crash as soon as possible.

+2
source

Source: https://habr.com/ru/post/1498986/


All Articles