[cfe-dev] [Obj-C]method lookup for invalid receiver

David Chisnall csdavec at swan.ac.uk
Thu Apr 22 09:32:22 PDT 2010


On 22 Apr 2010, at 17:08, Jean-Daniel Dupas wrote:

> Hello,
> 
> I see that when trying to send a message to a non object receiver (not type id but compatible type like void *), clang interprets the receiver as an 'id', but it does not lookup the selector in the global selector pool like it does for 'id' receiver.

This sounds like exactly the opposite of what it should be doing.  I don't think we should be allowing non-object types to be message receivers, even if GCC does (a few issues with struct objc_object* and struct objc_class* aside).  If people need to do this, they should use an explicit cast.

> Of course, I agree that code relying on this must be fixed, but this is true for a bunch of other warnings ;-)
> 
> So, if this is not a design choice, I attach a patch that change the behavior to lookup selector when the receiver is not an object (and fixes tests that rely on the old behavior).

The second part here is something that should be fixed.  GCC says 'this object doesn't advertise understanding this message, so I will assume that this is an oversight' while clang says 'this object doesn't advertise understanding this message, so I will generate a stack frame with a random layout - have fun debugging!'  For example, this snippet:

@interface A
- (void)foo: (float)a;
@end
@interface B
@end
@implementation B
- (void)bar
{
	[self foo: 0];
}
- (void)foo: (float)a {}
@end

The message send in this example has i32 0 as its last argument.  The receiver, in contrast, expects a float, so the stack layout will be wrong.  You should get a warning that B might not respond to -foo:, but you should then get the correct stack layout because there is only one -foo: method defined.  

A very common case for this warning is when someone forgets to include NSObject in a protocol list, for example specifying something as id<Foo> when they mean either NSObject*<Foo>, id<Foo, NSObject>, or for Foo to conform to the NSObject protocol.  Sending -retain or -release messages to an id<Foo> will tell you that the -retain and -release messages don't exist - which is clearly wrong.

(Aside: this would be a really useful thing for the fixit magic to do; suggest that you add the NSObject protocol if you send messages from this protocol to a qualified id that does not conform to it)

It would also be worth warning when you define two methods with the same name and different type signatures, because any message send to an id will pick one of these and you may get some fun stack corruption (this is more of an issue on Darwin; the GNU runtime, at least in theory, can recover from this gracefully, the Mac runtimes can't).

David

-- Sent from my IBM 1620

-- Send from my Jacquard Loom





More information about the cfe-dev mailing list