bugsnag / bugsnag-cocoa

BugSnag error monitoring & exception reporter for iOS, macOS, tvOS and watchOS
https://docs.bugsnag.com/platforms/ios
MIT License
239 stars 130 forks source link

NSInvalidArgumentExceptionBSGURLSessionTracingProxy.m:51 #1207

Closed gonzalonunez closed 3 years ago

gonzalonunez commented 3 years ago

Describe the bug

Looks like a crash is happening from within the new network breadcrumbs plugin.

Steps to reproduce

CrashReporter Key:  d9416be80cce66b219bcc4c9ccccf351d909271f
Hardware Model:     iPad7,4
Process:            Primer
Identifier:         com.withprimer.Primer
Version:            1.7.1
Role:               Foreground
OS Version:         iOS 14.7.1

NSInvalidArgumentException: -[NSInvocation getArgument:atIndex:]: index (1) out of bounds [-1, 0]

0  CoreFoundation          -[NSInvocation getArgument:atIndex:]
1  CoreFoundation          -[NSInvocation selector]
2  Primer                  -[BSGURLSessionTracingProxy forwardInvocation:] (BSGURLSessionTracingProxy.m:51:32)
3  CoreFoundation          ____forwarding___
4  CoreFoundation          ___forwarding_prep_0___
5  CFNetwork               __CFNetworkHTTPConnectionCacheSetLimit
6  Foundation              ___NSBLOCKOPERATION_IS_CALLING_OUT_TO_A_BLOCK__
7  Foundation              -[NSBlockOperation main]
8  Foundation              ___NSOPERATION_IS_INVOKING_MAIN__
9  Foundation              -[NSOperation start]
10 Foundation              ___NSOPERATIONQUEUE_IS_STARTING_AN_OPERATION__
11 Foundation              ___NSOQSchedule_f
12 libdispatch.dylib       __dispatch_block_async_invoke2
13 libdispatch.dylib       __dispatch_client_callout
14 libdispatch.dylib       __dispatch_continuation_pop$VARIANT$mp
15 libdispatch.dylib       __dispatch_async_redirect_invoke
16 libdispatch.dylib       __dispatch_root_queue_drain
17 libdispatch.dylib       __dispatch_worker_thread2
18 libsystem_pthread.dylib __pthread_wqthread
19 libsystem_pthread.dylib _start_wqthread

Environment

Example code snippet

  private func startBugsnag() {
    let configuration = BugsnagConfiguration(bugsnagAPIKey)
    configuration.add(BugsnagNetworkRequestPlugin())
    configuration.addOnSendError { event -> Bool in
      event.setCustomContextIfNeeded()
      event.trimStacktraceIfPossible()
      return true
    }
    Bugsnag.start(with: configuration)
  }

// MARK: - BugsnagEvent

private extension BugsnagEvent {

  func setCustomContextIfNeeded() {
    guard
      let contextualError = originalError as? ContextualError,
      let customContext = contextualError.customContext
    else {
      return
    }
    context = customContext
  }

  func trimStacktraceIfPossible() {
    errors.forEach {
      $0.trimStacktraceIfPossible()
    }
  }
}

// MARK: - BugsnagError

private extension BugsnagError {

  /// Represents the number of items we need to remove from a `BugsnagError`'s `stacktrace` before reporting
  /// the error.
  ///
  /// When using `LoggingService`, there are `2` extra items in the stacktrace that we need to account for:
  /// 1. The protocol witness for LoggingService to DefaultLoggingService
  /// 2. The call to notifyError(_:)
  private static let stackTraceItemsToRemoveCount = 2

  /// Removes the first `x` items from the `stacktrace` for the receiver, where
  /// `x` is `BugsnagError.stackTraceItemsToRemoveCount`.
  func trimStacktraceIfPossible() {
    guard stacktrace.count > BugsnagError.stackTraceItemsToRemoveCount else {
      return
    }
    stacktrace.removeFirst(BugsnagError.stackTraceItemsToRemoveCount)
  }
}
nickdowell commented 3 years ago

Hi @gonzalonunez thanks for reporting this issue, it's a confusing crash to diagnose!

The exception NSInvalidArgumentException: -[NSInvocation getArgument:atIndex:]: index (1) out of bounds [-1, 0] indicates that the NSInvocation is missing a selector argument, which should not be the case for a message that has been sent to an object. Invocations generally have at least two arguments; the target object and the selector i.e. method name.

We'd like to understand how to recreate this problem or identify what sends the unexpected invocation. Have you been able to reproduce this crash?

Please let us know if you use any other SDKs in your app, and whether your app contains any "swizzling" code that uses the Objective-C runtime to alter behaviour of classes or methods, so we can investigate further. You can email us at support@bugsnag.com if you'd prefer.

