Same issue in Objective-C
#import <Foundation/Foundation.h>
@interface Chained: NSObject
@property Chained* next;
@end
@implementation Chained
- (void)dealloc {
static int n = 0;
if ((n % 1000) == 0) {
NSLog(@"dealloc %d", n);
}
n += 1;
}
@end
void test(void) {
NSLog(@"building...");
Chained* first = [Chained new];
Chained* last = first;
int n = 100000; // 1000000 for release mode
for (int i = 1; i < n; i++) {
Chained* next = [Chained new];
last.next = next;
last = next;
}
last = nil;
NSLog(@"forgetting references...");
first = nil;
/*
Thread sanitizer, running outside Xcode
2022-02-02 00:20:23.496 StackOverflow[15381:446319] dealloc 30000
2022-02-02 00:20:24.229 StackOverflow[15381:446319] dealloc 31000
2022-02-02 00:20:24.980 StackOverflow[15381:446319] dealloc 32000
ThreadSanitizer:DEADLYSIGNAL
==15381==ERROR: ThreadSanitizer: stack-overflow on address 0x7ffee22edff8 (pc 0x00010d13a21c bp 0x7ffee22ee020 sp 0x7ffee22ee000 T446319)
*/
/*
No thread sanitizer:
2022-02-02 00:21:45.604 StackOverflow[15425:447543] dealloc 38000
2022-02-02 00:21:45.605 StackOverflow[15425:447543] dealloc 39000
2022-02-02 00:21:45.605 StackOverflow[15425:447543] dealloc 40000
Segmentation fault: 11
*/
/*
release mode:
2022-02-02 00:22:29.130 StackOverflow[15478:448365] dealloc 45000
2022-02-02 00:22:29.130 StackOverflow[15478:448365] dealloc 46000
2022-02-02 00:22:29.130 StackOverflow[15478:448365] dealloc 47000
Segmentation fault: 11
*/
NSLog(@"done");
}
int main(int argc, const char * argv[]) {
@autoreleasepool {
test();
}
return 0;
}
Ditto for the manual reference counted version (different number of deallocations until crash)
specify -fno-objc-arc for this file in build phases
#import <Foundation/Foundation.h>
@interface Chained: NSObject {
@public
Chained* next;
}
@end
@implementation Chained
- (void)dealloc {
static int n = 0;
if ((n % 1000) == 0) {
NSLog(@"dealloc %d", n);
}
n += 1;
Chained* next = self->next;
[super dealloc];
[next release];
}
@end
void test(void) {
NSLog(@"building...");
Chained* first = [Chained new];
Chained* last = first;
int n = 1000000;
for (int i = 1; i < n; i++) {
Chained* next = [Chained new];
last->next = next;
last = next;
}
last = nil;
NSLog(@"forgetting references...");
[first release];
/*
Thread sanitizer, running outside Xcode
2022-02-02 00:38:59.498 StackOverflow[15633:461353] dealloc 67000
2022-02-02 00:38:59.922 StackOverflow[15633:461353] dealloc 68000
2022-02-02 00:39:00.358 StackOverflow[15633:461353] dealloc 69000
2022-02-02 00:39:00.808 StackOverflow[15633:461353] dealloc 70000
ThreadSanitizer:DEADLYSIGNAL
ThreadSanitizer:DEADLYSIGNAL
ThreadSanitizer: nested bug in the same thread, aborting.
*/
/*
No thread sanitizer:
2022-02-02 00:40:15.630 StackOverflow[15722:463283] dealloc 126000
2022-02-02 00:40:15.630 StackOverflow[15722:463283] dealloc 127000
2022-02-02 00:40:15.630 StackOverflow[15722:463283] dealloc 128000
2022-02-02 00:40:15.630 StackOverflow[15722:463283] dealloc 129000
2022-02-02 00:40:15.631 StackOverflow[15722:463283] dealloc 130000
Segmentation fault: 11
*/
/*
release mode:
2022-02-02 00:40:47.407 StackOverflow[15765:463962] dealloc 171000
2022-02-02 00:40:47.407 StackOverflow[15765:463962] dealloc 172000
2022-02-02 00:40:47.408 StackOverflow[15765:463962] dealloc 173000
2022-02-02 00:40:47.408 StackOverflow[15765:463962] dealloc 174000
Segmentation fault: 11
*/
NSLog(@"done");
}
int main(int argc, const char * argv[]) {
@autoreleasepool {
test();
}
return 0;
}
I wonder how did we not notice it before.. No Objective-C user was using linked lists with 30-100K elements in the last 38 years? ![]()