Non-local jump via setjmp/longjmp
ID |
objectivec.maintainability.setjmp_longjmp |
Severity |
info |
Remediation Complexity |
hard |
Remediation Risk |
high |
Remediation Effort |
medium |
Resource |
Control Flow |
Language |
Objective-C |
Rationale
A longjmp transfers control straight to the matching setjmp point, unwinding every stack frame in between without running their cleanup. In Objective-C that is not merely untidy: ARC emits the release of every strong local at the end of its scope, and a jump past those points leaks each one, drains no autorelease pool, runs no @finally block and unlocks no @synchronized region. The resulting control flow is also invisible at the call site, which makes it very hard to trace and to test.
The following code illustrates the pattern detected by this rule:
@implementation ImageDecoder
- (BOOL)decodeData:(NSData *)data {
// FLAGGED: Non-local jump via setjmp/longjmp
if (setjmp(gRecoveryPoint)) {
return NO;
}
[self parseChunks:data];
return YES;
}
@end
Remediation
Replace the jump with ordinary structured control flow: return NO or nil together with an NSError ** out-parameter and let each caller handle the failure. Where a C library insists on a jump-based error path - libjpeg and libpng are the usual cases - confine setjmp to the smallest possible C wrapper function that owns no Objective-C objects, and convert the failure into an NSError before returning.