gnustep/libobjc2

Crash during objc_msg_lookup_sender (Aarch64)

Closed this issue · 8 comments

Hi,

When launching Gorm.app the app crashes. This is during an ASSIGN macro/command being used. Could it be incompatible? Is this perhaps related to the bug that was recently fixed?

Thank you,
Patryk

pinebook:~/Desktop/gnustep-build/ubuntu-16.04-clang-6.0-runtime-1.9-ARM/GNUstep-build/apps-gorm/Gorm.app$ lldb-6.0  ./Gorm 
(lldb) target create "./Gorm"
Current executable set to './Gorm' (aarch64).
(lldb) run
Process 10412 launched: './Gorm' (aarch64)
2019-08-28 05:51:40.657 Gorm[10412:10412] styleoffsets ... guessing offsets
2019-08-28 05:51:40.663 Gorm[10412:10412] styleoffsets ... guessing offsets
Process 10412 stopped and restarted: thread 1 received signal: SIGCHLD
2019-08-28 05:51:42.556 Gorm[10412:10412] Bad palette selection - -1
2019-08-28 05:51:42.669 Gorm[10412:10412] Bad palette selection - -1
2019-08-28 05:51:43.054 Gorm[10412:10412] Bad palette selection - -1
Process 10412 stopped
* thread #1, name = 'Gorm', stop reason = signal SIGSEGV: invalid address (fault address: 0x0)
    frame #0: 0x0000007fb61890a0 libobjc.so.4.6`objc_msg_lookup_sender + 708
libobjc.so.4.6`objc_msg_lookup_sender:
->  0x7fb61890a0 <+708>: ldr    x8, [x8]
    0x7fb61890a4 <+712>: stur   x8, [x29, #-0x18]
    0x7fb61890a8 <+716>: ldur   x8, [x29, #-0x18]
    0x7fb61890ac <+720>: stur   x8, [x29, #-0x50]
(lldb) up
frame #1: 0x0000007fb73d8900 libgnustep-gui.so.0.27`-[NSTableView _initDefaults](self=0x00000000011750a8, _cmd="\xeb\x1e") at NSTableView.m:2017
   2014   _rowHeight        = 16.0;
   2015   _intercellSpacing = NSMakeSize (5.0, 2.0);
   2016   ASSIGN(_selectedColumns, [NSMutableIndexSet indexSet]);
-> 2017   ASSIGN(_selectedRows, [NSMutableIndexSet indexSet]);
   2018   _allowsEmptySelection = YES;
   2019   _allowsMultipleSelection = NO;
   2020   _allowsColumnSelection = YES;
(lldb) up
frame #2: 0x0000007fb73d8d08 libgnustep-gui.so.0.27`-[NSTableView initWithFrame:](self=0x00000000011750a8, _cmd="\xaf\x1c", frameRect=(origin = (x = 0, y = 0), size = (width = 0, height = 0))) at NSTableView.m:2045
   2042   if (!self)
   2043     return self;
   2044 
-> 2045   [self _initDefaults];
   2046   ASSIGN(_gridColor, [NSColor gridColor]); 
   2047   ASSIGN(_backgroundColor, [NSColor controlBackgroundColor]); 
   2048   ASSIGN(_tableColumns, [NSMutableArray array]);
(lldb) up
frame #3: 0x0000007fb2b2f38c 3Containers`-[GormNSTableView initWithFrame:](self=0x00000000011750a8, _cmd="\xb0\x1c", aRect=(origin = (x = 0, y = 0), size = (width = 0, height = 0))) at GormNSTableView.m:112
   109  
   110  - (id) initWithFrame: (NSRect) aRect
   111  {
-> 112    self = [super initWithFrame: aRect];
   113    [super setDataSource: [GormNSTableView sharedDataSource]];
   114    _gormDataSource = nil;
   115    // ASSIGN(_savedColor, [NSColor controlBackgroundColor]);
(lldb) up
frame #4: 0x0000007fb2b2d99c 3Containers`-[ContainersPalette finishInstantiate](self=0x0000000001124eb8, _cmd="~F") at ContainersPalette.m:119
   116    contentSize = [v contentSize];
   117    [v setBorderType: NSBezelBorder];
   118  
-> 119    tv = [[GormNSTableView alloc] initWithFrame:
   120                                    NSZeroRect];
   121  
   122    tc = [[NSTableColumn alloc] initWithIdentifier: @"column1"];
(lldb) up
frame #5: 0x0000007fb7deda88 libGormCore.so.1`-[GormPalettesManager loadPalette:](self=0x0000000000bd26e8, _cmd="\x92I", path=0x000000000111e238) at GormPalettesManager.m:529
   526        [substituteClasses addEntriesFromDictionary: subClasses];
   527      }
   528  
