Is there a bug in NSOperation in Mac OS X 10.6? - objective-c

If I release an instance of NSOperation before sending -init to it I get a segmentation fault.
Reasons I think this is valid code:
Apple does this in its documentation.
Gnustep does it in its implementation of NSNumber, so it's fairly certain that this is in Apple's code too. (At least was.)
NSObjects -init doesn't do anything, therefore -release, which belongs to NSObject should be working before that.
// gcc -o test -L/System/Library/Frameworks -framework Foundation test.m
#import <Foundation/Foundation.h>
int main(int argc, char *argv[]) {
NSOperation *theOperation = [NSOperation alloc];
[theOperation release];
}
What do you think, is this a bug?
Can you show me an example of another class that has the same behavior?
Any idea why this is happening?

Sending any message other than init to an object that has not been initialized is not valid code AFAIK. Call the superclass initializer and then release and I'm betting it won't crash (although having one class's initializer return a completely unrelated class strikes me as doubleplusungood).

There is nothing remotely valid about that code.
Rewrite your -init as:
- (id) init
{
if (self = [super init]) {
[self release];
NSNumber *number = [[NSNumber alloc] initWithInteger:6];
return number;
}
return self;
}
Of course, the code is still nonsense, but it doesn't crash.
You must always call through to the super's initializer before messaging self. And you must always do it with the pattern shown above.

I thought you need to initialize your superclass before calling release, but according to this example in Apple's docs that's not the case.
So it may be a bug, but certainly not an important one.

My previou analysis was not really correct.
However, I want to point that this issue can happen with different classes. It actually depends on which class you're subclassing. Subclassing NSObject is no problem, but subclassing NSOperation, NSOperationQueue, and NSThread is an issue, for example.
And it happens because just like YOU might do, the classes you subclass might allocate stuff in their -init method. And that's also where you set to nil the variables you have not allocated yet (and might do so later in your code).
So, by calling -release on yourself without a previous -init, you might cause one of your parent classes to release object that it had not allocated. And they can't check if their object is nil, because it didn't even have the opportunity to init every object/value it needs.
This also might be the reason why releasing NSOperation without init worked on 10.5 and doesn't work on 10.6. The 10.6 implementation have been rewritten to use blocks and Grand Central Dispatch, and thus, their init and dealloc methods might have changed greatly, creating a different behavior on that piece of code.

Related

Thread-safety of method swizzling

Method swizzling is used in the following singleton initializer but i am not sure about thread safety of swizzling.
What happens while a thread is about to call a method which is about to be swizzled by another method?
Is it safe to swizzle in any time, while there are threads about to call that method? Answer with official references please. Thanks
#import <dispatch/dispatch.h>
#import <objc/runtime.h>
#implementation MySingleton
static MySingleton * __singleton = nil;
+ (MySingleton *) sharedInstance_accessor
{
return ( __singleton );
}
+ (MySingleton *) sharedInstance
{
static dispatch_once_t __once = 0;
dispatch_once( &__once, ^{
__singleton = [[self alloc] init];
Method plainMethod = class_getInstanceMethod( self, #selector(sharedInstance) );
Method accessorMethod = class_getInstanceMethod( self, #selector(sharedInstance_accessor) );
method_exchangeImplementations( plainMethod, accessorMethod );
});
return ( __singleton );
}
#end
https://gist.github.com/MSch/943369
I doubt there is an official reference on this, but none is needed.
First, the executable code of the method is not un-mapped from memory. Thus, it doesn't matter which implementation is installed, the prior implementation is still available for execution.
That does mean, however, that you have to ensure that your data management is thread safe (which it is, assuming no one tries to call sharedInstance_accessor directly).
So that leaves a question as to whether method_exchangeImplementations() is thread safe. The source says it is (and it was not several major release prior) and so does the documentation.
As Brad Allred said, this is unlikely to be an optimization worth pursuing.
According to the documentation, method_exchangeImplementations() is atomic. Presumably that means that if one of the two methods being exchanged is called from another thread at the same time as method_exchangeImplementations() is being run, it may get the previous (non-swapped) method, but it won't get something inconsistent (e.g. won't crash).
Note that dispatch_once() is thread safe, and also means that as long as all references to the singleton instance are obtained via +sharedInstance, no thread will have a reference to the object before the swizzling is complete.
Finally, I don't normally like adding this kind of thing to answers, because I realize that sometimes questioners are just trying to learn more about how things work, rather than trying to write production code. However, if you're planning to use this in real, shipping code, you should rethink it. Swizzling tends to be a "bad code smell", and it's likely that there's a better way to do whatever it is you're trying to accomplish (which is still not clear to me).

How to enforce __weak reference in parameters for protocol implementation

I have a protocol for which I want the implementations to use __weak references for method arguments. I define my protocol as:
#protocol TestProtocol
-(void) op:(__weak NSObject*)x;
#end
Then I create an implementation:
-(void) op:(NSObject*)x
{
}
And x becomes an strong reference. If I move the __weak declaration to the protocol implementation, 'x' is a weak reference.
As the caller of the protocol already keeps a strong reference, I want to ensure that the implementations don't create another strong reference.
I'm a tad surprised the compiler doesn't complain about a declaration mismatch. And, sure enough, it doesn't. I filed radar #13730581 to see what the compiler folks say.
As #hypercrypt cites, ARC isn't going to retain or release the arguments to a method in the general case. One of the few cases where the performance vs. correctness sacrifice was large enough to warrant such a tradeoff. (Note that you'll see a storeStrong in the non-optimized case but no such thing in the -Os case Release build case).
Which means you are really defending against a strong reference being created against the object by implication of the code in the method body (and, as per comments, that said strong reference isn't torn down when an #throw goes "over" the frame).
There isn't much you can do about that -- if you pass x off to, say, NSMutableArray's addObject: method, it'll create a strong reference.
Thus, in the general case, there isn't really a means of preventing a strong reference to an object from being created as a side effect of variable usage.
Specific to NSException cleanup, it isn't worth worrying about. Exceptions should be fatal and the state of the app after an exception is thrown is undefined (unless you can ensure that no system code was in any way involved with the exception, which isn't really viable).
// code tossed in main.m to play w/compiler behavior
#protocol TestProtocol
-(void) op:(__weak NSObject*)x;
#end
#interface DogBowl:NSObject <TestProtocol>
#end
#implementation DogBowl
-(void) op:(NSObject*)x
{
}
#end

ARC, non-ARC, and inheritance

I haven't used ARC yet other than to deal with it when it forces it's way into a project via 3rd party code. I've read all the ARC docs but haven't seen an answer to this question:
If I have a class that's defined in a module compiled with -fobjc-arc, can I derive a new class from this in a module that is NOT ARC-enabled?
In my mind it should work fine as long as the derived class doesn't attempt to touch any ivars in the root class. It seems to me that even having a dealloc method that calls [super dealloc] would be fine in the derived class.
And, what about the other way around? Can I derive a ARC-enabled class from a non-ARC class? Should work fine too, right?
Bonus points: are there any gotcha's when mixing ARC and non-ARC code that I should make myself aware of?
There are no issues that I am aware of. You have to realize that ARC is something like a source code preprocessor, adding the memory management calls for you during the compilation. When you arrive at the linking phase, you can’t really tell ARC code from non-ARC code. (This is probably an over-simplification, but one that should work for your purposes.) If your derived class has correct memory management and the super class has correct memory management, the result will work fine.
About the only difference I can think of is handling of weak properties. But I don’t know enough about those to say if it’s possible to arrive at buggy code using some combination of ARC and MRC code with weak properties.
This was a comment, but having thought about it I want to expand what it said.
Have you tried inheriting an ARC class from a normal subclass? My thoughts (without having tried it either) is that this will not work. Firstly, if the ARC class has public properties or ivars using ARC keywords, like weak I think you will get errors during compilation from the header file. Secondly, I don't know how the dealloc would work. Do you need to call [super dealloc] or not? I don't know.
Anyway, if your superclass is ARC, why would you not use ARC in any subclasses? There's no advantage to doing that at all.
Can I derive a ARC-enabled class from a non-ARC class? Should work fine too, right?
I was going to say that won't work either, but I would have been wrong. Virtually everything has to inherit from NSObject which is manual reference counted.
Yes, you may both implement non-ARC ancestor from ARC parent class, and ARC ancestor from non-ARC parent class.
Actually, ARC is a syntax sugar, or you may say, is just preprocessor which analyzes your source code at compile step and inserts appropriate [release] and [retain] calls to your code. At runtime level nothing is changed (except for the weak properties).
ARC means the compiler takes care of memory management, non-ARC means you take care of it, but in both cases memory management works exactly the same way:
If an object must stay alive, its retain counter is increased (that's what retain does)
If an object is not needed anymore, its retain counter is decreased before the reference to it is lost (that's what release does)
If you are done with an object but it must not die yet, e.g. as you need to return it as a method result (and you don't want to return a dead object), it must be added to an autorelease pool that will decrease its retain count at a later time (that's what autorelease does, it's like saying "call release on that object at some future time.")
Newly created objects have a retain count of 1.
If the retain count reaches zero, the object is freed.
Whether you do all that yourself or the compiler does it for you, it plays no role. After compilation, these methods are being called, also with ARC, but with ARC the compiler has decided for you when which method is called. There is some extra magic, e.g. ARC doesn't always have to add objects to autorelease pools when returning them as method result, this can often be optimized away, but you don't have to care as this magic is only applied if the caller and the called method both are using ARC; if one of them isn't, then a normal autorelease is used (which still works in ARC exactly as it used to).
The only thing you must take care of is retain cycles. Whether you use ARC or not, reference counting can't deal with retain cycles. No difference here.
Pitfalls? Careful with Toll Free Bridging. A NSString * and a CFStringRef are in fact the same thing but ARC doesn't know about the CF-world, so while ARC takes care of the NSString, you must take care of the CFString. When using ARC, you need to tell ARC how to bridge.
CFStringRef cfstr = ...;
NSString * nsstr = (__bridge_transfer NSString *)cfstr;
// NSString * nsstr = [(NSString *)cfstr autorelease];
Code above means "ARC, please take ownership of that CFString object and take care of releasing it as soon as you are done with it". The code behaves like the code shown in the comment below; so careful, cfstr should have a retain count of at least one and ARC will release it at least once, just not yet. The other way round:
NSString * nsstr = ...;
CFStringRef cfstr = (__bridge_retained CFStringRef)cftr;
// CFStringRef cfstr = (CFStringRef)[nsstr retain];
Code above means "ARC, please give me ownership of that NSString, I'll take care of releasing it once I'm done with it". Of course, you must keep that promise! At some time you will have to call CFRelease(cfstr) otherwise you will leak memory.
Finally there's (__bridge ...) which is just a type cast, no ownership is transferred. This kind of cast is dangerous as it can create dangling pointers if you try to keep the cast result around. Usually you use it when just feeding an ARC object to a function expecting a CF-object as ARC will for sure keep the object alive till the function returns, e.g. this is always safe:
doSomethingWithString((__bridge CFStringRef)nsstr);
Even if ARC was allowed to release nsstr at any time as no code below that line ever accesses it anymore, it will certainly not release it before this function has returned and function arguments are by definition only guaranteed to stay alive until the function returns (in case the function wants to keep the string alive, it must retain it and then ARC won't deallocate it after releasing it as the retain count won't become zero).
The thing most people seem to struggle with is passing ARC objects as void * context, as you sometimes have to with older API, yet that is in fact dead simple:
- (void)doIt {
NSDictionary myCallbackContext = ...;
[obj doSomethingWithCallbackSelector:#selector(iAmDone:)
context:(__bridge_retained void *)myCallbackContext
];
// Bridge cast above makes sure that ARC won't kill
// myCallbackContext prior to returning from this method.
// Think of:
// [obj doSomethingWithCallbackSelector:#selector(iAmDone:)
// context:(void *)[myCallbackContext retain]
// ];
}
// ...
- (void)iAmDone:(void *)context {
NSDictionary * contextDict = (__bridge_transfer NSDictionary *)context;
// Use contextDict as you you like, ARC will release it
// prior to returning from this method. Think of:
// NSDictionary * contextDict = [(NSDictionary *)context autorelease];
}
And I have to real big gotcha for you that are not that obvious at first sight. Please consider this code:
#implementation SomeObject {
id _someIVAR;
}
- (void)someMethod {
id someValue = ...;
_someIVAR = someValue;
}
This code is not the same in ARC and non ARC. In ARC all variables are strong by default, so in ARC this code behaves just like this code would have:
#interface SomeObject
#property (retain,nonatomic) id someIVAR;
#end
#implementation SomeObject
- (void)someMethod {
id someValue = ...;
self.someIVAR = someValue;
}
Assigning someValue will retain it, the object stays alive! In non-ARC the code will behave like this one:
#interface SomeObject
#property (assign,nonatomic) id someIVAR;
#end
#implementation SomeObject
- (void)someMethod {
id someValue = ...;
self.someIVAR = someValue;
}
Note the property is different, as ivar's in non-ARC are neither strong or weak, they are nothing, they are just pointers (in ARC that is called __unsafe_unretained and the keyword here is unsafe).
So if you have code that uses ivars directly and doesn't use properties with setters/getters to access them, then switching from non-ARC to ARC can cause retain cycles in code that used to have sane memory management. On the other hand, moving from ARC to non-ARC, code like that can cause dangling pointers (pointers to former objects but since the object has already died, these point to nowhere and using them has unpredictable results), as objects that used to be kept alive before may now die unexpectedly.

Why does ARC retain method arguments?

When compiling with ARC, method arguments often appear to be retained at the beginning of the method and released at the end. This retain/release pair seems superfluous, and contradicts the idea that ARC "produces the code you would have written anyway". Nobody in those dark, pre-ARC days performed an extra retain/release on all method arguments just to be on the safe side, did they?
Consider:
#interface Test : NSObject
#end
#implementation Test
- (void)testARC:(NSString *)s
{
[s length]; // no extra retain/release here.
}
- (void)testARC2:(NSString *)s
{
// ARC inserts [s retain]
[s length];
[s length];
// ARC inserts [s release]
}
- (void)testARC3:(__unsafe_unretained NSString *)s
{
// no retain -- we used __unsafe_unretained
[s length];
[s length];
// no release -- we used __unsafe_unretained
}
#end
When compiled with Xcode 4.3.2 in release mode, the assembly (such that I'm able to understand it) contained calls to objc_retain and objc_release at the start and end of the second method. What's going on?
This is not a huge problem, but this extra retain/release traffic does show up when using Instruments to profile performance-sensitive code. It seems you can decorate method arguments with __unsafe_unretained to avoid this extra retain/release, as I've done in the third example, but doing so feels quite disgusting.
See this reply from the Objc-language mailing list:
When the compiler doesn't know anything about the
memory management behavior of a function or method (and this happens a
lot), then the compiler must assume:
1) That the function or method might completely rearrange or replace
the entire object graph of the application (it probably won't, but it
could). 2) That the caller might be manual reference counted code, and
therefore the lifetime of passed in parameters is not realistically
knowable.
Given #1 and #2; and given that ARC must never allow an object to be
prematurely deallocated, then these two assumptions force the compiler
to retain passed in objects more often than not.
I think that the main problem is that your method’s body might lead to the arguments being released, so that ARC has to act defensively and retain them:
- (void) processItems
{
[self setItems:[NSArray arrayWithObject:[NSNumber numberWithInt:0]]];
[self doSomethingSillyWith:[items lastObject]];
}
- (void) doSomethingSillyWith: (id) foo
{
[self setItems:nil];
NSLog(#"%#", foo); // if ARC did not retain foo, you could be in trouble
}
That might also be the reason that you don’t see the extra retain when there’s just a single call in your method.
Passing as a parameter does not, in general, increase the retain count. However, if you're passing it to something like NSThread, it is specifically documented that it will retain the parameter for the new thread.
So without an example of how you're intending to start this new thread, I can't give a definitive answer. In general, though, you should be fine.
Even the answer of soul is correct, it is a bit deeper than it should be:
It is retained, because the passed reference is assigned to a strong variable, the parameter variable. This and only this is the reason for the retain/release pair. (Set the parameter var to __weak and what happens?)
One could optimize it away? It would be like optimizing every retain/release pairs on local variables away, because parameters are local variables. This can be done, if the compiler understands the hole code inside the method including all messages sent and functions calls. This can be applied that rarely that clang even does not try to do it. (Imagine that the arg points to a person (only) belonging to a group and the group is dealloc'd: the person would be dealloc'd, too.)
And yes, not to retain args in MRC was a kind of dangerous, but typically developers know their code that good, that they optimized the retain/release away without thinking about it.
It will not increment behind the scenes. Under ARC if the object is Strong it will simply remain alive until there are no more strong pointers to it. But this really has nothing to do with the object being passed as a parameter or not.

can we override alloc and dealloc in objective C?

I know that this is rarely required to override the alloc or dealloc methods,but if required is it possible in iPhone programming?
You can and indeed, you should (if using manual memory management) override dealloc to release any resources you hold (not forgetting to call [super dealloc] when finished). Overriding alloc is possible but, as you say, rarely needed.
In general, overriding alloc is only done when you wish to, eg, allocate an object from a pool of available instances, or perhaps allocate a variable amount of storage for the object based on some external parameter. (In C++ you can access the new parameters and allocate based on them, but Objective-C does not give you access to the initXXX parameters.)
I've never attempted any of this, and I suspect that its a bit of a minefield -- you need to study up on the structures and be pretty careful.
As Adam said, you should ALWAYS (in a reference counted environment) override dealloc if there are any retained objects held by your object.
Update: An interesting thing you can do ... in RedClass or a superclass of it code something like:
+(id)alloc {
if (self == [RedClass class]) {
return [BlueClass alloc];
}
else {
return [super alloc];
}
}
The net result is that whenever you execute [RedClass alloc] a BlueCLass object will be returned. (NB: Presumably BlueClass is a subclass of RedClass, or things will get seriously mucked up shortly after the object is returned.)
Not saying that it's a good idea to do this, but it's possible (and I don't offhand know of any cases where it wouldn't work reliably for vanilla user-defined classes). And it does have a few possible uses.
Additional note: In some cases one might want to use [self isSubclassOf:[RedClass class]] rather than == (though that has some serious pitfalls).