gnustep / libobjc2

Objective-C runtime library intended for use with Clang.
http://www.gnustep.org/
MIT License
434 stars 118 forks source link

Possible BOOL ivars offset problem #96

Closed trunkmaster closed 5 years ago

trunkmaster commented 5 years ago

It looks like this GNUstep GUI pull request https://github.com/gnustep/libs-gui/pull/23 try to solve problem that lays out of GNUstep source code. It can be the sign of some clang/libobjc2 problem. Can you check it, please?

triplef commented 5 years ago

FWIW, we saw what I think might have been a similar crash (SIGBUS / BUS_ADRALN) when assigning certain Objective C member variables in some of our classes, but this was only when using the 2.0 ABI (1.9 worked fine). However the libs-gui issue seems to be using the 1.8 ABI.

Unfortunately I was unable to reproduce the issue with a reduced test class outside our app, and we ultimately switched to the 1.9 ABI due to #90.

trunkmaster commented 5 years ago

Maybe... But I've patched my clang as David suggested in #90. And yes, libs-gui and applications was built with -fobjc-runtime=gnustep-1.8 option. -fobjc-runtime=gnustep-2.0 doesn't work for me - it's a subject for separate issue. Moreover, libs-gui applications stops segfaulting if BOOL type (unsigned char) changed to int without moving ivars declarations.

davidchisnall commented 5 years ago

Is this still an issue with the latest clang? There was an issue related to bool ivars having their metadata incorrectly initialised. If there's a test case, I can try to debug it.

trunkmaster commented 5 years ago

Do you mean clang 8.0? I've just built 7.0 and no 8.0 yet. Test case is simple: if you have libs-gui and some application with GUI, set GSX11HandlesWindowDecorations to NO and run it. For example, application named "TextEdit":

$ defaults write TextEdit GSX11HandlesWindowDecorations NO
$ openapp TextEdit
zsh: segmentation fault  openapp TextEdit
$ gdb /Applications/TextEdit.app/TextEdit
(gdb) r
Starting program: /Applications/TextEdit.app/TextEdit
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff710dae6 in -[GSStandardWindowDecorationView updateRects] (self=0xfeff18,
    _cmd=0x7ffff75d2980 <.objc_selector_list+832>) at GSStandardWindowDecorationView.m:98
98        if (hasTitleBar)
(gdb) bt
#0  0x00007ffff710dae6 in -[GSStandardWindowDecorationView updateRects] (self=0xfeff18, _cmd=0x7ffff75d2980 <.objc_selector_list+832>) at GSStandardWindowDecorationView.m:98
#1  0x00007ffff710e8cd in -[GSStandardWindowDecorationView initWithFrame:window:] (self=0xfeff18, _cmd=0x7ffff75d5490 <.objc_selector_list>, frame=..., w=0xff2198) at GSStandardWindowDecorationView.m:167
#2  0x00007ffff71109a2 in +[GSWindowDecorationView newWindowDecorationViewWithFrame:window:] (self=0x99bc70, _cmd=0x7ffff7563eb0 <.objc_selector_list+1424>, frame=..., aWindow=0xff2198)
    at GSWindowDecorationView.m:77
#3  0x00007ffff7061b34 in -[NSWindow initWithContentRect:styleMask:backing:defer:] (self=0xff2198, _cmd=0x7ffff7565410 <.objc_selector_list+6896>, contentRect=..., aStyle=64, bufferingType=0, flag=0 '\000') at NSWindow.m:1077
#4  0x00007ffff7061f0c in -[NSWindow initWithContentRect:styleMask:backing:defer:screen:] (self=0xff2198, _cmd=0x7ffff74116d8 <.objc_selector_list+672>, contentRect=..., aStyle=64, bufferingType=0, flag=0 '\000', aScreen=0x0) at NSWindow.m:1140
#5  0x00007ffff6e313b0 in -[NSApplication(Private) _appIconInit] (self=0xcb2ff8, _cmd=0x7ffff7411a58 <.objc_selector_list+1568>) at NSApplication.m:3856
#6  0x00007ffff6e27e41 in -[NSApplication _init] (self=0xcb2ff8, _cmd=0x7ffff7412108 <.objc_selector_list+3280>) at NSApplication.m:925
#7  0x00007ffff62bd98b in -[NSObject performSelector:withObject:] (self=0xcb2ff8, _cmd=0x7ffff6808f28 <.objc_selector_list+112>, aSelector=0x7ffff7412108 <.objc_selector_list+3280>, anObject=0xcb2ff8)
    at NSObject.m:2020
