sequelpro / sequelpro

MySQL/MariaDB database management for macOS
https://sequelpro.com/
Other
9.05k stars 841 forks source link

Use after free in _isSearchingAsynchronousDocument #2492

Open dmoagx opened 8 years ago

dmoagx commented 8 years ago

This is a longstanding (back to 1.0.2) random exception/crash issue that seems to have been overlooked previously. Usually we see 3-10 occurrences/day.

Pattern (multiple exist):

NSInvalidArgumentException

-[__NSArrayI _isSearchingAsynchronousDocument]: unrecognized selector sent to instance 0x12b103590

(
    0   CoreFoundation                      0x00007fff963a94f2 __exceptionPreprocess + 178
    1   libobjc.A.dylib                     0x00007fff83993f7e objc_exception_throw + 48
    2   CoreFoundation                      0x00007fff964131ad -[NSObject(NSObject) doesNotRecognizeSelector:] + 205
    3   CoreFoundation                      0x00007fff96319571 ___forwarding___ + 1009
    4   CoreFoundation                      0x00007fff963190f8 _CF_forwarding_prep_0 + 120
    5   AppKit                              0x00007fff933930c8 -[_NSTextFinderImpl _noteClientStringWillChange] + 98
    6   AppKit                              0x00007fff9339278b -[NSTextFinder setClient:] + 73
    7   AppKit                              0x00007fff930fcc85 -[NSTextView _updateTextFinder] + 167
    8   AppKit                              0x00007fff93435588 -[NSTextView _textViewFinder] + 316
    9   AppKit                              0x00007fff93435391 -[NSTextView(NSSharing) setPreferredTextFinderStyle:] + 101
    10  Sequel Pro                          0x00000001000b1e95 -[SPFieldEditorController init] + 389
    11  Sequel Pro                          0x000000010000bdc0 -[SPCustomQuery tableView:shouldEditTableColumn:row:] + 432
    12  AppKit                              0x00007fff937333e3 -[NSTableView _userCanEditTableColumn:row:] + 163
    13  AppKit                              0x00007fff93733454 -[NSTableView _userCanSelectAndEditTableColumn:row:] + 95
    14  AppKit                              0x00007fff9373b20e -[NSTableView _internalShouldEditColumn:row:withEvent:] + 92
    15  AppKit                              0x00007fff9373b503 -[NSTableView _shouldEditColumn:row:withEvent:ignoringSelection:] + 68
    16  AppKit                              0x00007fff9332e81d -[NSTableView mouseDown:] + 5574
    17  AppKit                              0x00007fff93802469 -[NSWindow _handleMouseDownEvent:isDelayedEvent:] + 6322
    18  AppKit                              0x00007fff9380344d -[NSWindow _reallySendEvent:isDelayedEvent:] + 212
    19  AppKit                              0x00007fff9324263d -[NSWindow sendEvent:] + 517
    20  Sequel Pro                          0x000000010012e644 -[SPWindow sendEvent:] + 783
    21  AppKit                              0x00007fff931c2b3c -[NSApplication sendEvent:] + 2540
    22  AppKit                              0x00007fff93029ef6 -[NSApplication run] + 796
    23  AppKit                              0x00007fff92ff346c NSApplicationMain + 1176
    24  Sequel Pro                          0x0000000100002454 start + 52
)

(most popular reports, only the exception cases):

http://log.sequelpro.com/view/5538 http://log.sequelpro.com/view/3689 (misgrouped) http://log.sequelpro.com/view/5165 http://log.sequelpro.com/view/3161 (misgrouped) http://log.sequelpro.com/view/3680 (misgrouped) http://log.sequelpro.com/view/5124 (misgrouped) http://log.sequelpro.com/view/3959 (misgrouped) http://log.sequelpro.com/view/3528 (misgrouped) http://log.sequelpro.com/view/3429 (misgrouped) http://log.sequelpro.com/view/3622 (misgrouped)

dmoagx commented 8 years ago

Here is a trace up to the point in the exception:

[SPFieldEditorController init]
    [NSTextView(NSSharing) setUsesFindBar:YES] (SPEditSheetTextView *editTextView)
        [NSTextView(NSSharing) setPreferredTextFinderStyle:] (self)
            [NSTextView _textViewFinder] (self)
                [NSTextView isFieldEditor] (self)
                [NSTextView(NSSharing) usesFindBar] (self)
                    [NSTextView(NSSharing) preferredTextFinderStyle] (self)
                NSTextViewSharedData._textFinder = [[NSTextFinder alloc] init]
                [NSTextFinder setPreferredTextFinderStyle:] (NSTextFinder *_textFinder)
                [NSTextView(NSSharing) isIncrementalSearchingEnabled] (self)
                [NSTextFinder setIncrementalSearchingEnabled:] (_textFinder)
                [NSTextFinder setIncrementalSearchingShouldDimContentView:] (_textFinder)
                [NSTextView _updateTextFinder] (self)
                    [NSLayoutManager firstTextView] (NSTextViewIvars.layoutManager)
                    [NSTextFinder setClient:] (_textFinder)
                        [NSTextFinder _textFinderImplCreate:] (self)
                            +[NSTextFinder activeStyle]
                                +[NSFindPanel _isLoaded]
                            [NSTextFinder preferredTextFinderStyle] (self)
                            [NSTextFinder _textFinderForStyle:create:] (self)
                                [NSMapTable objectForKey:] (global NSMapTable *_sharedBarFinders)
                                {
                                    [[_NSBarTextFinder alloc] init]
                                    [NSMapTable setObject:forKey:]
                                    [_NSBarTextFinder release]
                                }
                                [nil isVisible]
                                +[NSTextFinder _globalTextFinder]
                        [_NSGlobalTextFinder<inherited from _NSTextFinderImpl> _noteClientStringWillChange]
                            [nil stopSearchingAndWait:] (_NSTextFinderImpl._asyncSearch)
                            [nil release]
                            [nil _isSearchingAsynchronousDocument] (_NSTextFinderImpl._finder)

