I am facing a weird OC Exception, it looks that I am sending a message to a released address, but when I
try to check if it is NULL, it still crashs.
try to debug or add #try #catch, it catches nothing but runs for days, no crash at all.
exception
Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Subtype: KERN_INVALID_ADDRESS at 0x0000000000000010
VM Region Info: 0x10 is not in any region. Bytes before following region: 4304617456
REGION TYPE START - END [ VSIZE] PRT/MAX SHRMOD REGION DETAIL
UNUSED SPACE AT START
--->
__TEXT 100934000-100a98000 [ 1424K] r-x/r-x SM=COW ...x/APP
Termination Signal: Segmentation fault: 11
Termination Reason: Namespace SIGNAL, Code 0xb
Terminating Process: exc handler [18302]
Triggered by Thread: 22
code below is not strict ,just shows the logic ( code is running in one serial dispatch queue )
struct st_type {
void *arg;
};
static NSMutableDictionary *dictionary;
// init values
void init ()
{
// there is a static dictionary to retain the object
dictionary = [[NSMutableDictionary alloc]init];
// an object reference saved in dictionary and a struct holds it's pointer
NSObject *obj = [[NSObject alloc]init];
struct st_type *st = malloc(sizeof(struct st_type));
st->arg = (__bridge void *)obj;
dictionary[#"cached"] = obj;
// then the struct * passes to every where, I think it's safe because the object always in the dictionary.
...
}
// the only place to release the nsobject, so I think there is no chance to EXC_BAD_ACCESS, but ...
void release_object(struct st_type *st, NSObject obj){
[dictionary removeObjectForKey:#"cached"];
st->arg = NULL;
}
// some where to use the struct
void use_struct(struct st_type *st){
if(st->arg == NULL){
return;
}
// if I add try catch, it never crashs
// #try {
NSObject *obj = (__bridge NSObject*)st->arg;
[obj description]; // crash here.
// } #catch (NSException *exception) { print some log but it never reaches here... }
}
Could anyone help me what I can do next to fix this error?
If I understand correctly you want to store a reference to an Objective-C object as a void *. This is a similar use case as the old-style context or userInfo pointers that were passed as callbacks to sheets, for example.
See ARC: __bridge versus __bridge_retained using contextInfo test case for an example. I also assume you're using ARC (please read Casting and Object Lifetime Semantics).
Assuming the lifetime of the struct is longer than that of the Objective-C object, and that you explicitly set and release the object in the struct, you shouldn't need a dictionary for memory management.
Once the struct and object are allocated (using malloc and [[XX alloc] init] respectively), you can transfer ownership of the object out of ARC and store it in st->arg using a (__bridge_retained void *) cast.
To use the object, cast using (__bridge NSObject *). This will not change ownership.
When you are ready to release the object, pass ownership back to ARC by casting using (__bridge_transfer NSObject *). Then you can set the void * pointer to NULL.
So overall something like:
struct st_type {
void *arg;
};
void init()
{
NSObject *obj = [[NSObject alloc] init];
struct st_type *st = malloc(sizeof(struct st_type));
// transfer ownership out of ARC
st->arg = (__bridge_retained void *)obj;
}
void use_struct(struct st_type *st){
// no change in ownership
NSObject *obj = (__bridge NSObject *)st->arg;
// use `obj`
}
void release_object(struct st_type *st){
// transfer ownership back to ARC
NSObject *obj = (__bridge_transfer NSObject *)st->arg;
st->arg = NULL;
}
Related
In a third-party lib I use, I am getting the warning
"Block captures an autoreleasing out-parameter"
What is the problem and how can I fix it?
- (BOOL)register:(NSString *)param error:(NSError **)errPtr
{
__block BOOL result = YES;
__block NSError *err = nil;
dispatch_block_t block = ^{ #autoreleasepool {
NSMutableArray *elements = [NSMutableArray array];
/**** Block captures an autoreleasing out-parameter,
which may result in use-after-free bugs ****/
/* on errPtr */
[self registerWithElements:elements error:errPtr];
}};
if (errPtr)
*errPtr = err;
return result;
}
When you have a method with an indirect non-const parameter (T **param) Clang with ARC automatically qualify such a parameter with __autoreleasing (T *__autoreleasing*). This happens because Clang reasonably assumes, that the calling side is not always required to release such an object, so it puts a requirement on the function to assign autoreleasing objects only. Thus this:
- (void)myMethod:(NSObject **)param {
*param = [NSObject new];
}
Turns into this under ARC:
- (void)myMethod:(NSObject *__autoreleasing*)param {
*param = [[NSObject new] autorelease];
}
This in turn imposes special requirements on the arguments for such a method, so in common scenario where you actually just pass some (strongly retained) object to the function:
NSObject *obj;
[self myMethod:&obj];
ARC in fact makes a temporary autoreleasing argument:
NSObject *__strong obj = nil;
NSObject *__autoreleasing tmp = obj;
[self myMethod:&tmp];
obj = [tmp retain];
What is the problem...
If, instead of (indirectly) passing strongly retained pointer, you pass your own indirect pointer, ARC doesn't make any temporary in between:
NSObject *__autoreleasing obj;
NSObject *__autoreleasing *objPtr = &obj;
[self myMethod:objPtr];
It means that the object "returned" by myMethod: doesn't get retained anymore, thus will be destroyed when current autorelease pool is drained. The same is true if you pass a parameter with the same semantic:
- (void)anotherMethod:(NSObject **)param {
[self myMethod:param];
}
Thus if, for any reason, you decide to wrap the invocation of myMethod: with an autorelease block, the code here ends up with a zombie object:
- (void)anotherMethod:(NSObject **)param {
#autoreleasepool {
[self myMethod:param]; // object was created and assigned to a autoreleasing pointer
} // ref. count of the object reached zero. `*param` refers to a released object
}
The same can potentially happen if you wrap the invocation with a block:
- (void)anotherMethod:(NSObject **)param {
void(^block)(void) = ^{
// "Block captures an autoreleasing out-parameter, which may result in use-after-free bugs" warning appears
[self myMethod:param];
};
block();
}
For this specific implementation no problem will happen, and you could just silence the error by explicitly giving the indirect pointer __autoreleasing qualifier (by which you inform Clang that you are well aware of possible consequences):
- (void)anotherMethod:(NSObject *__autoreleasing*)param {
void(^block)(void) = ^{
[self myMethod:param];
};
block();
}
But now you has to be very careful, because block is a first-party object, which can be retained and called from anywhere and there are countless scenarios where additional autorelease pool is spawned. E.g. this code will case the same zombie-object error:
- (void)anotherMethod:(NSObject *__autoreleasing*)param {
void(^block)(void) = ^{
[self myMethod:param];
};
... some code here ...
#autoreleasepool {
block();
}
}
The same if the autorelease pool is right in the block body:
- (void)anotherMethod:(NSObject **)param {
void(^block)(void) = ^{
#autoreleasepool {
[self myMethod:param];
}
};
block();
}
Having that said, Clangs doesn't warn about the error (it's actually obvious in your case, because you wrap the body of your block with an #autoreleasepool block), it just wants you to double check that you are aware of possible problems (as you can see, it's still possible to implement things like that, but you will have hard time to track all the errors if they appear).
how can I fix it?
This depends on your definition of "fix". You either can remove the autorelease pool block from the body of your block and qualify __autoreleasing parameter explicitly (provided it's merely called in the same thread somewhere in the method):
- (BOOL)register:(NSString *)param error:(NSError *__autoreleasing*)errPtr {
....
dispatch_block_t block = ^{
....
[self registerWithElements:elements error:errPtr];
};
block();
....
}
Or you can introduce another "local" variable to capture and pass it inside a block:
- (BOOL)register:(NSString *)param error:(NSError **)errPtr {
....
__block NSError *err;
dispatch_block_t block = ^{
#autoreleasepool {
....
[self registerWithElements:elements error:&err];
}
};
block();
*errPtr = err;
....
}
This again implies that the block is called synchronously in the method, but not necessarily within the same autorelease pool block. If you want to store the block for later use, or call it asynchronously, then you will need another NSError variable with prolonged lifetime to capture inside the block.
I've a c function which takes a callback function as one parameter, I'm going to write an Obj-C wrapper to a standard C API. I would like to replace C callbacks by blocks.
Let's imagine a C API:
void audioStopFunction(void (*callback)(void *), void *udata);
The Obj-C wrapper looks like this:
- (void)myAudioStopFunction:(dispatch_block_t)block
{
void *udata = (__bridge void *)block;
audioStopFunction(my_callback, udata);
}
void my_callback(void *udata)
{
dispatch_block_t block = (__bridge_transfer dispatch_block_t)udata;
block();
}
Now, I have some questions:
In myAudioStopFunction function, do i need to copy the block like below:
void *udata = (__bridge void *)[block copy];
In my_callback function, should i use __bridge instead of __bridge_transfer? And also, do i need to call Block_release after block()?
Will the code cause memory leak? if yes, then what's the correct way?
As the C callback is managed by the wrapper class it's most easy to let the class manage the ownership of the block. (I'm calling the block completionBlock, as this seems to be a bit more in line with Cocoa naming conventions.)
#interface AudioCallbackWrapper
#property (nonatomic) dispatch_block_t completionBlock;
#end
static void my_callback(void *udata)
{
dispatch_block_t block = (__bridge dispatch_block_t)udata;
if (block != nil)
block();
}
#implementation AudioCallbackWrapper
- (void)setCompletionBlock:(dispatch_block_t)completionBlock
{
_completionBlock = [completionBlock copy];
audioStopFunction(my_callback, (__bridge void *)_completionBlock);
}
- (void)dealloc
{
// remove the C callback before completionBlock is released
self.completionBlock = nil;
}
#end
Since the block's lifetime is managed by the enclosing wrapper, the C code never has to transfer ownership. So the code only contains __bridge casts to and from a void *.
Will the code cause memory leak? if yes, then what's the correct way?
Your original code would release the block every time the callback fires. The block pointer would dangle after the first callback.
I am trying to implement the countByEnumeratingWithState method in my objective-c class (say MyClass
In this method I do an
MyOtherClass *cl = [[MyOtherClass alloc] init];
buffer[count++] = cl;
The reason why I have to allocate objects on the fly is because those objects are stored 'elsewhere'.
However, when using this method from an application, it will crash:
for (const MyOtherClass *cl in myClassObj){
NSLog(#"obj: %#", cl.description);
}
The reason for this is most likely that ARC throws away my MyOtherClass object in countByEnumeratingWithState because the buffer is 'unretained'.
How can I make sure the MyOtherClass object 'retains' ?
More relevant information:
thread #4: tid = 0x5ca941, 0x0000000101a4cf8b libobjc.A.dylibobjc_msgSend + 11, stop reason = EXC_BAD_ACCESS (code=EXC_I386_GPFLT)
frame #0: 0x0000000101a4cf8b libobjc.A.dylibobjc_msgSend + 11
Why do you use const keyword? Const let you allocate object just for initialization and after then throw exception when you want to try change it. Try that:
for (MyOtherClass *cl in myClassObj){
NSLog(#"obj: %#", cl.description);
}
I am using an instance of the this class to pass necessary values to a function for sending Socket Data:
#interface SsdpParameters : NSObject
{
CFDataRef msg;
CFDataRef addr;
CFSocketRef sock;
}
#property CFDataRef msg;
#property CFDataRef addr;
#property CFSocketRef sock;
#end
This is the function that is responsible for sending the socket data:
-(void)SendSsdpResponse:(id)parameters
{
SsdpParameters *params = parameters;
CFDataRef msg = (CFDataRef)params.msg;
CFDataRef addr = (CFDataRef)params.addr;
CFSocketRef sock = (CFSocketRef)params.sock;
CFSocketError err = CFSocketSendData (sock, addr, msg, 0); // Program received signal: "EXC_BAD_ACCESS".
if (err)
{
NSLog(#"Error sending Valid Response");
}
}
This function sets up the socket and calls SendSsdpResponse after a 1 second delay:
- (void) sendValidResponses
{
NSMutableString *message = nil;
CFSocketRef sock = [self newSSDPSendSocket];
if(sock != nil)
{
struct sockaddr_in SSDPaddr;
memset(&SSDPaddr, 0, sizeof(SSDPaddr));
SSDPaddr.sin_family=AF_INET;
SSDPaddr.sin_addr.s_addr=inet_addr(SSDP_ADDRESS);
SSDPaddr.sin_port=htons(SSDP_PORT);
// Loop through list, sending SSDP
for (NSString *aKey in list)
{
message = [[NSMutableString alloc] initWithString:#"NOTIFY * HTTP/1.1\r\n"];
// Append more lines to message.
CFDataRef addr = CFDataCreate(NULL, (const UInt8*)&SSDPaddr, sizeof(SSDPaddr));
CFDataRef msg = CFDataCreate(NULL, (const UInt8*)[message UTF8String], [message lengthOfBytesUsingEncoding:NSUTF8StringEncoding]);
SsdpParameters *parameters = [[SsdpParameters alloc] init];
parameters.msg = msg;
parameters.addr = addr;
parameters.sock = sock;
[self performSelector:#selector(SendSsdpResponse:) withObject:parameters afterDelay:1.0];
CFRelease(addr);
CFRelease(msg);
[message release];
}
CFRelease(sock);
}
}
As you can see by the comment, in SendSsdpResponse, I an getting a "EXC_BAD_ACCESS" error when trying to call CFSendSocketData. I have a suspicion that it's because I am "passing" sock, addr, and msg and there is something the runtime does not like about this. I have run into this problem before with passing variables of the CF data types to other functions. I have yet to find an answer and hope someone here can finally help me understand what's going on behind the scenes.
Thanks!
EXC_BAD_ACCESS errors generally indicate that you're attempting to invoke a method on an instance that has already been deallocated. This is often the case when you fail to properly retain variables, especially when they're being passed between functions.
When you perform the selector with the delay, on this line:
[self performSelector:#selector(SendSsdpResponse:) withObject:parameters afterDelay:1.0];
You're providing the method with the parameters variable, which has the properties as defined in the header you provided. The problem is that right after the performSelector: method, you're releasing the memory referred to addr and msg. Since you're performing this selector with a delay, the memory that addr and msg point to is being deallocated prior to its use.
So, once this memory has been released, it is no longer "good" in the SsdpParameters object. You should (in the setter for these properties, on the SsdpParameters object) copy this memory, so that the original callers can release it safely.
You should investigate this function:
CFDataRef CFDataCreateCopy (
CFAllocatorRef allocator,
CFDataRef theData
);
Then, your setter could look like:
#implementation SsdpParameters
...
- (void)setMsg:(CFDataRef)m {
// You should also release msg if it already exists
msg = CFDataCreateCopy(CFAllocatorGetDefault(), m);
}
...
#end
To troubleshoot, try replacing the call to
[self performSelector:#selector(SendSsdpResponse:) withObject:parameters afterDelay:1.0];
with an immediate call to
[self SendSsdpResponse:parameters];
and see what happens.
If you still get "EXC_BAD_ACCESS", it means your parameters are set up incorrectly somehow. If, on the other hand, you don't get an error, it means that the parameter object is ok initially, but becomes invalid before the delay completes. For example, is the parameters object retaining or copying "addr" and "msg"?
Before ARC I had the following code that retains the delegate while an async operation is in progress:
- (void)startAsyncWork
{
[_delegate retain];
// calls executeAsyncWork asynchronously
}
- (void)executeAsyncWork
{
// when finished, calls stopAsyncWork
}
- (void)stopAsyncWork
{
[_delegate release];
}
What is the equivalent to this pattern with ARC?
I have occasionally needed to manually retain and release things (sometimes just for debugging) and came up with the following macros:
#define AntiARCRetain(...) void *retainedThing = (__bridge_retained void *)__VA_ARGS__; retainedThing = retainedThing
#define AntiARCRelease(...) void *retainedThing = (__bridge void *) __VA_ARGS__; id unretainedThing = (__bridge_transfer id)retainedThing; unretainedThing = nil
This works by using the __bridge_retained and __bridge_transfer to cast things to and from (void *) which causes things to be retained, or to create a strong reference without calling retain.
Have fun, but be careful!
Why not just assign your delegate object to a strong ivar for the duration of the asynchronous task?
Or have a local variable in executeAsyncWork
- (void)executeAsyncWork
{
id localCopy = _delegate;
if (localCopy != nil) // since this method is async, the delegate might have gone
{
// do work on local copy
}
}
Something like this:
- (void)startAsyncWork
{
id<YourProtocol> delegate = _delegate;
dispatch_async(/* some queue */, ^{
// do work
[delegate doSomething];
}
}
The block will retain the delegate as long as needed...