-> 529    [palette finishInstantiate];
   530    window = [palette originalWindow];
   531    [window setExcludedFromWindowsMenu: YES];
   532  
(lldb) up
frame #6: 0x0000007fb7dec0d0 libGormCore.so.1`-[GormPalettesManager init](self=0x0000000000bd26e8, _cmd="\xa3") at GormPalettesManager.m:360
   357  
   358        for (index = 0; index < [array count]; index++)
   359          {
-> 360            [self loadPalette: [array objectAtIndex: index]];
   361          }
   362      }
   363  
(lldb) up
frame #7: 0x000000000040e618 Gorm`-[Gorm palettesManager](self=0x00000000007e2d78, _cmd="\vF") at Gorm.m:1065
   1062 {
   1063   if (palettesManager == nil)
   1064     {
-> 1065       palettesManager = [[GormPalettesManager alloc] init];
   1066     }
   1067   return palettesManager;
   1068 }
(lldb) up
frame #8: 0x0000000000406d6c Gorm`-[Gorm init](self=0x00000000007e2d78, _cmd="\xa3") at Gorm.m:164
   161         * editors and inspectors provided in the standard palettes
   162         * are available.
   163         */
-> 164        [self palettesManager];
   165        [self pluginManager];
   166  
   167        /*
(lldb) up
frame #9: 0x0000007fb7181288 libgnustep-gui.so.0.27`+[NSApplication sharedApplication](self=0x0000000000435908, _cmd="\xb9\e") at NSApplication.m:858
   855    if (NSApp == nil)
   856      {
   857        /* -init sets NSApp.  */
-> 858        [[self alloc] init];
   859      }
   860    return NSApp;
   861  }
(lldb) 

The ASSIGN macro just does retain and then release of the arguments. Depending on how GNUstep is compiled, this may call the objc_retain() and objc_release functions, or send -retain and -release messages. Both should work.

I suspect that the crash is in sending the [NSMutableIndexSet indexSet] message. I can't really tell you anything about the reason for the crash when it's without debug info (it is in C code though).

I enabled debug and it looks like it might be crashing in looking up the class for the object. That seems strange, how could that be happening?

patryk@pinebook:~/Desktop/gnustep-build/ubuntu-16.04-clang-6.0-runtime-1.9-ARM/GNUstep-build/apps-gorm/Gorm.app$ lldb-6.0 ./Gorm 
(lldb) target create "./Gorm"
Current executable set to './Gorm' (aarch64).
(lldb) run
Process 31423 launched: './Gorm' (aarch64)
2019-08-30 04:50:26.492 Gorm[31423:31423] Bad palette selection - -1
2019-08-30 04:50:26.626 Gorm[31423:31423] Bad palette selection - -1
2019-08-30 04:50:27.017 Gorm[31423:31423] Bad palette selection - -1
Process 31423 stopped
* thread #1, name = 'Gorm', stop reason = signal SIGSEGV: invalid address (fault address: 0x0)
    frame #0: 0x0000007fb61870a0 libobjc.so.4.6`objc_msg_lookup_sender [inlined] classForObject(obj=0x4000000000000000) at class.h:316
   313 				return SmallObjectClasses[(addr & OBJC_SMALL_OBJECT_MASK)];
   314 			}
   315 		}
-> 316 		return obj->isa;
   317 	}
   318 	
   319 	static inline BOOL classIsOrInherits(Class cls, Class base)
