On Dec 22, 2017, at 10:05 AM, Richard Frith-Macdonald wrote:

I think that's a possible indication of a bug in the compiler/ runtime nonfragile API support; it looks as if there may be an inconsistency in calculating the size of a structure used as an ivar.



After more testing, here's some additional info that might be useful:

-- Hardware (virtual):
   Clean, up-to-date Ubuntu 16.04 VM, 32bit

-- GNUstep install: Used the current Ubuntu script from the wiki, with two changes: - Removed the script's workaround for the ivar-offset issue (so it builds using the current version of gnustep-make instead of an old version). - Built a version of gnustep-base from a couple days ago (Dec. 19) which still used the obsolete -fobjc-nonfragile-abi build flag. (As previously mentioned, the current version of base won't build with the Ubuntu script if the script's ivar-offset workaround is removed).

-- Attachments:
Attached are 2 patches that print info about NSThread ivars at runtime, and 2 debugging-session outputs that were run with patches installed. The patches assume that the libs-base & libs-gui directories are in the same parent directory as the libobjc2 directory (as they are when running the Ubuntu script), because the patches add an #import "../../libobjc2/ivar.h" in order to use the runtime's ivar & ivar_list types.

The patches - one for base, and one for gui - each add a static C function that prints out the objc-runtime's NSThread ivar layout, obtained using the runtime API function, class_getIvarLayout(). The patch function also prints the locations in memory of the current thread's instance members, obtained using statements like: &thread- >_gcontext.

The base patch adds the diagnostic function to NSAutoreleasePool.m, & calls it from -[NSAutorelease dealloc] before the NSThread's _autorelease_vars is modified (which will leave a garbage value in _gcontext). The gui patch adds a matching function to NSGraphicsContext.m & calls it from -[NSGraphicsContext setCurrentContext:] before it frees the garbage value in _gcontext & segfaults.

The first output file, patched_base_session_output.txt, is the result of installing only the base patch & running a debug session.

The second output file, patched_base_and_gui_session_output.txt, is a followup session after also installing the gui patch. In this session, gnustep-base (previously patched) was not rebuilt, so base is the same binary as the first session.


-- Output summary:
In the first session (patched_base_session_output.txt), the diagnostic output shows most of the NSThread members' addresses line up with the runtime's ivar layout - up until the first member after the _autorelease_vars struct, _gcontext.

The runtime's ivar-layout offset for NSThread's _autorelease_vars member is 44, and _gcontext's is 64. The 20-byte space for _autorelease_vars is the smallest possible size for that struct on 32bit, as the struct is made up of 5 members, each of which is 4 bytes (3 ints & 2 pointers - see struct autorelease_thread_vars definition in NSAutoreleasePool.h).

However, the memory address of thread->_gcontext is offset from the thread instance's address by 56 - not the 64 listed by the runtime API - which is only 12 bytes away from thread->_autorelease_vars. At that offset value, _gcontext occupies the same memory location as the _autorelease_vars struct member, pool_cache_size; When pool_cache_size is set in NSAutoreleasePool.m (base), the same value will be accessed later in NSGraphicsContext.m (gui) as _gcontext, causing a crash due to sending an objc message to a non-nil garbage value.

In the second session (patched_base_and_gui_session_output.txt), the NSThread ivar diagnostics are also printed from within gui. Two notes:

1) I had thought the "ivar-offset" issue was due to a mismatch between gui & base ivar offsets (gui using a different offset to _gcontext than base), but the output shows that this is not the case: gui & base actually match each other's objc2-runtime ivar layouts and also have matching memory addresses returned from &thread->member statements; The mismatch is between the runtime's ivar layout and the memory addresses returned by &thread->member statements.

2) NSThread's ivar layout (obtained from the runtime API) was the same between the first & second sessions. This was expected, because the only change made between sessions was to add a static C function to NSGraphicsContext.m, and a call to it from -[NSGraphicsContext setCurrentContext:].

Unexpectedly, the memory locations of NSThread members (as obtained from &thread->member statements) did change between the two sessions, and not just in gui, which was recompiled - it also changed in base, even though it was the same binary in both sessions.

