View mode: basic / threaded / horizontal-split · Log in · Help
October 11, 2012
Tips for debugging EXC_BAD_ACCESS
I didn't have any luck with this in the learn newsgroup so I'm trying here.

I'm trying to debug the Mac OS X port of DWT. Almost as soon as a DWT 
application starts to process events I receive a segmentation fault. The 
error happens in the "objc_msgSend" C function when calling an 
Objective-C method. GDB backtrace:

http://pastebin.com/0fmUmPQ1

The source code of DWT is located here:

https://github.com/d-widget-toolkit/dwt-mac

The error happens at this call:

https://github.com/d-widget-toolkit/dwt-mac/blob/master/dwt/widgets/Shell.d#L1874

Which calls:

https://github.com/d-widget-toolkit/dwt-mac/blob/master/dwt/widgets/Widget.d#L1824

Then:

https://github.com/d-widget-toolkit/dwt-mac/blob/master/dwt/widgets/Widget.d#L230

Some other points of interest:

https://github.com/d-widget-toolkit/dwt-mac/blob/master/dwt/widgets/Display.d#L4871

https://github.com/d-widget-toolkit/dwt-mac/blob/master/dwt/widgets/Shell.d#L1818

https://github.com/d-widget-toolkit/dwt-mac/blob/master/dwt/widgets/Display.d#L4501

https://github.com/d-widget-toolkit/dwt-mac/blob/master/dwt/widgets/Display.d#L4367

-- 
/Jacob Carlborg
October 11, 2012
Re: Tips for debugging EXC_BAD_ACCESS
On 2012-10-11 06:52:24 +0000, Jacob Carlborg <doob@me.com> said:

> I didn't have any luck with this in the learn newsgroup so I'm trying here.
> 
> I'm trying to debug the Mac OS X port of DWT. Almost as soon as a DWT 
> application starts to process events I receive a segmentation fault. 
> The error happens in the "objc_msgSend" C function when calling an 
> Objective-C method.

Most likely, the object objc_msgSend is called on has been deallocated, 
which would mean that windowSendEvent is called with a deallocated 
NSWindow object as its first argument.

I don't know how DWT works, but I'd say there's something amiss with 
how DWT is retaining its NSWindow.

Since you're on OS X, I'd suggest you try using Instruments to track 
the reference counters of all Objective-C objects within your program 
until it crashes, then search back the history for all 
retain/release/autorelease calls made to the address the 
EXEC_BAD_ACCESS happens on.

-- 
Michel Fortin
michel.fortin@michelf.ca
http://michelf.ca/
October 12, 2012
Re: Tips for debugging EXC_BAD_ACCESS
On 2012-10-11 20:19, Michel Fortin wrote:

> Most likely, the object objc_msgSend is called on has been deallocated,
> which would mean that windowSendEvent is called with a deallocated
> NSWindow object as its first argument.

How can I detect that? Can I use the object somehow and try to get the 
crash inside my own code instead of in system function?

> I don't know how DWT works, but I'd say there's something amiss with how
> DWT is retaining its NSWindow.

Ok, I'll have a look at this.

If I understand it correctly, it works something like this:

* DWT creates a couple of subclasses
* DWT creates a native window
* Sets up an event loop
* Fetches the next native event
* Translate it into a DWT event
* Calls any handlers
* Pass the native event to the super class

> Since you're on OS X, I'd suggest you try using Instruments to track the
> reference counters of all Objective-C objects within your program until
> it crashes, then search back the history for all
> retain/release/autorelease calls made to the address the EXEC_BAD_ACCESS
> happens on.

I tried using Instruments but I'm barely know what I'm doing. I tried 
with the "leaks" profile but I could really find anything/didn't really 
know how to use it.

It also crashes so fast that Instruments barely has a chance of 
collection any data.

-- 
/Jacob Carlborg
October 12, 2012
Re: Tips for debugging EXC_BAD_ACCESS
On 2012-10-11 20:19, Michel Fortin wrote:

> Most likely, the object objc_msgSend is called on has been deallocated,
> which would mean that windowSendEvent is called with a deallocated
> NSWindow object as its first argument.

I have done some investigation and I can call other methods on the 
NSWindow object, but regular methods and super methods. This would 
indicate that it's something wrong with the NSEvent object, but I can 
call methods on that as well.

> Since you're on OS X, I'd suggest you try using Instruments to track the
> reference counters of all Objective-C objects within your program until
> it crashes, then search back the history for all
> retain/release/autorelease calls made to the address the EXEC_BAD_ACCESS
> happens on.

I don't know how to use Instruments for this.

-- 
/Jacob Carlborg
October 12, 2012
Re: Tips for debugging EXC_BAD_ACCESS
On 2012-10-12 12:40:35 +0000, Jacob Carlborg <doob@me.com> said:

> On 2012-10-11 20:19, Michel Fortin wrote:
> 
>> Most likely, the object objc_msgSend is called on has been deallocated,
>> which would mean that windowSendEvent is called with a deallocated
>> NSWindow object as its first argument.
> 
> I have done some investigation and I can call other methods on the 
> NSWindow object, but regular methods and super methods. This would 
> indicate that it's something wrong with the NSEvent object, but I can 
> call methods on that as well.

That's not a very good proof. You might just be calling a method on the 
object before it gets released. Often, Objective-C objects are 
autoreleased, which means that deallocation is postponed until the end 
of the current event loop iteration (unless someone increase the 
reference counter again), so you might be having a valid pointer to it 
right now, but it might already be in the queue for deallocation.

