Hello all,

I’ve discovered a bug that’s causing crashes when Swift code interoperates with 
AppKit in a certain way. I intend to file a bug report, but I’m not sure 
whether the bug should be filed as a Swift bug, or as an AppKit bug since a 
case could probably be made for either, and I thought I would ask the list 
first.

What’s happening, basically, is that when an NSTextFieldCell subclass contains 
Objective-C-compatible reference-type properties, and is loaded from a .nib 
file in which its containing text field has its Baseline aligned to some other 
object via autolayout, its properties get over-released when the cell is 
deallocated. A simple example that will cause the crash is:

@objc(Foo) class Foo: NSObject {}

@objc(CustomTextFieldCell) class CustomTextFieldCell: NSTextFieldCell {
    let foo = Foo()
}

The equivalent code in Objective-C works properly and does not crash:

#import <Cocoa/Cocoa.h>

@interface Foo: NSObject
@end

@implementation Foo
@end

@interface CustomTextFieldCell: NSTextFieldCell

@property (nonatomic, strong) Foo *foo;

@end

@implementation CustomTextFieldCell

- (instancetype)initWithCoder:(NSCoder *)coder {
    self->_foo = [Foo new];
    
    return [super initWithCoder:coder];
}

@end

The problem seems to occur, as far as I can tell, because when the Baseline 
layout relation is applied, AppKit copies the text field’s cell. Subsequently, 
NSCell’s -copyWithZone: method calls NSCopyObject, which in turn calls a 
private function named “fixUpCopiedIvars.” With an Objective-C cell class, 
fixUpCopiedIvars calls class_getIvarLayout, and retains all its instance 
variables, so both the original cell and the copy have an owning reference to 
all of them. This retain is then balanced by a release when the cell is 
deallocated. With a Swift cell class, however, class_getIvarLayout returns 
NULL, so the ivars are never retained; however, this nonexistent retain is 
still balanced by a release when the cell is deallocated. The result is that 
the program accesses freed memory, leading to a crash or worse.

A sample project demonstrating all this is here: 
http://www.charlessoft.com/bug_examples/Crash_Swiftly.zip

So, there’s clearly a bug here, but I’m not sure which of these three 
possibilities is correct:

- This is a bug in AppKit, because NSCell should not be using the deprecated 
NSCopyObject or assuming that class_getIvarLayout will work.

- This is a bug in the Swift<->Objective-C bridge, because Swift can be used to 
write Objective-C objects, and legacy Objective-C code like NSCopyObject that 
interacts with said objects may assume that it can access instance variables 
via class_getIvarLayout; thus, the latter should work.

- Or option 3: The Swift team considers it to be a bug in AppKit, and the 
AppKit team considers this to be a bug in Swift, or maybe the Foundation team 
gets involved to make this into a triangle. This is obviously the worst-case 
scenario. ;-)

What does the community think? Should I file this as a bug on Swift? 
Foundation? AppKit? All three?

Thanks,
Charles

_______________________________________________
swift-users mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-users

Reply via email to