The first session had memory address offsets (obtained from &thread->member statements) for _autorelease_vars & _gcontext at 44 & 56, respectively; In the second session, those members' offsets were 36 & 56 (_gcontext stayed in the same place, _autorelease_vars shifted 8 bytes down, and now both members' addresses disagreed with the runtime's ivar layout offsets of 44 & 64).

The changed offsets also changed the location of the crash, because the in the second session, _autorelease_vars & _gcontext were separated by 20 bytes instead of 12 bytes, so they no longer overlapped. Subsequently, the call to -[NSGraphicsContext setCurrentContext:] (where the first session crashed) returned successfully, because _gcontext wasn't overwritten by a garbage value when writing pool_cache_size. (The crash happened at a later point, in -[GSWindowDecorationView layout]; Stack trace is in the output file).


   Hope this helps track down the issue.

Cheers,

Josh

P.S Using the current Ubuntu script unmodified (leaving the workaround in place) still works fine - everything builds, and no crashes when starting apps.

BASE:
 class_getIvarLayout([NSThread class])
   _target : 4
   _arg : 8
   _selector : 12
   _name : 16
   _stackSize : 20
   _cancelled : 24
   _active : 25
   _finished : 26
   _exception_handler : 28
   _thread_dictionary : 32
   _autorelease_vars : 44
   _gcontext : 64
   _runLoopInfo : 68
   _internal : 72

 Current thread from GSCurrentThread(): 0x813b51c
   thread->_target: 0x813b520 (4)
   thread->_arg: 0x813b524 (8)
   thread->_selector: 0x813b528 (12)
   thread->_name: 0x813b52c (16)
   thread->_stackSize: 0x813b530 (20)
   thread->_cancelled: 0x813b534 (24)
   thread->_active: 0x813b535 (25)
   thread->_finished: 0x813b536 (26)
   thread->_exception_handler: 0x813b538 (28)
   thread->_thread_dictionary: 0x813b53c (32)
   thread->_autorelease_vars: 0x813b548 (44)
   thread->_gcontext: 0x813b554 (56)
   thread->_runLoopInfo: 0x813b560 (68)


Program received signal SIGSEGV, Segmentation fault.
0xb6e4f3bc in objc_msgSend () from 
/usr/GNUstep/Local/Library/Libraries/libobjc.so.4.6
(gdb) bt
#0  0xb6e4f3bc in objc_msgSend () from 
/usr/GNUstep/Local/Library/Libraries/libobjc.so.4.6
#1  0xb77fbf06 in +[NSGraphicsContext setCurrentContext:] (self=0xb7b9bf2c 
<_OBJC_CLASS_NSGraphicsContext>, 
    _cmd=0xb7b6607c <.objc_selector_list+792>, context=0x82aa05c) at 
NSGraphicsContext.m:221
#2  0xb771ee0d in -[NSApplication _init] (self=0x827b1c4, _cmd=0xb7b663fc 
<.objc_selector_list+1688>) at NSApplication.m:892
#3  0xb711fc58 in -[NSObject performSelector:withObject:] (self=0x827b1c4, 
_cmd=0xb7450acc <.objc_selector_list+280>, 
    aSelector=0xb7b663fc <.objc_selector_list+1688>, anObject=0x827b1c4) at 
NSObject.m:1980
#4  0xb71b4f0f in -[NSObject(NSThreadPerformAdditions) 
performSelector:onThread:withObject:waitUntilDone:modes:] (self=0x827b1c4, 
    _cmd=0xb7450bac <.objc_selector_list+504>, aSelector=0xb7b663fc 
<.objc_selector_list+1688>, aThread=0x813b51c, 
    anObject=0x827b1c4, aFlag=1 '\001', anArray=0x827b29c) at NSThread.m:1672
#5  0xb71b4b8c in -[NSObject(NSThreadPerformAdditions) 
performSelectorOnMainThread:withObject:waitUntilDone:modes:] (
    self=0x827b1c4, _cmd=0xb7450b4c <.objc_selector_list+408>, 
aSelector=0xb7b663fc <.objc_selector_list+1688>, anObject=0x827b1c4, 
    aFlag=1 '\001', anArray=0x827b29c) at NSThread.m:1627
