Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ARC & Malloc: EXEC_BAD_ACCESS

I have been working on a project for some time now, and I decided to make the jump to ARC. I came across some code that was bombing out every time, and I would like to know why. I have managed to simplify it down to this snippet:

typedef __strong id MYID;

int main(int argc, char *argv[])
{ 
    MYID *arr = (MYID *) malloc(sizeof(MYID) * 4);

    arr[0] = @"A";     // always get an EXEC_BAD ACCESS HERE
    arr[1] = @"Test";
    arr[2] = @"Array";
    arr[3] = @"For";

    // uh oh, we need more memory
    MYID *tmpArray = (MYID *) realloc(arr, sizeof(MYID) * 8);
    assert(tmpArray != NULL);

    arr = tmpArray;

    arr[4] = @"StackOverflow";  // in my actual project, the EXEC_BAD_ACCESS occurs here
    arr[5] = @"Is";
    arr[6] = @"This";
    arr[7] = @"Working?";

    for (int i = 0; i < 8; i++) {
        NSLog(@"%@", arr[i]);
    }

    return 0;
}

I'm not quite sure what is happening here, tired this in 4 different projects, and they all fail. Is there something wrong with my malloc call? Sometimes it returns null, and other times it returns a pointer that I can't access.

like image 263
Richard J. Ross III Avatar asked Feb 02 '12 20:02

Richard J. Ross III


2 Answers

The crash is because you're casting malloc'd memory to a C array of objects. The moment you try to assign to one of the slots, ARC will release the previous value, which will be garbage memory. Try using calloc() instead of malloc() to get zeroed memory and it should work.

Note that your realloc() call will also not zero-fill any new memory that's allocated, so if you need the realloc() then you may want to be using a temporary void* pointer that you then zero-fill manually before assigning to your object array.

like image 144
Lily Ballard Avatar answered Oct 23 '22 10:10

Lily Ballard


The malloc function does not zero the memory it allocates. The memory can contain random garbage.

From the Clang Automatic Reference Counting guide, section 4.2:

For __strong objects, the new pointee is first retained; second, the lvalue is loaded with primitive semantics; third, the new pointee is stored into the lvalue with primitive semantics; and finally, the old pointee is released.

So what's probably happening here is malloc is returning memory that contains random non-zero values. ARC tries to use that random value as a pointer to an object and release it, but it's not a valid object pointer. Crash.

like image 42
rob mayoff Avatar answered Oct 23 '22 09:10

rob mayoff