discuss-gnustep
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Mysterious crash in NSRunLoop, using libobjc2 on Linux


From: Lobron, David
Subject: Re: Mysterious crash in NSRunLoop, using libobjc2 on Linux
Date: Wed, 20 Dec 2017 21:08:14 +0000

Hi David-

>> I've now got a very pruned-down program that reproduces the bug.  However, 
>> that program still uses NSException, NSAutoreleasePool, and the 
>> NS_DURING/HANDLER/ENDHANDLER macros.  I've tried replacing these with plain 
>> @try/@catch and @throw in order to depend only on libobjc2, but so far the 
>> latter code hasn't reproduced the bug.  For example, here is some code from 
>> my minimal code that reproduces the bug:
>> 
>> @interface MinRep2 : NSObject {
>> }
>> - (void)poke;
>> @end
>> @implementation MinRep2
>> - (void)poke {
>> NSAutoreleasePool *pool = [NSAutoreleasePool new];
>> NS_DURING {
>>   [NSException raise:@"foo" format:@"bar"];
>> } NS_HANDLER {
>>   [localException retain];
>>   [pool release];
>>   [[localException autorelease] raise];
>> } NS_ENDHANDLER
>>     [pool release];
>> }
>> @end
>> 
>> I tried to translate this into code that depends only on libobjc2 as follows 
>> (this inherits the Test class in the libobjc2 Test directory):
>> 
>> @interface MinRep2 : Test {
>> }
>> - (void)poke;
>> @end
>> @implementation MinRep2
>> - (void)poke {
>> id e1;
>> @try {
>>   @throw e1;
>> } @catch (id x) {
>>   [x retain];
>>   [x autorelease];
>>   @throw x;
>> }
>> }
>> @end
>> 
>> Am I doing this translation approximately the right way?  The "raise" method 
>> in the gnustep-base NSException class does a lot of things, and so it's 
>> likely that my call to @throw above might be missing something essential to 
>> coercing the ObjC exceptions to and from a C++ one.
> 
> This looks mostly correct, though you have removed the autorelease pool calls 
> (objc_autoreleasePoolPush() / objc_autoreleasePoolPop()).  The big difference 
> is that this looks as if it might be rethrowing, whereas your other code is 
> definitely calling another function that is throwing the object again (in a 
> different exception object).  This is a bit more interesting, because this is 
> the case where you’re in a catch block, but now you’re throwing another 
> exception out of it.  This logic might be incorrect in the runtime, because I 
> don’t think it’s well tested.  

Looking at my code in the first example, I don't quite see where it's calling 
another function.  I'm using native ObjC exceptions, so the 
NS_DURING/HANDLER/ENDHANDLER macros expand to @try and @catch (in 
gnustep-base).  The [NSException raise] method just calls "@throw self" when 
_NATIVE_OBJC_EXCEPTIONS is defined.  Can you explain exactly how the first code 
code is doing the call to another function and throwing the object again in a 
different exception object?  I'm trying to replicate that behavior in my 
stand-alone test that doesn't use gnustep-base.

I tried defining a new function that copies an exception and throws a copy:

@implementation MinRep2

- (void)throwACopy:(id)x {
  id y = x;
  @throw y;
}
...
- (void)poke {
  //NSAutoreleasePool *pool = [NSAutoreleasePool new];                          
                                                                                
         
  //NS_DURING {                                                                 
                                                                                
         
  id e1;
  @try {
    @throw e1;
    //[NSException raise:@"foo" format:@"bar"];                                 
                                                                                
         
    //} NS_HANDLER {                                                            
                                                                                
         
    // [localException retain];                                                 
                                                                                
         
    //[pool release];                                                           
                                                                                
         
    //[[localException autorelease] raise];                                     
                                                                                
         
  } @catch (id x) {
    [x retain];
    [x autorelease];
    [self throwACopy:x];
    //  } NS_ENDHANDLER                                                         
                                                                                
         
  }
      //  [pool release];                                                       
                                                                                
         
}

This compiles and runs without a problem, but it doesn't trigger the bug.

> When we unwind through this stack frame, if it’s in a C++ compilation unit, 
> then we should be calling objc_end_catch() in the cleanup, which should be 
> deallocating the first exception, decrementing the reference count of the 
> object, and then resuming throwing the other object.  It’s entirely possible 
> that there’s a bug somewhere there...

I set a breakpoint on objc_end_catch in my program that reproduces the bug, and 
the breakpoint is never crossed (see below).  Could that itself be the problem?

--David

Output of program that reproduces the bug:

(gdb) break objc_end_catch
Breakpoint 1 at 0x401d50
(gdb) r
Starting program: /home/dlobron/build/clangport/akamai/mapmaker/Test/obj/MinRep 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Throwing 0x7b83a0
Throwing 0x7b83a0
New personality function called 0x7fb400
Class: GNUCOBJC
LSDA: 0x41148c
Search phase...
Filter: 1
Class name: NSException
0x7ffff5e73de8 type: 1
found handler for NSException
handler: 4
Found handler! 4
New personality function called 0x7fb4a0
Class: GNUCC++
Foreign class: 0x7ffff5e32a28
LSDA: 0x41148c
Phase 2: Fight!
Not the handler frame, looking up the cleanup again
Filter: 1
Class name: NSException
0x7ffff5e73de8 type: 0
Filter: 0
0 filter
handler! 1 0
Installing cleanup...
Installing context, selector 0
New personality function called 0x7fb4a0
Class: GNUCC++
Foreign class: 0x7ffff5e32a28
LSDA: 0x41148c
Phase 2: Fight!
Not the handler frame, looking up the cleanup again

Program received signal SIGABRT, Aborted.
0x00007ffff4bcfcc9 in __GI_raise (sig=sig@entry=6) at 
../nptl/sysdeps/unix/sysv/linux/raise.c:56
56      ../nptl/sysdeps/unix/sysv/linux/raise.c: No such file or directory.


reply via email to

[Prev in Thread] Current Thread [Next in Thread]