(lldb) up
frame #1: 0x0000007fb6187050 libobjc.so.4.6`objc_msg_lookup_sender [inlined] objc_msg_lookup_internal(receiver=0x0000007fffffcbe0, selector="\a", sender=0x0000000001159158) at sendmsg2.c:65
   62  	                                id sender)
   63  	{
   64  	retry:;
-> 65  		Class class = classForObject((*receiver));
   66  		Slot_t result = objc_dtable_lookup(class->dtable, selector->index);
   67  		if (UNLIKELY(0 == result))
   68  		{
(lldb) fr va
(id *) receiver = 0x0000007fffffcbe0
(SEL) selector = "\a"
(id) sender = 0x0000000001159158
(Class) class = 0x0000000000000000
(Slot_t) result = 0x0000000000000000
(lldb) up
frame #2: 0x0000007fb6187044 libobjc.so.4.6`objc_msg_lookup_sender(receiver=0x0000007fffffcbe0, selector="\a", sender=0x0000000001159158) at sendmsg2.c:171
   168 			(sender->isa->info & (*receiver)->isa->info & _CLS_PLANE_AWARE),1))
   169 		*/
   170 		{
-> 171 			return objc_msg_lookup_internal(receiver, selector, sender);
   172 		}
   173 		// If we are in plane-aware code
   174 		void *senderPlaneID = *((void**)sender - 1);
(lldb) fr va
(id *) receiver = 0x0000007fffffcbe0
(SEL) selector = "\a"
(id) sender = 0x0000000001159158
(lldb) up
frame #3: 0x0000007fb73d8900 libgnustep-gui.so.0.27`-[NSTableView _initDefaults](self=0x0000000001159158, _cmd="\xeb\x1e") at NSTableView.m:2017
   2014	  _rowHeight        = 16.0;
   2015	  _intercellSpacing = NSMakeSize (5.0, 2.0);
   2016	  ASSIGN(_selectedColumns, [NSMutableIndexSet indexSet]);
-> 2017	  ASSIGN(_selectedRows, [NSMutableIndexSet indexSet]);
   2018	  _allowsEmptySelection = YES;
   2019	  _allowsMultipleSelection = NO;
   2020	  _allowsColumnSelection = YES;
(lldb) fr v
(NSTableView *) self = 0x0000000001159158
(SEL) _cmd = "\xeb\x1e"
(id) __object = 0x4000000000000000
(lldb) up
frame #4: 0x0000007fb73d8d08 libgnustep-gui.so.0.27`-[NSTableView initWithFrame:](self=0x0000000001159158, _cmd="\xaf\x1c", frameRect=(origin = (x = 0, y = 0), size = (width = 0, height = 0))) at NSTableView.m:2045
   2042	  if (!self)
   2043	    return self;
   2044	
-> 2045	  [self _initDefaults];
   2046	  ASSIGN(_gridColor, [NSColor gridColor]); 
   2047	  ASSIGN(_backgroundColor, [NSColor controlBackgroundColor]); 
   2048	  ASSIGN(_tableColumns, [NSMutableArray array]);
(lldb) 

Hi David,

I don"t quite understand the question about whether the class is accessed via class variable or via a call into the runtime.

The memory corruption seems to be happening during
2016 ASSIGN(_selectedColumns, [NSMutableIndexSet indexSet]);
2017 ASSIGN(_selectedRows, [NSMutableIndexSet indexSet]);

I set a breakpoint in indexSet and the object seems to be allocating and initializing itself.

(lldb) run
There is a running process, kill it and restart?: [Y/n] y
Process 8385 exited with status = 9 (0x00000009) 
Process 8428 launched: './Gorm' (aarch64)
2019-09-01 19:06:47.474 Gorm[8428:8428] Bad palette selection - -1
2019-09-01 19:06:47.574 Gorm[8428:8428] Bad palette selection - -1
2019-09-01 19:06:47.895 Gorm[8428:8428] Bad palette selection - -1
Process 8428 stopped
* thread #1, name = 'Gorm', stop reason = breakpoint 1.1
    frame #0: 0x0000007fb73d875c libgnustep-gui.so.0.27`-[NSTableView _initDefaults](self=0x0000000001159528, _cmd="\xeb\x1e") at NSTableView.m:2016
   2013   _drawsGrid        = YES;
   2014   _rowHeight        = 16.0;
   2015   _intercellSpacing = NSMakeSize (5.0, 2.0);