#8  0x00007ffff63454f4 in -[NSObject(NSThreadPerformAdditions) performSelector:onThread:withObject:waitUntilDone:modes:] (self=0xcb2ff8, _cmd=0x7ffff6809238 <.objc_selector_list+896>, aSelector=0x7ffff7412108 <.objc_selector_list+3280>, aThread=0xaf5a58, anObject=0xcb2ff8, aFlag=1 '\001', anArray=0xdb48c8)
    at NSThread.m:2139
#9  0x00007ffff6345206 in -[NSObject(NSThreadPerformAdditions) performSelectorOnMainThread:withObject:waitUntilDone:modes:] (self=0xcb2ff8, _cmd=0x7ffff6809268 <.objc_selector_list+944>, aSelector=0x7ffff7412108 <.objc_selector_list+3280>, anObject=0xcb2ff8, aFlag=1 '\001', anArray=0xdb48c8)
    at NSThread.m:2094
#10 0x00007ffff6345281 in -[NSObject(NSThreadPerformAdditions) performSelectorOnMainThread:withObject:waitUntilDone:] (self=0xcb2ff8, _cmd=0x7ffff74125e8 <.objc_selector_list+4528>, aSelector=0x7ffff7412108 <.objc_selector_list+3280>, anObject=0xcb2ff8, aFlag=1 '\001') at NSThread.m:2105
#11 0x00007ffff6e281b0 in -[NSApplication init] (self=0xcb2ff8, _cmd=0x7ffff7411d08 <.objc_selector_list+2256>) at NSApplication.m:979
#12 0x00007ffff6e27a20 in +[NSApplication sharedApplication] (self=0x7be760, _cmd=0x7ffff73fe298 <.objc_selector_list+192>) at NSApplication.m:851
#13 0x00007ffff6dff9d0 in NSApplicationMain (argc=1, argv=0x7fffffffe1a8) at Functions.m:78
#14 0x000000000041e6a2 in main (argc=1, argv=0x7fffffffe1a8) at Edit_main.m:4
(gdb) break GSStandardWindowDecorationView.m:98
Breakpoint 1 at 0x7ffff710dadf: file GSStandardWindowDecorationView.m, line 98.
(gdb) r
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /Applications/TextEdit.app/TextEdit
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".

Breakpoint 1, -[GSStandardWindowDecorationView updateRects] (self=0xff0dc8,
    _cmd=0x7ffff75d2980 <.objc_selector_list+832>) at GSStandardWindowDecorationView.m:98
98        if (hasTitleBar)
(gdb) print hasTitleBar
$1 = 112 'p'
(gdb) print hasResizeBar
$2 = 112 'p'
(gdb) print hasCloseButton
$3 = 112 'p'
(gdb) print hasMiniaturizeButton
$4 = 112 'p'
(gdb)
davidchisnall commented 5 years ago

Thanks, I can reproduce that. If you've got a smaller test case, that would be helpful...

davidchisnall commented 5 years ago

Note that gdb doesn't know about non-fragile instance variables, so anything that it prints for ivar accesses is likely to be nonsense...

davidchisnall commented 5 years ago

It appears as if the runtime is initialising the offset of hasTitleBar to -1, which is obviously wrong.

trunkmaster commented 5 years ago

Do you still need and a smaller test case? BTW, what would you recommend as a debugger? lldb?

davidchisnall commented 5 years ago

LLDB also doesn't know about the new ABI, though would probably be easier to fix. When debugging, unfortunately, you have to fall back to the runtime's introspection APIs.

trunkmaster commented 5 years ago

Great work, David! Thank you!

triplef commented 5 years ago

@davidchisnall unfortunately this latest change crashes for us here: https://github.com/gnustep/libobjc2/blob/8dd9c9a0ae5e198149fba0c5a7a3b3ec6f7b624d/ivar.c#L81

It crashes with i == 1 and *ivar->offset == -3. The first two ivars of the affected class are of type BOOL. This is with ABI 1.9 using clang from the latest Android NDK.

Let me know if I can provide any further info.

davidchisnall commented 5 years ago

Hmm, I can see how that would happen. The assert is, unfortunately, firing because the code surrounding it is wrong. If we start with 3 chars in a class then the offsets will be -3, -2, and -1, so we need to handle that case. Unfortunately, we also need to handle the case that we have a bitfield of ints, in which case the offsets will be -4, -4, and -4. I will try to add a test for both of these cases.

davidchisnall commented 5 years ago

Should be fixed in afee197c67c4ad4e80da1e92c93800b67ca083a1

triplef commented 5 years ago

Works great now. Thanks for the quick fix!