#6  0xb71b4c31 in -[NSObject(NSThreadPerformAdditions) 
performSelectorOnMainThread:withObject:waitUntilDone:] (self=0x827b1c4, 
    _cmd=0xb7b6634c <.objc_selector_list+1512>, aSelector=0xb7b663fc 
<.objc_selector_list+1688>, anObject=0x827b1c4, aFlag=1 '\001')
    at NSThread.m:1638
#7  0xb771f44d in -[NSApplication init] (self=0x827b1c4, _cmd=0x80604d4 
<.objc_selector_list+1344>) at NSApplication.m:978
#8  0x0804d1f6 in -[Gorm init] (self=0x827b1c4, _cmd=0xb7b66164 
<.objc_selector_list+1024>) at Gorm.m:89
#9  0xb771ebdf in +[NSApplication sharedApplication] (self=0x805fc8c 
<_OBJC_CLASS_Gorm>, _cmd=0xb7b5c120 <.objc_selector_list+96>)
    at NSApplication.m:850
#10 0xb76f39d5 in NSApplicationMain (argc=1, argv=0xbfffe014) at Functions.m:78
#11 0x0805425a in main (argc=1, argv=0xbfffe014) at main.m:30
(gdb)
 
BASE:
 class_getIvarLayout([NSThread class])
   _target : 4
   _arg : 8
   _selector : 12
   _name : 16
   _stackSize : 20
   _cancelled : 24
   _active : 25
   _finished : 26
   _exception_handler : 28
   _thread_dictionary : 32
   _autorelease_vars : 44
   _gcontext : 64
   _runLoopInfo : 68
   _internal : 72

 Current thread from GSCurrentThread(): 0x813b51c
   thread->_target: 0x813b520 (4)
   thread->_arg: 0x813b524 (8)
   thread->_selector: 0x813b528 (12)
   thread->_name: 0x813b52c (16)
   thread->_stackSize: 0x813b530 (20)
   thread->_cancelled: 0x813b534 (24)
   thread->_active: 0x813b535 (25)
   thread->_finished: 0x813b536 (26)
   thread->_exception_handler: 0x813b538 (28)
   thread->_thread_dictionary: 0x813b53c (32)
   thread->_autorelease_vars: 0x813b540 (36)
   thread->_gcontext: 0x813b554 (56)
   thread->_runLoopInfo: 0x813b558 (60)


GUI:
 class_getIvarLayout([NSThread class])
   _target : 4
   _arg : 8
   _selector : 12
   _name : 16
   _stackSize : 20
   _cancelled : 24
   _active : 25
   _finished : 26
   _exception_handler : 28
   _thread_dictionary : 32
   _autorelease_vars : 44
   _gcontext : 64
   _runLoopInfo : 68
   _internal : 72

 Current thread from GSCurrentThread(): 0x813b51c
   thread->_target: 0x813b520 (4)
   thread->_arg: 0x813b524 (8)
   thread->_selector: 0x813b528 (12)
   thread->_name: 0x813b52c (16)
   thread->_stackSize: 0x813b530 (20)
   thread->_cancelled: 0x813b534 (24)
   thread->_active: 0x813b535 (25)
   thread->_finished: 0x813b536 (26)
   thread->_exception_handler: 0x813b538 (28)
   thread->_thread_dictionary: 0x813b53c (32)
   thread->_autorelease_vars: 0x813b540 (36)
   thread->_gcontext: 0x813b554 (56)
   thread->_runLoopInfo: 0x813b558 (60)


Program received signal SIGSEGV, Segmentation fault.
0xb6e4f3bc in objc_msgSend () from 
/usr/GNUstep/Local/Library/Libraries/libobjc.so.4.6
(gdb) bt
#0  0xb6e4f3bc in objc_msgSend () from 
/usr/GNUstep/Local/Library/Libraries/libobjc.so.4.6
#1  0xb7a4877c in -[GSWindowDecorationView layout] (self=0x8393b1c, 
_cmd=0xb7c4a244 <.objc_selector_list+344>)
    at GSWindowDecorationView.m:284