-> 2016   ASSIGN(_selectedColumns, [NSMutableIndexSet indexSet]);
   2017   ASSIGN(_selectedRows, [NSMutableIndexSet indexSet]);
   2018   _allowsEmptySelection = YES;
   2019   _allowsMultipleSelection = NO;
(lldb) n
Process 8428 stopped
* thread #1, name = 'Gorm', stop reason = breakpoint 7.1
    frame #0: 0x0000007fb6648588 libgnustep-base.so.1.26`+[NSIndexSet indexSet](self=0x0000007fb6aa75c0, _cmd="\x96\x04") at NSIndexSet.m:123
   120  @implementation NSIndexSet
   121  + (id) indexSet
   122  {
-> 123    id    o = [self allocWithZone: NSDefaultMallocZone()];
   124  
   125    o = [o init];
   126    return AUTORELEASE(o);
(lldb) n
Process 8428 stopped
* thread #1, name = 'Gorm', stop reason = step over
    frame #0: 0x0000007fb66485e0 libgnustep-base.so.1.26`+[NSIndexSet indexSet](self=0x0000007fb6aa75c0, _cmd="\x96\x04") at NSIndexSet.m:125
   122  {
   123    id    o = [self allocWithZone: NSDefaultMallocZone()];
   124  
-> 125    o = [o init];
   126    return AUTORELEASE(o);
   127  }
   128  
(lldb) n
Process 8428 stopped
* thread #1, name = 'Gorm', stop reason = step over
    frame #0: 0x0000007fb664861c libgnustep-base.so.1.26`+[NSIndexSet indexSet](self=0x0000007fb6aa75c0, _cmd="\x96\x04") at NSIndexSet.m:126
   123    id    o = [self allocWithZone: NSDefaultMallocZone()];
   124  
   125    o = [o init];
-> 126    return AUTORELEASE(o);
   127  }
   128  
   129  + (id) indexSetWithIndex: (NSUInteger)anIndex
(lldb) fr va
(Class) self = 0x0000007fb6aa75c0
(SEL) _cmd = "\x96\x04"
(id) o = 0x0000000001161008
(lldb) n
Process 8428 stopped
* thread #1, name = 'Gorm', stop reason = step over
    frame #0: 0x0000007fb73d87cc libgnustep-gui.so.0.27`-[NSTableView _initDefaults](self=0x0000000001159528, _cmd="\xeb\x1e") at NSTableView.m:2016
   2013   _drawsGrid        = YES;
   2014   _rowHeight        = 16.0;
   2015   _intercellSpacing = NSMakeSize (5.0, 2.0);
-> 2016   ASSIGN(_selectedColumns, [NSMutableIndexSet indexSet]);
   2017   ASSIGN(_selectedRows, [NSMutableIndexSet indexSet]);
   2018   _allowsEmptySelection = YES;
   2019   _allowsMultipleSelection = NO;
(lldb) fr va
(NSTableView *) self = 0x0000000001159528
(SEL) _cmd = "\xeb\x1e"
(id) __object = nil
(lldb) 



(lldb) n
Process 8428 stopped
* thread #1, name = 'Gorm', stop reason = step over
    frame #0: 0x0000007fb73d885c libgnustep-gui.so.0.27`-[NSTableView _initDefaults](self=0x0000000001159528, _cmd="\xeb\x1e") at NSTableView.m:2017
   2014   _rowHeight        = 16.0;
   2015   _intercellSpacing = NSMakeSize (5.0, 2.0);
   2016   ASSIGN(_selectedColumns, [NSMutableIndexSet indexSet]);
-> 2017   ASSIGN(_selectedRows, [NSMutableIndexSet indexSet]);
   2018   _allowsEmptySelection = YES;
   2019   _allowsMultipleSelection = NO;
   2020   _allowsColumnSelection = YES;