gonzalonunez commented 3 years ago

Hi @nickdowell! Thanks for the quick reply :)

I haven't been able to reproduce this crash locally myself, yet – and it has only happened once from what I can tell. I'm not entirely sure where to start.

We don't swizzle any methods ourselves, but maybe Apollo, Firebase, or StreamChat do? As far as networking code goes, that's where I would start.

Any help getting to the bottom of this would be greatly appreciated! I'm happy to report bugs in the other SDKs if we can make any headway 🙏

Here's our complete Package.resolved, if that helps:

{
  "object": {
    "pins": [
      {
        "package": "abseil",
        "repositoryURL": "https://github.com/firebase/abseil-cpp-SwiftPM.git",
        "state": {
          "branch": null,
          "revision": "fffc3c2729be5747390ad02d5100291a0d9ad26a",
          "version": "0.20200225.4"
        }
      },
      {
        "package": "Segment",
        "repositoryURL": "https://github.com/segmentio/analytics-ios",
        "state": {
          "branch": null,
          "revision": "6e5dc12663a96081f375f11441f8d1a4def62aec",
          "version": "4.1.5"
        }
      },
      {
        "package": "Apollo",
        "repositoryURL": "https://github.com/apollographql/apollo-ios",
        "state": {
          "branch": null,
          "revision": "d41efb5e670ccc064e636f9b6f6def3abe517e79",
          "version": "0.42.0"
        }
      },
      {
        "package": "BoringSSL-GRPC",
        "repositoryURL": "https://github.com/firebase/boringssl-SwiftPM.git",
        "state": {
          "branch": null,
          "revision": "734a8247442fde37df4364c21f6a0085b6a36728",
          "version": "0.7.2"
        }
      },
      {
        "package": "Bugsnag",
        "repositoryURL": "https://github.com/bugsnag/bugsnag-cocoa",
        "state": {
          "branch": null,
          "revision": "5918cc9226d7f2e8128ad9ea4dc62ed84c255568",
          "version": "6.12.1"
        }
      },
      {
        "package": "Cloudinary",
        "repositoryURL": "https://github.com/cloudinary/cloudinary_ios",
        "state": {
          "branch": null,
          "revision": "8fd3da4bc4138e6e87e27fd8453b6496e28acd4e",
          "version": "3.0.1"
        }
      },
      {
        "package": "combine-schedulers",
        "repositoryURL": "https://github.com/pointfreeco/combine-schedulers",
        "state": {
          "branch": null,
          "revision": "6bde3b0063ba8e7537b43744948535ca7e9e0dad",
          "version": "0.5.2"
        }
      },
      {
        "package": "CommonMark",
        "repositoryURL": "https://github.com/SwiftDocOrg/CommonMark.git",
        "state": {
          "branch": null,
          "revision": "35718fc895ff25908628a47b44ae74aba75b6770",
          "version": "0.3.2"
        }
      },
      {
        "package": "CommonMarkAttributedString",
        "repositoryURL": "https://github.com/withprimer/CommonMarkAttributedString",
        "state": {
          "branch": null,
          "revision": "c0adfef427a1ca7723e7475bfbe1c2ff716e8328",
          "version": "0.5.3"
        }
      },
      {
        "package": "Firebase",
        "repositoryURL": "https://github.com/firebase/firebase-ios-sdk",
        "state": {
          "branch": null,
          "revision": "2f972249c520cbf87ac8856f176ebc994cb1c9a6",
          "version": "8.7.0"
        }
      },
      {
        "package": "GoogleAppMeasurement",
        "repositoryURL": "https://github.com/google/GoogleAppMeasurement.git",
        "state": {
          "branch": null,
          "revision": "4901bde146b0269da35470d261f741f0e910d8df",
          "version": "8.7.0"
        }
      },
      {
        "package": "GoogleDataTransport",
        "repositoryURL": "https://github.com/google/GoogleDataTransport.git",
        "state": {
          "branch": null,
          "revision": "7fb27ea49414b9c5483503cd06baa821c8654d1e",
          "version": "9.1.1"
        }
      },
      {
        "package": "GoogleUtilities",
        "repositoryURL": "https://github.com/google/GoogleUtilities.git",
        "state": {
          "branch": null,
          "revision": "616fac2626b6b2d1424d79a6f786b4e2ed1cfb49",
          "version": "7.5.2"
        }
      },
      {
        "package": "gRPC",
        "repositoryURL": "https://github.com/firebase/grpc-SwiftPM.git",
        "state": {
          "branch": null,
          "revision": "fb405dd2c7901485f7e158b24e3a0a47e4efd8b5",
          "version": "1.28.4"
        }
      },
      {
        "package": "GTMSessionFetcher",
        "repositoryURL": "https://github.com/google/gtm-session-fetcher.git",
        "state": {
          "branch": null,
          "revision": "bc6a19702ac76ac4e488b68148710eb815f9bc56",
          "version": "1.7.0"
        }
      },
      {
        "package": "InflectorKit",
        "repositoryURL": "https://github.com/apollographql/InflectorKit",
        "state": {
          "branch": null,
          "revision": "b1d0099abe36facd198113633f502889842906af",
          "version": "0.0.2"
        }
      },
      {
        "package": "leveldb",
        "repositoryURL": "https://github.com/firebase/leveldb.git",
        "state": {
          "branch": null,
          "revision": "0706abcc6b0bd9cedfbb015ba840e4a780b5159b",
          "version": "1.22.2"
        }
      },
      {
        "package": "nanopb",
        "repositoryURL": "https://github.com/firebase/nanopb.git",
        "state": {
          "branch": null,
          "revision": "7ee9ef9f627d85cbe1b8c4f49a3ed26eed216c77",
          "version": "2.30908.0"
        }
      },
      {
        "package": "Nuke",
        "repositoryURL": "https://github.com/kean/Nuke.git",
        "state": {
          "branch": null,
          "revision": "0db18dd34998cca18e9a28bcee136f84518007a0",
          "version": "10.4.1"
        }
      },
      {
        "package": "PathKit",
        "repositoryURL": "https://github.com/kylef/PathKit.git",
        "state": {
          "branch": null,
          "revision": "73f8e9dca9b7a3078cb79128217dc8f2e585a511",
          "version": "1.0.0"
        }
      },
      {
        "package": "Promises",
        "repositoryURL": "https://github.com/google/promises.git",
        "state": {
          "branch": null,
          "revision": "611337c330350c9c1823ad6d671e7f936af5ee13",
          "version": "2.0.0"
        }
      },
      {
        "package": "Purchases",
        "repositoryURL": "https://github.com/RevenueCat/purchases-ios",
        "state": {
          "branch": null,
          "revision": "b7e38906f3290f19b2396dd5665b13d05c8e672a",
          "version": "3.12.4"
        }
      },
      {
        "package": "SDWebImage",
        "repositoryURL": "https://github.com/SDWebImage/SDWebImage",
        "state": {
          "branch": null,
          "revision": "76dd4b49110b8624317fc128e7fa0d8a252018bc",
          "version": "5.11.1"
        }
      },
      {
        "package": "SDWebImageSwiftUI",
        "repositoryURL": "https://github.com/SDWebImage/SDWebImageSwiftUI",
        "state": {
          "branch": null,
          "revision": "4c7f169e39bc35d6b80d42b8eb8301bee9cd0907",
          "version": "1.5.0"
        }
      },
      {
        "package": "Spectre",
        "repositoryURL": "https://github.com/kylef/Spectre.git",
        "state": {
          "branch": null,
          "revision": "f79d4ecbf8bc4e1579fbd86c3e1d652fb6876c53",
          "version": "0.9.2"
        }
      },
      {
        "package": "SQLite.swift",
        "repositoryURL": "https://github.com/stephencelis/SQLite.swift.git",
        "state": {
          "branch": null,
          "revision": "0a9893ec030501a3956bee572d6b4fdd3ae158a1",
          "version": "0.12.2"
        }
      },
      {
        "package": "Stencil",
        "repositoryURL": "https://github.com/stencilproject/Stencil.git",
        "state": {
          "branch": null,
          "revision": "973e190edf5d09274e4a6bc2e636c86899ed84c3",
          "version": "0.14.1"
        }
      },
      {
        "package": "StreamChat",
        "repositoryURL": "https://github.com/GetStream/stream-chat-swift.git",
        "state": {
          "branch": null,
          "revision": "92cb8b079b1e74364c3a7ed3aaded6ff4b9e88f6",
          "version": "4.0.1"
        }
      },
      {
        "package": "swift-case-paths",
        "repositoryURL": "https://github.com/pointfreeco/swift-case-paths",
        "state": {
          "branch": null,
          "revision": "d226d167bd4a68b51e352af5655c92bce8ee0463",
          "version": "0.7.0"
        }
      },
      {
        "package": "cmark",
        "repositoryURL": "https://github.com/SwiftDocOrg/swift-cmark.git",
        "state": {
          "branch": null,
          "revision": "9c8096a23f44794bde297452d87c455fc4f76d42",
          "version": "0.29.0+20210102.9c8096a"
        }
      },
      {
        "package": "swift-collections",
        "repositoryURL": "https://github.com/apple/swift-collections",
        "state": {
          "branch": null,
          "revision": "07e47b1e93e5a1e0ef0c50fcb2d6739fb6be4003",
          "version": "1.0.0"
        }
      },
      {
        "package": "swift-composable-architecture",
        "repositoryURL": "https://github.com/pointfreeco/swift-composable-architecture",
        "state": {
          "branch": null,
          "revision": "a1aac6cfd654051d0ab5e626462afff36c399219",
          "version": "0.27.1"
        }
      },
      {
        "package": "swift-custom-dump",
        "repositoryURL": "https://github.com/pointfreeco/swift-custom-dump",
        "state": {
          "branch": null,
          "revision": "1a2947d25d43e295c6f5e83f54696d590620b364",
          "version": "0.1.3"
        }
      },
      {
        "package": "swift-identified-collections",
        "repositoryURL": "https://github.com/pointfreeco/swift-identified-collections",
        "state": {
          "branch": null,
          "revision": "c8e6a40209650ab619853cd4ce89a0aa51792754",
          "version": "0.3.0"
        }
      },
      {
        "package": "SwiftProtobuf",
        "repositoryURL": "https://github.com/apple/swift-protobuf.git",
        "state": {
          "branch": null,
          "revision": "1f62db409f2c9b0223a3f68567b4a01333aae778",
          "version": "1.17.0"
        }
      },
      {
        "package": "SwiftyGif",
        "repositoryURL": "https://github.com/kirualex/SwiftyGif.git",
        "state": {
          "branch": null,
          "revision": "0cd770feed5807d9fd4fa8df5ad74b56b814b0c8",
          "version": "5.4.0"
        }
      },
      {
        "package": "Valet",
        "repositoryURL": "https://github.com/Square/Valet",
        "state": {
          "branch": null,
          "revision": "7447d1661d938643b0004084367e7bdcb94fdcc4",
          "version": "3.2.8"
        }
      },
      {
        "package": "xctest-dynamic-overlay",
        "repositoryURL": "https://github.com/pointfreeco/xctest-dynamic-overlay",
        "state": {
          "branch": null,
          "revision": "50a70a9d3583fe228ce672e8923010c8df2deddd",
          "version": "0.2.1"
        }
      }
    ]
  },
  "version": 1
}
nickdowell commented 3 years ago

