Pro Yearly is on sale from $80 to $50! »

Smart Debugging - Heavy Weapons for Hard Bugs

Smart Debugging - Heavy Weapons for Hard Bugs

Debugging can be exciting, but often also very, very frustrating. In this talk, I'll show you some lesser-known tools and techniques to find problems faster and make the compiler show you issues, before they become a crash for your users. Of course we also look at some real world examples.. TEKI CON🍍 Atlanta, March 2018

Video and Blog Post coming up soon at https://pspdfkit.com/blog/

832ece085bfe2c7c5b0ed6be62d7e675?s=128

Peter Steinberger

March 12, 2018
Tweet

Transcript

  1. Smart Debugging Peter Steinberger — @steipete TEKI CON Atlanta, March

    2018
  2. U+0C1C U+0C4D U+0C1E U+200C U+0C3Ex Peter Steinberger — @steipete —

    PSPDFKit.com
  3. Peter Steinberger — @steipete — PSPDFKit.com

  4. Peter Steinberger — @steipete — PSPDFKit.com

  5. Peter Steinberger — @steipete — PSPDFKit.com

  6. Peter Steinberger — @steipete — PSPDFKit.com

  7. PSPDFKit iOS, macOS, Android, Windows, Server, WebAssembly Peter Steinberger —

    @steipete — PSPDFKit.com
  8. Categories of Bugs → Business Logic → Performance → API

    Misuse → View → Memory → Locking/Threading/Races Peter Steinberger — @steipete — PSPDFKit.com
  9. Categories of Bugs → Business Logic Tests → Performance →

    API Misuse → View → Memory → Locking/Threading/Races Peter Steinberger — @steipete — PSPDFKit.com
  10. Categories of Bugs → Business Logic Tests → Performance ➡

    Instruments + Measure → API Misuse → View → Memory → Locking/Threading/Races Peter Steinberger — @steipete — PSPDFKit.com
  11. Categories of Bugs → Business Logic Tests → Performance ➡

    Instruments + Measure → API Misuse ➡ Documentation + Asserts → View → Memory → Locking/Threading/Races Peter Steinberger — @steipete — PSPDFKit.com
  12. Categories of Bugs → Business Logic Tests → Performance ➡

    Instruments + Measure → API Misuse ➡ Documentation + Asserts → View ➡ Architecture, UI Tests, QA → Memory → Locking/Threading/Races Peter Steinberger — @steipete — PSPDFKit.com
  13. Debug for any ObjC Object @interface NSObject (Private) -(id)_ivarDescription; -(id)_shortMethodDescription;

    -(id)_methodDescription; @end Peter Steinberger — @steipete — PSPDFKit.com
  14. LLDB View Debugging po [UIWindow.keyWindow recursiveDescription] po [UIViewController _printHierarchy] po

    [UIView _autolayoutTrace] po [_UIViewLayoutFeedbackLoopDebugger layoutFeedbackLoopDebugger] // lldb in Swift context: expr -l objc++ -O -- [UIWindow.keyWindow recursiveDescription] Peter Steinberger — @steipete — PSPDFKit.com
  15. View Debugging Helper Category @interface UIView (Debug) - (id)recursiveDescription; @end

    po self.recursiveDescription() as NSString Peter Steinberger — @steipete — PSPDFKit.com
  16. .lldbinit command alias alt expr -l objc++ -O --[[UIWindow keyWindow]

    _autolayoutTrace] Peter Steinberger — @steipete — PSPDFKit.com
  17. github.com/facebook/chisel Command Explanation pa11y <aView> Print accessibility labels alamborder Highlight

    views with ambiguous layout pproperties Print the properties of an instance slowanim Slows down animations. Sim + Device showimage Open a UIImage in Preview.app pactions <control> Print the actions/targets of a control Peter Steinberger — @steipete — PSPDFKit.com
  18. findinstances findinstances UIView subviews.@count == 0 findinstances NSArray @count >

    100 findinstances UIScrollViewDelegate findinstances UIView window == nil || hidden == true || alpha == 0 || layer.bounds.#size.width == 0 || layer.bounds.#size.height == 0 Peter Steinberger — @steipete — PSPDFKit.com
  19. findinstances findinstances UIView subviews.@count == 0 findinstances NSArray @count >

    100 findinstances UIScrollViewDelegate findinstances UIView window == nil || hidden == true || alpha == 0 || layer.bounds.#size.width == 0 || layer.bounds.#size.height == 0 Peter Steinberger — @steipete — PSPDFKit.com
  20. findinstances findinstances UIView subviews.@count == 0 findinstances NSArray @count >

    100 findinstances UIScrollViewDelegate findinstances UIView window == nil || hidden == true || alpha == 0 || layer.bounds.#size.width == 0 || layer.bounds.#size.height == 0 Peter Steinberger — @steipete — PSPDFKit.com
  21. findinstances findinstances UIView subviews.@count == 0 findinstances NSArray @count >

    100 findinstances UIScrollViewDelegate findinstances UIView window == nil || hidden == true || alpha == 0 || layer.bounds.#size.width == 0 || layer.bounds.#size.height == 0 Peter Steinberger — @steipete — PSPDFKit.com
  22. Memory Graph Debugger Peter Steinberger — @steipete — PSPDFKit.com

  23. Memory Graph Debugger Peter Steinberger — @steipete — PSPDFKit.com

  24. Peter Steinberger — @steipete — PSPDFKit.com

  25. Peter Steinberger — @steipete — PSPDFKit.com

  26. Peter Steinberger — @steipete — PSPDFKit.com

  27. @interface PSPDFRenderedImage : UIImage @end @implementation PSPDFRenderedImage @end object_setClass(image, PSPDFRenderedImage.class);

    Peter Steinberger — @steipete — PSPDFKit.com
  28. Peter Steinberger — @steipete — PSPDFKit.com

  29. PDFViewer.io Peter Steinberger — @steipete — PSPDFKit.com

  30. Clang Analyzer Peter Steinberger — @steipete — PSPDFKit.com

  31. Peter Steinberger — @steipete — PSPDFKit.com

  32. clang -cc1 -analyzer-checker-help Checker Explanation alpha.core.BoolAssignment Warn about assigning non-{0,1}

    values to Boolean variables alpha.clone.CloneChecker Reports similar pieces of code alpha.cplusplus.MisusedMovedObject Method calls on a moved-from object and copying a moved-from object will be reported optin.osx.cocoa.localizability.NonLocalizedStri ngChecker Warns about uses of non-localized NSStrings passed to UI methods expecting localized NSStrings Peter Steinberger — @steipete — PSPDFKit.com
  33. PSPDF_ANALYZER_FLAGS = -Xclang -analyzer-checker -Xclang alpha.core.BoolAssignment -Xclang -analyzer-checker -Xclang alpha.core.CallAndMessageUnInitRefArg

    -Xclang -analyzer-checker -Xclang alpha.core.DynamicTypeChecker -Xclang -analyzer-checker -Xclang alpha.core.FixedAddr -Xclang -analyzer-checker -Xclang alpha.core.IdenticalExpr -Xclang -analyzer-checker -Xclang alpha.core.PointerSub -Xclang -analyzer-checker -Xclang alpha.core.SizeofPtr -Xclang -analyzer-checker -Xclang alpha.core.TestAfterDivZero -Xclang -analyzer-checker -Xclang alpha.security.ArrayBoundV2 -Xclang -analyzer-checker -Xclang alpha.security.MallocOverflow -Xclang -analyzer-checker -Xclang alpha.security.ReturnPtrRange -Xclang -analyzer-checker -Xclang alpha.security.taint.TaintPropagation -Xclang -analyzer-checker -Xclang alpha.cplusplus.MisusedMovedObject -Xclang -analyzer-checker -Xclang alpha.unix.BlockInCriticalSection -Xclang -analyzer-checker -Xclang alpha.unix.Chroot -Xclang -analyzer-checker -Xclang alpha.unix.SimpleStream -Xclang -analyzer-checker -Xclang alpha.unix.cstring.BufferOverlap -Xclang -analyzer-checker -Xclang alpha.unix.cstring.NotNullTerminated -Xclang -analyzer-checker -Xclang alpha.unix.cstring.OutOfBounds -Xclang -analyzer-checker -Xclang alpha.osx.cocoa.InstanceVariableInvalidation -Xclang -analyzer-checker -Xclang alpha.osx.cocoa.DirectIvarAssignmentForAnnotatedFunctions -Xclang -analyzer-checker -Xclang alpha.core.Conversion // Crashes Xcode 9.2 // -Xclang -analyzer-checker -Xclang alpha.cplusplus.IteratorPastEnd Peter Steinberger — @steipete — PSPDFKit.com
  34. #ifndef __clang_analyzer__ // Ignore in analyzer - we're assigning nil

    to a nonnull property. // The getter never returns nil - we reload on demand. _resourceManager = nil; #endif Peter Steinberger — @steipete — PSPDFKit.com
  35. /** Returns the string argument marked as localized to avoid

    analyzer warnings. Use this for strings that may be shown in the UI but should not be localized. http://clang-analyzer.llvm.org/faq.html */ __attribute__((annotate("returns_localized_nsstring"))) inline NSString *PSPDFLocalizationNotNeeded(NSString *string) { return string; } Peter Steinberger — @steipete — PSPDFKit.com
  36. -Weverything Hard Mode in Xcode Peter Steinberger — @steipete —

    PSPDFKit.com
  37. Warnings (Reality) // Xcode 9.2 PSPDF_WARNING_CFLAGS_0920 = $(inherited) $(PSPDF_ANALYZER_FLAGS) -Weverything

    -Wno-error-deprecated-declarations -Wno-objc-missing-property-synthesis -Wno-unused-parameter -Wno-covered-switch-default -Wno-direct-ivar-access -Wno-assign-enum -Wno-float-equal -Wno-vla -Wno-documentation-unknown-command -Wno-packed -Wno-padded -Wno-auto-import -Wno-selector -Wno-sign-conversion -Wno-auto-import -Wno-static-in-inline -Wno-gnu-conditional-omitted-operand -Wno-gnu-zero-variadic-macro-arguments -Wno-gnu-statement-expression -Wno-language-extension-token -Wno-pointer-arith -Wno-empty-translation-unit -Wno-format-non-iso -Wno-comment -Wno-gnu-folding-constant -Wno-c++98-compat-pedantic -Wno-c++98-compat -Wno-old-style-cast -Wno-incomplete-module -Wno-vla-extension -Wno-c99-extensions -Wno-cstring-format-directive -Rno-module-build -Wno-reserved-id-macro -Wno-undef -Wno-weak-vtables -Wno-over-aligned -Wno-double-promotion -Wno-incompatible-sysroot -Wno-gnu-auto-type -Wno-undefined-func-template -Wno-comma -Wno-c++1z-extensions // Xcode 9.3 PSPDF_WARNING_CFLAGS_0930 = $(PSPDF_WARNING_CFLAGS_0920) -Wno-zero-as-null-pointer-constant -Wno-deprecated-dynamic-exception-spec -Wno-private-module PSPDF_WARNING_CFLAGS = $(PSPDF_WARNING_CFLAGS_$(XCODE_VERSION_MINOR)) WARNING_CFLAGS = $(PSPDF_WARNING_CFLAGS) Peter Steinberger — @steipete — PSPDFKit.com
  38. Warnings (Reality) // Xcode 9.2 PSPDF_WARNING_CFLAGS_0920 = $(inherited) $(PSPDF_ANALYZER_FLAGS) -Weverything

    -Wno-error-deprecated-declarations -Wno-objc-missing-property-synthesis -Wno-unused-parameter -Wno-covered-switch-default -Wno-direct-ivar-access -Wno-assign-enum -Wno-float-equal -Wno-vla -Wno-documentation-unknown-command -Wno-packed -Wno-padded -Wno-auto-import -Wno-selector -Wno-sign-conversion -Wno-auto-import -Wno-static-in-inline -Wno-gnu-conditional-omitted-operand -Wno-gnu-zero-variadic-macro-arguments -Wno-gnu-statement-expression -Wno-language-extension-token -Wno-pointer-arith -Wno-empty-translation-unit -Wno-format-non-iso -Wno-comment -Wno-gnu-folding-constant -Wno-c++98-compat-pedantic -Wno-c++98-compat -Wno-old-style-cast -Wno-incomplete-module -Wno-vla-extension -Wno-c99-extensions -Wno-cstring-format-directive -Rno-module-build -Wno-reserved-id-macro -Wno-undef -Wno-weak-vtables -Wno-over-aligned -Wno-double-promotion -Wno-incompatible-sysroot -Wno-gnu-auto-type -Wno-undefined-func-template -Wno-comma -Wno-c++1z-extensions // Xcode 9.3 PSPDF_WARNING_CFLAGS_0930 = $(PSPDF_WARNING_CFLAGS_0920) -Wno-zero-as-null-pointer-constant -Wno-deprecated-dynamic-exception-spec -Wno-private-module PSPDF_WARNING_CFLAGS = $(PSPDF_WARNING_CFLAGS_$(XCODE_VERSION_MINOR)) WARNING_CFLAGS = $(PSPDF_WARNING_CFLAGS) Peter Steinberger — @steipete — PSPDFKit.com
  39. #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" ...

    #pragma clang diagnostic pop Peter Steinberger — @steipete — PSPDFKit.com
  40. Clang Sanitizers → Address Sanitizer → Undefined Behaviour Sanitizer →

    Main Thread Checker → Thread Sanitizer Peter Steinberger — @steipete — PSPDFKit.com
  41. Peter Steinberger — @steipete — PSPDFKit.com

  42. Address Sanitizer /** ASAN_OPTIONS no longer settable when running tests

    within Xcode. rdar://28103342 Document Xcode config settings to enable Clang Sanitizers. rdar://28250805 Build fails with address sanitizer feature enabled and custom CC. rdar://24972653 https://github.com/google/sanitizers/wiki/AddressSanitizer */ __attribute__((visibility("default"))) __attribute__((no_sanitize_address)) FOUNDATION_EXPORT const char *__asan_default_options(void); FOUNDATION_EXPORT const char *__asan_default_options(void) { return "verbosity=0:detect_odr_violation=0:suppressions=" ASANSUPPPATH; // AddressSanitizerSuppressions.supp } __attribute__((constructor)) static void PSPDFASANSettingsPrinter(void) { NSLog(@"AddressSanitizer Enabled. Settings: %s (See ASAN_OPTIONS.h)", __asan_default_options()); } // FILE AddressSanitizerSuppressions.supp # Apple has issues in there that we cannot fix. interceptor_via_fun:pdf_Finalize Peter Steinberger — @steipete — PSPDFKit.com
  43. // We only enable ASAN for 64-bit as the Simulator

    has troubles running that in 32 bit. // We eventually run out of memory while the tests work. // Using ASAN on devices fails with "dyld: Library not loaded: @rpath/libclang_rt.asan_ios_dynamic.dylib". CLANG_ADDRESS_SANITIZER[arch=x86_64] = YES CLANG_UNDEFINED_BEHAVIOR_SANITIZER = YES // Typical slowdown introduced by ThreadSanitizer is about 5x-15x. // Typical memory overhead introduced by ThreadSanitizer is about 5x-10x. ENABLE_THREAD_SANITIZER = NO Peter Steinberger — @steipete — PSPDFKit.com
  44. Hunting an Over-Release *** -[PSPDFDocument release]: message sent to deallocated

    instance 0x617000007780 Peter Steinberger — @steipete — PSPDFKit.com
  45. // release resources as we no longer need them //

    but don't block the calling thread for this! [[PSPDFDispatchQueue.backgroundQueue namedQueue:@"cache.deallocation"] async:^{ @synchronized(self) { self->_imageRenderingCompletionBlock = nil; } }]; Peter Steinberger — @steipete — PSPDFKit.com
  46. Peter Steinberger — @steipete — PSPDFKit.com

  47. ARC objc_autorelease() _swift_objc_autoreleasePoolPop() swift_retain() Peter Steinberger — @steipete — PSPDFKit.com

  48. ARC, the Enemy Peter Steinberger — @steipete — PSPDFKit.com

  49. Retain Tracker - (BOOL)shouldPrintRetainRelease { return !NSThread.isMainThread; } - (id)retain

    { // release, autorelease if ([self shouldPrintRetainRelease]) { printf("RETAIN %p %s (queue:%s) -> %s", (void *)self, NSThread.currentThread.name.UTF8String, [self queueName], [NSThread callStackSymbols].description.UTF8String); } return [super retain]; } Peter Steinberger — @steipete — PSPDFKit.com
  50. + (void)initialize { class_setSuperclass(PSPDFDocument.class, (Class)NSClassFromString(@"PSPDFRetainTracker")); } Peter Steinberger — @steipete

    — PSPDFKit.com
  51. /** * Sets the superclass of a given class. *

    * @param cls The class whose superclass you want to set. * @param newSuper The new superclass for cls. * * @return The old superclass for cls. * * @warning You should not use this function. */ OBJC_EXPORT Class _Nonnull class_setSuperclass(Class _Nonnull cls, Class _Nonnull newSuper) __OSX_DEPRECATED(10.5, 10.5, "not recommended") __IOS_DEPRECATED(2.0, 2.0, "not recommended") __TVOS_DEPRECATED(9.0, 9.0, "not recommended") __WATCHOS_DEPRECATED(1.0, 1.0, "not recommended") __BRIDGEOS_DEPRECATED(2.0, 2.0, "not recommended"); Peter Steinberger — @steipete — PSPDFKit.com
  52. )AUTORELEASE 0x617000007780 (queue:com.apple.root.background-qos) -> ( 0 PSPDFKit 0x000000012ed5818b -[PSPDFRetainTracker autorelease]

    + 747 1 PSPDFKit 0x0000000129fbce4c _ZN5PSPDF2asI13PSPDFDocumentEEPT_P11objc_object + 652 2 PSPDFKit 0x0000000129fb83e3 _ZN5PSPDF11as_force_nnI13PSPDFDocumentEEPT_P8NSObject + 2563 3 PSPDFKit 0x0000000129fb8b02 -[PSPDFCacheDocumentHashManager willCloseDocument:] + 514 4 CoreFoundation 0x000000010feb2b8c __CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ + 12 5 CoreFoundation 0x000000010feb2a65 _CFXRegistrationPost + 453 6 CoreFoundation 0x000000010feb27a1 ___CFXNotificationPost_block_invoke + 225 7 CoreFoundation 0x000000010fe74422 -[_CFXNotificationRegistrar find:object:observer:enumerator:] + 1826 8 CoreFoundation 0x000000010fe735a1 _CFXNotificationPost + 609 9 Foundation 0x000000010eef2e57 -[NSNotificationCenter postNotificationName:object:userInfo:] + 66 10 PSPDFKit 0x000000012a073e05 -[PSPDFDocument destroyDocumentProviders] + 917 11 PSPDFKit 0x000000012a0533d7 -[PSPDFDocument dealloc] + 375 12 Foundation 0x000000010ef574e8 NSKVODeallocate + 158 13 libobjc.A.dylib 0x000000010f525a6e _ZN11objc_object17sidetable_releaseEb + 202 14 PSPDFKit 0x000000012ed587dd -[PSPDFRetainTracker release] + 1117 15 PSPDFKit 0x000000012a2a37f6 -[PSPDFRenderRequest .cxx_destruct] + 182 16 libobjc.A.dylib 0x000000010f50f920 _ZL27object_cxxDestructFromClassP11objc_objectP10objc_class + 127 17 libobjc.A.dylib 0x000000010f51b502 objc_destructInstance + 124 18 CoreFoundation 0x000000010ff98936 -[NSObject(NSObject) __dealloc_zombie] + 150 19 libobjc.A.dylib 0x000000010f525a6e _ZN11objc_object17sidetable_releaseEb + 202 20 PSPDFKit 0x000000012a02a208 -[PSPDFRenderTask .cxx_destruct] + 152 21 libobjc.A.dylib 0x000000010f50f920 _ZL27object_cxxDestructFromClassP11objc_objectP10objc_class + 127 22 libobjc.A.dylib 0x000000010f51b502 objc_destructInstance + 124 23 CoreFoundation 0x000000010ff98936 -[NSObject(NSObject) __dealloc_zombie] + 150 24 PSPDFKit 0x000000012a0204e9 -[PSPDFRenderTask dealloc] + 409 25 libobjc.A.dylib 0x000000010f525a6e _ZN11objc_object17sidetable_releaseEb + 202 26 CoreFoundation 0x000000010fe938bd -[__NSSetM dealloc] + 157 27 libobjc.A.dylib 0x000000010f525a6e _ZN11objc_object17sidetable_releaseEb + 202 28 PSPDFKit 0x000000012a1161fe -[PSPDFRenderJob .cxx_destruct] + 126 29 libobjc.A.dylib 0x000000010f50f920 _ZL27object_cxxDestructFromClassP11objc_objectP10objc_class + 127 30 libobjc.A.dylib 0x000000010f51b502 objc_destructInstance + 124 31 CoreFoundation 0x000000010ff98936 -[NSObject(NSObject) __dealloc_zombie] + 150 32 PSPDFKit 0x000000012a10ce39 -[PSPDFRenderJob dealloc] + 409 33 libobjc.A.dylib 0x000000010f525a6e _ZN11objc_object17sidetable_releaseEb + 202 34 PSPDFKit 0x000000012a115fcd __destroy_helper_block_.127 + 29 35 libsystem_blocks.dylib 0x000000011414d98a _Block_release + 111 36 PSPDFKit 0x000000012ec8334b __destroy_helper_block_.216 + 59 37 libsystem_blocks.dylib 0x000000011414d98a _Block_release + 111 38 libobjc.A.dylib 0x000000010f5261b2 _ZN12_GLOBAL__N_119AutoreleasePoolPage3popEPv + 860 39 libdispatch.dylib 0x0000000114066762 _dispatch_last_resort_autorelease_pool_pop + 27 40 libdispatch.dylib 0x0000000114070fc1 _dispatch_root_queue_drain + 1186 41 libdispatch.dylib 0x0000000114070ac1 _dispatch_worker_thread3 + 119 42 libsystem_pthread.dylib 0x00000001145881ca _pthread_wqthread + 1387 43 libsystem_pthread.dylib 0x0000000114587c4d start_wqthread + 13 ) Peter Steinberger — @steipete — PSPDFKit.com
  53. )AUTORELEASE 0x617000007780 (queue:com.apple.root.background-qos) -> ( 0 PSPDFKit 0x000000012ed5818b -[PSPDFRetainTracker autorelease]

    + 747 1 PSPDFKit 0x0000000129fbce4c _ZN5PSPDF2asI13PSPDFDocumentEEPT_P11objc_object + 652 2 PSPDFKit 0x0000000129fb83e3 _ZN5PSPDF11as_force_nnI13PSPDFDocumentEEPT_P8NSObject + 2563 3 PSPDFKit 0x0000000129fb8b02 -[PSPDFCacheDocumentHashManager willCloseDocument:] + 514 4 CoreFoundation 0x000000010feb2b8c __CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ + 12 5 CoreFoundation 0x000000010feb2a65 _CFXRegistrationPost + 453 6 CoreFoundation 0x000000010feb27a1 ___CFXNotificationPost_block_invoke + 225 7 CoreFoundation 0x000000010fe74422 -[_CFXNotificationRegistrar find:object:observer:enumerator:] + 1826 8 CoreFoundation 0x000000010fe735a1 _CFXNotificationPost + 609 9 Foundation 0x000000010eef2e57 -[NSNotificationCenter postNotificationName:object:userInfo:] + 66 10 PSPDFKit 0x000000012a073e05 -[PSPDFDocument destroyDocumentProviders] + 917 11 PSPDFKit 0x000000012a0533d7 -[PSPDFDocument dealloc] + 375 12 Foundation 0x000000010ef574e8 NSKVODeallocate + 158 13 libobjc.A.dylib 0x000000010f525a6e _ZN11objc_object17sidetable_releaseEb + 202 14 PSPDFKit 0x000000012ed587dd -[PSPDFRetainTracker release] + 1117 15 PSPDFKit 0x000000012a2a37f6 -[PSPDFRenderRequest .cxx_destruct] + 182 ) Peter Steinberger — @steipete — PSPDFKit.com
  54. )AUTORELEASE 0x617000007780 (queue:com.apple.root.background-qos) -> ( 0 PSPDFKit 0x000000012ed5818b -[PSPDFRetainTracker autorelease]

    + 747 1 PSPDFKit 0x0000000129fbce4c _ZN5PSPDF2asI13PSPDFDocumentEEPT_P11objc_object + 652 2 PSPDFKit 0x0000000129fb83e3 _ZN5PSPDF11as_force_nnI13PSPDFDocumentEEPT_P8NSObject + 2563 3 PSPDFKit 0x0000000129fb8b02 -[PSPDFCacheDocumentHashManager willCloseDocument:] + 514 4 CoreFoundation 0x000000010feb2b8c __CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ + 12 5 CoreFoundation 0x000000010feb2a65 _CFXRegistrationPost + 453 6 CoreFoundation 0x000000010feb27a1 ___CFXNotificationPost_block_invoke + 225 7 CoreFoundation 0x000000010fe74422 -[_CFXNotificationRegistrar find:object:observer:enumerator:] + 1826 8 CoreFoundation 0x000000010fe735a1 _CFXNotificationPost + 609 9 Foundation 0x000000010eef2e57 -[NSNotificationCenter postNotificationName:object:userInfo:] + 66 10 PSPDFKit 0x000000012a073e05 -[PSPDFDocument destroyDocumentProviders] + 917 11 PSPDFKit 0x000000012a0533d7 -[PSPDFDocument dealloc] + 375 12 Foundation 0x000000010ef574e8 NSKVODeallocate + 158 13 libobjc.A.dylib 0x000000010f525a6e _ZN11objc_object17sidetable_releaseEb + 202 14 PSPDFKit 0x000000012ed587dd -[PSPDFRetainTracker release] + 1117 15 PSPDFKit 0x000000012a2a37f6 -[PSPDFRenderRequest .cxx_destruct] + 182 ) Peter Steinberger — @steipete — PSPDFKit.com
  55. - (void)willCloseDocument:(NSNotification *)aNotification { let document = PSPDF::as_force_nn<PSPDFDocument>(aNotification.object); if (document.hasUnsavedChanges

    || document.hasDirtyAnnotations) { return; } [self updateHashesForDocument:document]; } Peter Steinberger — @steipete — PSPDFKit.com
  56. - (void)willCloseDocument:(NSNotification *)aNotification { let document = PSPDF::as_force_nn<PSPDFDocument>(aNotification.object); if (document.hasUnsavedChanges

    || document.hasDirtyAnnotations) { return; } [self updateHashesForDocument:document]; } Peter Steinberger — @steipete — PSPDFKit.com
  57. Peter Steinberger — @steipete — PSPDFKit.com

  58. /// as? Casts nullable object to type T. Return nil

    if wrong type. template <class T> inline T *_Nullable as(id _Nullable o) noexcept { if ([o isKindOfClass:[T class]]) { return (T * _Nullable)o; } return nil; } Peter Steinberger — @steipete — PSPDFKit.com
  59. /// as? Casts nullable object to type T. Return nil

    if wrong type. template <class T> inline T *_Nullable as(id _Nullable o) noexcept { if ([o isKindOfClass:[T class]]) { return (T * _Nullable)o; } return nil; } Peter Steinberger — @steipete — PSPDFKit.com
  60. /// as? Casts nullable object to type T. Return nil

    if wrong type. template <class T> inline __attribute__((always_inline)) T *_Nullable as(id _Nullable o) noexcept { if ([o isKindOfClass:[T class]]) { return (T * _Nullable)o; } return nil; } Peter Steinberger — @steipete — PSPDFKit.com
  61. Recap → Best debugging is no debugging → brew install

    chisel → Enable Xcode Hard Mode → Use the Force Sanitizers → Remember the Memory Graph Debugger → When debugging, anything goes Peter Steinberger — @steipete — PSPDFKit.com
  62. Thanks for listening! Slides: @steipete on Twitter Picking Apart the

    Crashing iOS String: https://manishearth.github.io/blog/2018/02/15/picking-apart-the-crashing-ios-string/ Testing with Address Sanitizer: https://pspdfkit.com/blog/2016/test-with-asan/ Chisel Cheat Cheet: https://kapeli.com/cheat_sheets/LLDB_Chisel_Commands.docset/Contents/Resources/Documents/index iOS Device List with maximum supported version: https://everyi.com/by-capability/maximum-supported-ios-version-for-ipod-iphone-ipad.html Undefined Behavior Sanitizer: https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html Swift and Warnings: https://twitter.com/jckarter/status/972894889221414912 Self-Written Main Thread Guard: https://gist.github.com/steipete/5664345 Scripted Breakpoints: https://pspdfkit.com/blog/2016/scripted-breakpoints/ User Breakpoints: https://pspdfkit.com/blog/2017/user-breakpoints-in-xcode/ Swift Compiler Bug Hunt: https://topologyeyewear.github.io/engineering-blog/2018/03/07/heap_corruption/ View Layout Feedback Loop Debugger: https://developer.apple.com/videos/play/wwdc2016/236 Visual Debugging with Xcode: https://developer.apple.com/videos/play/wwdc2016/410 Make UI Tests Fast: https://pspdfkit.com/blog/2016/running-ui-tests-with-ludicrous-speed/ Smart Debugging — TEKI CON Atlanta, March 2018 — Peter Steinberger — @steipete — PSPDFKit.com