If you want to test for the deallocated object theory, just call retain 
via objc_msgSend on any object you suspect might be deallocated too 
early, one by one, until you find the one that is causing the trouble. 
Once you find the problematic object, print its address on the console 
and use Instrument…


>> Since you're on OS X, I'd suggest you try using Instruments to track the
>> reference counters of all Objective-C objects within your program until
>> it crashes, then search back the history for all
>> retain/release/autorelease calls made to the address the EXEC_BAD_ACCESS
>> happens on.
> 
> I don't know how to use Instruments for this.

It's the Allocations profile you need. It'll record logs of every 
allocation, deallocation, and optionally every change to reference 
counters (click the (i) icon next to Allocations and check "Record 
reference counts"). Each log entry has a stack trace.

To see the raw log, you should open the Object List pane at the bottom 
(click the Statistics button, it's a menu). There'll be a lot of 
unrelated allocations, which is why you should output the pointer 
address to the object to the console (available under the same menu), 
and then search it in the log (or filter on it). Then look at the call 
stack for each entry, and hopefully you'll understand what's happening.

I hope this helps.


-- 
Michel Fortin
michel.fortin@michelf.ca
http://michelf.ca/
October 12, 2012
Re: Tips for debugging EXC_BAD_ACCESS
On 11.10.2012 08:52, Jacob Carlborg wrote:
> I didn't have any luck with this in the learn newsgroup so I'm trying here.
>
> I'm trying to debug the Mac OS X port of DWT. Almost as soon as a DWT
> application starts to process events I receive a segmentation fault. The
> error happens in the "objc_msgSend" C function when calling an
> Objective-C method. GDB backtrace:

If this is something that worked in D1 but doesn't in D2, it could be 
just some static member variable that suddenly became thread local.  But 
you probably already thought of that.
October 13, 2012
Re: Tips for debugging EXC_BAD_ACCESS
On 2012-10-13 00:37, torhu wrote:

> If this is something that worked in D1 but doesn't in D2, it could be
> just some static member variable that suddenly became thread local.  But
> you probably already thought of that.

This is D1. I started the port with D1 and I want to make it work with 
D1 before moving to D2.

-- 
/Jacob Carlborg
October 14, 2012
Re: Tips for debugging EXC_BAD_ACCESS
On 2012-10-11 20:19, Michel Fortin wrote:

> Most likely, the object objc_msgSend is called on has been deallocated,
> which would mean that windowSendEvent is called with a deallocated
> NSWindow object as its first argument.

I found the problem now, it's really embarrassing. I had missed passing 
the argument of any super call taking one argument:

https://github.com/d-widget-toolkit/dwt-mac/commit/d6674c1074e8a58600cb5052a79b784ae0d3b366

-- 
/Jacob Carlborg
October 14, 2012
Re: Tips for debugging EXC_BAD_ACCESS
On 2012-10-14 19:38:21 +0000, Jacob Carlborg <doob@me.com> said:

> On 2012-10-11 20:19, Michel Fortin wrote:
> 
>> Most likely, the object objc_msgSend is called on has been deallocated,
>> which would mean that windowSendEvent is called with a deallocated
>> NSWindow object as its first argument.
> 
> I found the problem now, it's really embarrassing. I had missed passing 
> the argument of any super call taking one argument:
> 
> https://github.com/d-widget-toolkit/dwt-mac/commit/d6674c1074e8a58600cb5052a79b784ae0d3b366

By 
> 
the way, that line is half-fishy:

	super_struct.super_class = cast(objc.Class) OS.objc_msgSend(id, OS.sel_superclass);

It'll 

work as long as you have only one level of derived classes, and only as 
long as you don't have a class that overrides the superclass method 
(which would be weird, I acknowledge). You should be aware of this if 
you're creating new object classes, especially the first part (the 
second part is only relevant if you wish to implement some kind of 
proxy objects).

Theoretically, I think it'd be better to use directly functions from 
the Objective-C runtime[1], which also avoids the dynamic dispatch 
overhead of objc_msgSend:

	super_struct.super_class = class_getSuperclass(object_getClass(id));

Note however that this is still not equivalent to calling:

	[super method:arg0];

because this last one gets the class pointer at compile-tome from its 
static symbol, so there's no overhead at all (and it works with derived 
classes of derived classes too).

[1]: 
https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ObjCRuntimeRef/Reference/reference.html

-- 


Michel Fortin
michel.fortin@michelf.ca
http://michelf.ca/
October 15, 2012
Re: Tips for debugging EXC_BAD_ACCESS
On 2012-10-14 22:58, Michel Fortin wrote:

> By
>>
> the way, that line is half-fishy:
>
>      super_struct.super_class = cast(objc.Class) OS.objc_msgSend(id, OS.sel_superclass);
>
> It'll
> work as long as you have only one level of derived classes, and only as
> long as you don't have a class that overrides the superclass method
> (which would be weird, I acknowledge). You should be aware of this if
> you're creating new object classes, especially the first part (the
> second part is only relevant if you wish to implement some kind of proxy
> objects).
>
> Theoretically, I think it'd be better to use directly functions from the
> Objective-C runtime[1], which also avoids the dynamic dispatch overhead
> of objc_msgSend:
>
>      super_struct.super_class = class_getSuperclass(object_getClass(id));

Thanks for the pointer. As a first step I'm only porting the Java code 
to D and this is how the Java code looks like. I'm trying to stay as 
close as possible to the Java code, making it easier to port future 
versions of SWT. But I also want the code to be correct.

-- 
/Jacob Carlborg
Top | Discussion index | About this forum | D home