#2  0xb7a49a58 in -[GSWindowDecorationView setFrame:] (self=0x8393b1c, 
_cmd=0xb7c1150c <.objc_selector_list+2256>, frameRect=...)
    at GSWindowDecorationView.m:413
#3  0xb799a99e in -[NSWindow sendEvent:] (self=0x838cc5c, _cmd=0xb448f3b8 
<.objc_selector_list+880>, theEvent=0x83a8a64)
    at NSWindow.m:4155
#4  0xb444a0a4 in -[XGServer(WindowOps) placewindow::] (self=0x825bcc4, 
_cmd=0xb7c116cc <.objc_selector_list+2704>, rect=..., win=1)
    at XGServerWindow.m:3269
#5  0xb7990eb9 in -[NSWindow setFrame:display:] (self=0x838cc5c, 
_cmd=0xb7b66124 <.objc_selector_list+960>, frameRect=..., 
    flag=1 '\001') at NSWindow.m:2266
#6  0xb7729799 in -[NSApplication(Private) _appIconInit] (self=0x827b1c4, 
_cmd=0xb7b666c4 <.objc_selector_list+2400>)
    at NSApplication.m:3847
#7  0xb771f438 in -[NSApplication _init] (self=0x827b1c4, _cmd=0xb7b663fc 
<.objc_selector_list+1688>) at NSApplication.m:924
#8  0xb711fc58 in -[NSObject performSelector:withObject:] (self=0x827b1c4, 
_cmd=0xb7450acc <.objc_selector_list+280>, 
    aSelector=0xb7b663fc <.objc_selector_list+1688>, anObject=0x827b1c4) at 
NSObject.m:1980
#9  0xb71b4f0f in -[NSObject(NSThreadPerformAdditions) 
performSelector:onThread:withObject:waitUntilDone:modes:] (self=0x827b1c4, 
    _cmd=0xb7450bac <.objc_selector_list+504>, aSelector=0xb7b663fc 
<.objc_selector_list+1688>, aThread=0x813b51c, 
    anObject=0x827b1c4, aFlag=1 '\001', anArray=0x827b29c) at NSThread.m:1672
#10 0xb71b4b8c in -[NSObject(NSThreadPerformAdditions) 
performSelectorOnMainThread:withObject:waitUntilDone:modes:] (
    self=0x827b1c4, _cmd=0xb7450b4c <.objc_selector_list+408>, 
aSelector=0xb7b663fc <.objc_selector_list+1688>, anObject=0x827b1c4, 
    aFlag=1 '\001', anArray=0x827b29c) at NSThread.m:1627
#11 0xb71b4c31 in -[NSObject(NSThreadPerformAdditions) 
performSelectorOnMainThread:withObject:waitUntilDone:] (self=0x827b1c4, 
    _cmd=0xb7b6634c <.objc_selector_list+1512>, aSelector=0xb7b663fc 
<.objc_selector_list+1688>, anObject=0x827b1c4, aFlag=1 '\001')
    at NSThread.m:1638
#12 0xb771f82d in -[NSApplication init] (self=0x827b1c4, _cmd=0x80604d4 
<.objc_selector_list+1344>) at NSApplication.m:978
#13 0x0804d1f6 in -[Gorm init] (self=0x827b1c4, _cmd=0xb7b66164 
<.objc_selector_list+1024>) at Gorm.m:89
#14 0xb771efbf in +[NSApplication sharedApplication] (self=0x805fc8c 
<_OBJC_CLASS_Gorm>, _cmd=0xb7b5c120 <.objc_selector_list+96>)
    at NSApplication.m:850
#15 0xb76f3db5 in NSApplicationMain (argc=1, argv=0xbfffe014) at Functions.m:78
#16 0x0805425a in main (argc=1, argv=0xbfffe014) at main.m:30
(gdb) 
 

Attachment: base-NSThread-diagnostic.diff
Description: Binary data

 

Attachment: gui-NSThread-diagnostic.diff
Description: Binary data



_______________________________________________
Discuss-gnustep mailing list
[email protected]
https://lists.gnu.org/mailman/listinfo/discuss-gnustep

Reply via email to