What's interesting here is that _isSearchingAsynchronousDocument is usually called on a nil.

However, when opening the find panel for the Query Editor (and leaving it open) and then opening the sheet editor it is != nil and Sequel Pro crashes once I close the sheet again. That is a different issue, though: http://log.sequelpro.com/view/5850

dmoagx commented 8 years ago

Events that cause this crash/exception:

dmoagx commented 7 years ago

There is another crash that may be related to this:

Application Specific Information:
objc_msgSend() selector name: respondsToSelector:

Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
0   libobjc.A.dylib                 0x00007fffd5b38b5d objc_msgSend + 29
1   com.apple.AppKit                0x00007fffbf4059ed -[NSFindPanel windowDidUpdate:] + 454
2   com.apple.CoreFoundation        0x00007fffc0ee8a6c __CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ + 12
3   com.apple.CoreFoundation        0x00007fffc0ee896b _CFXRegistrationPost + 427
4   com.apple.CoreFoundation        0x00007fffc0ee86d2 ___CFXNotificationPost_block_invoke + 50
5   com.apple.CoreFoundation        0x00007fffc0ea5d63 -[_CFXNotificationRegistrar find:object:observer:enumerator:] + 1827
6   com.apple.CoreFoundation        0x00007fffc0ea4d9c _CFXNotificationPost + 604
7   com.apple.Foundation            0x00007fffc28cba37 -[NSNotificationCenter postNotificationName:object:userInfo:] + 66
8   com.apple.CoreFoundation        0x00007fffc0ef2c60 -[NSArray makeObjectsPerformSelector:] + 272
9   com.apple.AppKit                0x00007fffbea07f98 -[NSApplication(NSWindowCache) _updateWindowsUsingCache] + 565
10  com.apple.AppKit                0x00007fffbea06992 -[NSApplication updateWindows] + 80
11  com.apple.AppKit                0x00007fffbee3e777 __38-[NSApplication setWindowsNeedUpdate:]_block_invoke.2372 + 68
12  com.apple.CoreFoundation        0x00007fffc0ef2397 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 23
13  com.apple.CoreFoundation        0x00007fffc0ef2307 __CFRunLoopDoObservers + 391
14  com.apple.CoreFoundation        0x00007fffc0ed2f39 __CFRunLoopRun + 873
15  com.apple.CoreFoundation        0x00007fffc0ed2974 CFRunLoopRunSpecific + 420
16  com.apple.HIToolbox             0x00007fffc045ea5c RunCurrentEventLoopInMode + 240
17  com.apple.HIToolbox             0x00007fffc045e799 ReceiveNextEventCommon + 184
18  com.apple.HIToolbox             0x00007fffc045e6c6 _BlockUntilNextEventMatchingListInModeWithFilter + 71
19  com.apple.AppKit                0x00007fffbea045b4 _DPSNextEvent + 1120
20  com.apple.AppKit                0x00007fffbf17ed6b -[NSApplication(NSEvent) _nextEventMatchingEventMask:untilDate:inMode:dequeue:] + 2789
21  com.apple.AppKit                0x00007fffbe9f8f35 -[NSApplication run] + 926
22  com.apple.AppKit                0x00007fffbe9c3850 NSApplicationMain + 1237
23  com.sequelpro.SequelPro         0x0000000100002454 start + 52

The code in the windowDidUpdate: method looks like this on 10.9:

// ...
id sharedFinder = [NSTextFinder _sharedPanelTextFinder];
id obj;
if([[sharedFinder _finder] respondsToSelector:@selector(textObjectToSearchIn)]) // <---
    obj = [[sharedFinder _finder] textObjectToSearchIn];
else
    obj = [NSTextFinder _actionResponder];

if(obj && [obj respondsToSelector:@selector(validateUserInterfaceItem:)])
    //...
dmoagx commented 7 years ago

I found a way to reproduce the crash in -[NSFindPanel windowDidUpdate:]:

This also works with other text views that still use the find panel, so we should probably switch all of them to the find bar and additionally hide it before closing the window.