(lldb) fr va
(NSTableView *) self = 0x0000000001159528
(SEL) _cmd = "\xeb\x1e"
(id) __object = 0x0000000001159528
(lldb) n
Process 8428 stopped
* thread #1, name = 'Gorm', stop reason = breakpoint 7.1
    frame #0: 0x0000007fb6648588 libgnustep-base.so.1.26`+[NSIndexSet indexSet](self=0x0000007fb6aa75c0, _cmd="\x96\x04") at NSIndexSet.m:123
   120  @implementation NSIndexSet
   121  + (id) indexSet
   122  {
-> 123    id    o = [self allocWithZone: NSDefaultMallocZone()];
   124
   125    o = [o init];
   126    return AUTORELEASE(o);
(lldb) n
Process 8428 stopped
* thread #1, name = 'Gorm', stop reason = step over
    frame #0: 0x0000007fb66485e0 libgnustep-base.so.1.26`+[NSIndexSet indexSet](self=0x0000007fb6aa75c0, _cmd="\x96\x04") at NSIndexSet.m:125
   122  {
   123    id    o = [self allocWithZone: NSDefaultMallocZone()];
   124
-> 125    o = [o init];
   126    return AUTORELEASE(o);
   127  }
   128
(lldb) n
Process 8428 stopped
* thread #1, name = 'Gorm', stop reason = step over
    frame #0: 0x0000007fb664861c libgnustep-base.so.1.26`+[NSIndexSet indexSet](self=0x0000007fb6aa75c0, _cmd="\x96\x04") at NSIndexSet.m:126
   123    id    o = [self allocWithZone: NSDefaultMallocZone()];
   124
   125    o = [o init];
-> 126    return AUTORELEASE(o);
   127  }
   128
   129  + (id) indexSetWithIndex: (NSUInteger)anIndex
(lldb) fr va
(Class) self = 0x0000007fb6aa75c0
(SEL) _cmd = "\x96\x04"
(id) o = 0x0000000001161028
(lldb) n
Process 8428 stopped
* thread #1, name = 'Gorm', stop reason = step over
    frame #0: 0x0000007fb73d88ac libgnustep-gui.so.0.27`-[NSTableView _initDefaults](self=0x0000000001159528, _cmd="\xeb\x1e") at NSTableView.m:2017
   2014   _rowHeight        = 16.0;
   2015   _intercellSpacing = NSMakeSize (5.0, 2.0);
   2016   ASSIGN(_selectedColumns, [NSMutableIndexSet indexSet]);
-> 2017   ASSIGN(_selectedRows, [NSMutableIndexSet indexSet]);
   2018   _allowsEmptySelection = YES;
   2019   _allowsMultipleSelection = NO;
   2020   _allowsColumnSelection = YES;
(lldb) fr va
(NSTableView *) self = 0x0000000001159528
(SEL) _cmd = "\xeb\x1e"
(id) __object = 0x4000000000000000
(lldb) n
Process 8428 stopped
* thread #1, name = 'Gorm', stop reason = signal SIGSEGV: invalid address (fault address: 0x0)
    frame #0: 0x0000007fb61870a0 libobjc.so.4.6`objc_msg_lookup_sender [inlined] classForObject(obj=0x4000000000000000) at class.h:316
   313                          return SmallObjectClasses[(addr & OBJC_SMALL_OBJECT_MASK)];
   314                  }
   315          }
-> 316          return obj->isa;
   317  }
   318
   319  static inline BOOL classIsOrInherits(Class cls, Class base)
(lldb) 

So it's successfully calling -indexSet once and then failing in the second call? It's difficult to tell, because you step over the next line (which includes three message sends and an assignment or two function calls, a message send, and an assignment, depending on how the code was compiled). Can you step into the second ASSIGN macro? Or, ideally, manually expand it so that you can see exactly what the sequence is?

The first call will probably be the first call to anything in NSMutableSet so will install the dtable for this class. It is possible that I haven't quite fixed the stack corruption that was happening when calling from the objc_msgSend assembly into C code (though I'd expect everything to crash if that were the case), but I'm not sure what is causing the call to objc_msg_lookup_sender here. Is clang generating those calls instead of objc_msgSend? I though I flipped the switch on AArch64 to make that the default, but possibly not. If this is only hitting C code, then the bug is more interesting: that code is used on all platforms, so it's not clear what the issue would be.

Were you able to triage this any further?

The only thing I tried is running Gorm on an AWS ARM instance and didn’t get a crash. So maybe the crash is a result of some incompatible library on my laptop’s Armbian distribution.... hope to track it down further.

I will reopen this or open a new ticket once I track it down further or find a simple test case.