Thanks @gonzalonunez for the detailed information :-)

We have not yet been able to reproduce the issue either, but have made some defensive changes to our code that should prevent it happening in the future

We will be releasing a new version with this and other fixes next week.

If you do happen to encounter this crash with a debugger attached, it would be very useful to capture as much as possible about the NSMethodSignature including the number of arguments and their type encodings.

gonzalonunez commented 3 years ago

@nickdowell This is great news, thank you! I'll let you know if I'm able to reproduce this in the meantime. Looking forward to the next release :)

luke-belton commented 3 years ago

Hi @gonzalonunez - just to let you know the changes mentioned above were released in v6.14.1 of bugsnag-cocoa 🎉

I'm going to close this issue for now but if you have anything further to add or encounter this crash again in the future then please feel free to re-open! Thanks again for reporting it 😃

gonzalonunez commented 3 years ago

@luke-belton Awesome! Thank you for letting me know – will do!

gonzalonunez commented 3 years ago

Hey @luke-belton!

If it's helpful, I just reproduced this crash locally (on the same old version of Bugsnag). It happens 100% of the time when I present a UIActivityViewController for our App Store URL:

"https://apps.apple.com/us/app/apple-store/id1517900736".
gonzalonunez commented 3 years ago

@luke-belton Just confirmed that it doesn't occur for this case on the latest version. Thanks again!

nickdowell commented 3 years ago

Thanks @gonzalonunez - presenting a UIActivityViewController with https://apps.apple.com/us/app/apple-store/id1517900736 reproduces the crash 100% for us too, and has allowed us to verify our fix 👍

UIActivityViewController performs some network requests with a AMSURLDelegateProxy instance as the session's delegate.

AMSURLDelegateProxy is a proxy (similar to ours) which for some reason only known by Apple returns method signatures with too few arguments. Its implementation of forwardInvocation: must be expecting these invalid looking signatures.

Putting a breakpoint on -[AMSBagNetworkTask URLSession:dataTask:didReceiveResponse:completionHandler:] (which is the proxy's target) confirms that the method gets invoked successfully when using v6.14.1 - so everything is now working as expected with our fix in place 👍

gonzalonunez commented 3 years ago

Wow! Thank you for the thorough investigation and the quick turnaround 🙏🏻