Debugging NSInvocation Out‑of‑Bounds Crash After iOS 13.3 Upgrade
This article analyzes a crash caused by NSInvocation argument out‑of‑bounds on iOS 13.3+, explains the underlying runtime changes, demonstrates how to reproduce the issue with a timer‑triggered message forwarding scenario, and provides a fix by correcting the method signature.
Apple updates iOS each year, sometimes altering system libraries in ways that break existing code. After upgrading to iOS 13.3, a project experienced a crash where an NSInvocation call caused an array‑bounds error due to an incorrect method signature.
Problem Overview : The crash occurs only on devices running iOS 13.3 or later, and the stack trace points to internal NSInvocation handling.
Crash Exception :
'NSInvalidArgumentException', reason: '-[NSInvocation getArgument:atIndex:]: index (0) out of bounds [-1, -1]'Simplified Crash Stack :
1 _GSEventRunModal(main thread runloop wakeup)
2 __NSFireTimer
3 _CF_forwarding_prep_0
4 +[NSInvocation _invocationWithMethodSignature:frame:]
5 _NSIGetArgumentAtIndex
6 _objc_exception_throwSuspicious Points :
Why does message forwarding occur?
Why does NSInvocation access an out‑of‑bounds argument?
The analysis shows that the timer’s target implements a methodSignatureForSelector: that returns an empty signature when the selector is not implemented, leading to the out‑of‑bounds access.
Implementation of methodSignatureForSelector:
// Return method signature
- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector {
NSMethodSignature *signature = [self.target methodSignatureForSelector:selector];
if (!signature) {
signature = [NSMethodSignature signatureWithObjCTypes:"v"];
}
return signature;
}When the timer invokes an unimplemented method, the second branch returns a signature with only the return type "v" , missing the required @ (self) and : (selector) arguments. Consequently, NSInvocation’s argument array lacks the expected entries, and accessing index 0 triggers the crash.
Fix : Provide a proper method signature that includes the hidden arguments.
[NSMethodSignature signatureWithObjCTypes:"v@:"];After updating the signature, the crash disappears. The fix aligns with Objective‑C’s messaging convention where every method implicitly receives self and _cmd (selector), represented by @ and : in the type encoding.
For reference, the low‑level message send function is:
objc_msgSend(id _Nullable self, SEL _Nonnull op, ...)Runtime Analysis Steps :
Collect valuable information from the crash log.
Identify suspicious areas (message forwarding and argument out‑of‑bounds).
Hypothesize and simulate the scenario by creating a demo timer that calls an unimplemented selector.
Use a symbolic breakpoint on methodSignatureForSelector to inspect the returned signature.
Modify the signature to include @: and verify the crash is resolved.
Summary : The root cause was an empty method signature returned by a custom timer category, causing NSInvocation to read beyond its argument array. Adding the correct type encoding fixes the issue, highlighting the importance of accurate runtime method signatures when dealing with dynamic message forwarding.
Sohu Tech Products
A knowledge-sharing platform for Sohu's technology products. As a leading Chinese internet brand with media, video, search, and gaming services and over 700 million users, Sohu continuously drives tech innovation and practice. We’ll share practical insights and tech news here.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.