|Home » Learning Curve » Developers Workshop
Bug Reports & Core Rot
When systemic crashes become expected behaviour.
Not many people seem to understand NSOutlineView, particularly those still saddled with its maintenance at One Infinite Loop. And worse still is the insouciance shown to bug reports today.
One gets uncomfortable flashbacks to the day OS X 10.5 was introduced, when the Apple bug reporting team, saddled with more and more tickets as Scott Forstall's 'chosen' were migrated to the iPhone project, suddenly chucked up all the remaining tickets and told everyone to purchase Leopard instead.
That approach was at least honest and intelligent. The number of bug reports was overwhelming. Apple didn't have the resources to deal with them, and had these difficulties already during the development of 10.4 Tiger when the iPhone project was born.
But today Apple are supposed to be bringing iOS back to OS X, although save for a few obviously useful features, the point of it all escapes the great majority.
A question remains however. Almost more a riddle than a question, in that it defies human logic: how can they take a piece of perfectly good code that's stood the test of time - of ten years or more - and then through sheer stupidity ruin it?
Apple's NSOutlineView, legacy from OpenStep and NeXTSTEP, is a Cocoa code class built atop NSTableView. Its primary claim to fame is the flippy triangle most often seen in the leftmost column - NSOutlineView can be hierarchical.
Most of the code of NSOutlineView is of course inherited from NSTableView. And that is as it should be. The architecture of these 'NeXTSTEP' classes is nigh on perfect, truly a paragon in computer science, something the Pascal programmers at Apple 'inherited' watery-eyed from their NeXT brethren.
As with NSTableView, it's possible to both drag from and drag to NSOutlineView and effect drops. Drops are made possible through the NSOutlineViewDataSource protocol. (The 'data source' part of that name is actually key, so keep it in mind.)
acceptDrop:(id < NSDraggingInfo >)info
The above is an early indication for a client that an attempt is made to drop something on an NSOutlineView. The call tells the client which outline view is involved, passes along additional information, indicates which item in the view is being targeted, and because NSOutlineView is hierarchical, also indicates which child item is involved. The client responds with either a YES or a NO to allow or disallow the drop.
The actual drag part of the operation is handled independently by NSOutlineView. As the dragged item comes into contact with items in the outline view, those items expand if they can. The outline view determines whether they can be expanded by asking a question in turn of the client.
-(BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item
The item passed in this call is an item already owned by the client. The outline view is asking if the item is expandable, and a simple YES or NO will do nicely, thank you. The outline view also queries the client about the number of children to a particular item, so it knows how to populate its view, and finally it will ask for data for each item to be displayed.
Simple enough? Indeed. And then a curious thing happened. A curious twist of bizarre fate came along with the introduction of OS X 10.7. Suddenly, after ten years of flawless behaviour - actually longer still, as the code existed and ran well in Redwood City years before it came to Apple - the code became flawed. For no fathomable reason.
All the while Apple's iOS programmers slaved away on their famed products and Apple promised at long last to revitalise the dormant OS X.
Suddenly the data being sent in the above calls by NSOutlineView - data generated by Apple's own code - was utter rubbish.
The item values sent - those values that tell the client which NSOutlineView items the calls are about - were garbage values. And any client responding to such calls from Apple's code would of course go pear-shaped.
The curious part of this pernicious bug was that the garbage values were only generated whilst the outline view was still expanding. Garbage values were not sent to clients for items that could not be expanded, and garbage values were not sent to clients for items whose children had already been expanded. Garbage was only sent when the NSOutlineView was simultaneously still in the process of expanding.
The workaround, once this fact was determined and the bug was 100% reproducible, was of course straightforward. The client of course cannot check for the validity of an item object, as merely accessing a garbage value will cause the application to go south. The client can instead check for how the expansion is going.
The client, if impatient, can also attempt to speed things along by telling the outline view to get a move on and expand.
The important thing is that the client can only proceed when it knows that the data sent by Apple's code will no longer be bogus and cause a crash.
A bug report was submitted in good faith, in the belief that such a woeful error could and would be swiftly taken care of.
Applications using NSOutlineView which also permit drops on this view, where the items in the view can have children, will experience an unavoidable crash when drops are made before the outline view has a chance to expand its child items.
Steps to Reproduce:
Create an application using NSOutlineView and another view which can drop objects on the outline view. See that the top level items in the NSOutlineView have children. Drop objects on this view, waiting for the items in NSOutlineView to expand. This will be fine. Drop them without waiting for the items to expand and you will get an irrevocable crash.
Expected results are as with every version of OS X up to Lion, all the way back to 10.2 ten years ago. The drop should of course work without a crash.
Of course one must keep the 'band-aid' code in place anyway, as Apple will rarely fix bugs retroactively, even if they do get around to addressing an issue (which more and more is unlikely these days).
Apple finally looked at the bug seven months later. Their response is under NDA, as they say. Here's a serious bug in their own code, people can warn others of its existence, but people must absolutely not tell anyone how Apple responded.
Was the bug fixed? No. This is verifiable by independent test code.
Our engineers are aware of the issue and have determined that the issue behaves as intended.
That line caught a number of people off guard.
A crash is 'behaves as intended'?????? Who are they f**king kidding? How can they genuinely keep a straight face when writing a response like that???
But it gets worse. For in an addendum to Apple's response, an anonymous engineer deigned to educate - and put the proverbial foot in the all too real gaping mouth.
Trying to explain that the bug concerned an 'all too common misunderstanding' about NSOutlineView, Mr Anon pointed out that objects sent by NSOutlineView are not retained.
But an outline view with a data source isn't creating any objects of its own in these circumstances - it's using (sending) objects already owned by the client. The client is the data source. (Remember the NSOutlineViewDataSource protocol from above?)
There's nothing for the NSOutlineView or the client to retain - the data source (the client) has long since retained it.
But Apple get off cheaply because so few applications use NSOutlineView in this way. Apple's file I/O ('open', 'save as') sheets could do it but don't. As but just one example.
Out of sight, out of mind.
2013 and Beyond
Some are calling it 'core rot': the condition by which the key functionality of OS X is slowly eaten away because, ultimately, Apple are too busy with iOS to give a damn what happens to OS X, and the programmers left behind after Scott Forstall recruited the iOS groups simply don't have the wherewithal, in terms of either basic user skills or knowledge of the Cocoa classes, to maintain OS X code without ruining something already there.
I just found this blog post and it sort of voices a few of my own gripes. Thought I'd post it here so as to get a discussion going and hoping that Apple will somehow take notice.
Over the past few years a semi-conscious unease has been steadily growing in my mind: OS X is not getting more reliable and more stable, it is instead developing more and nastier problems that range from interference with getting work done to potential data loss.
People will always disagree on what exactly makes them uneasy (or whether they should feel uneasy) but a growing number are noticing the trend.
Seeing Apple declare bugs that unavoidably cause crashes 'behaves as intended' makes the trend hard to miss.