2012-02-02 15 views
5

He estado trabajando en un proyecto desde hace un tiempo y decidí dar el salto a ARC. Encontré un código que estaba bombardeando cada vez, y me gustaría saber por qué. He conseguido simplificarlo hasta este fragmento:ARC & Malloc: EXEC_BAD_ACCESS

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; 
} 

No estoy muy seguro de lo que está pasando aquí, cansado esto en 4 proyectos diferentes, y todos ellos fallar. ¿Hay algún problema con mi llamada malloc? A veces devuelve nulo, y otras veces devuelve un puntero al que no puedo acceder.

+0

¿Por qué typedef? Se supone que los punteros a objetos que no están calificados de otra manera son '__strong'. –

+0

Porque en el proyecto real, 'MYID' es una parte de una estructura (ccCArray de cocos2d). Además, el código no se compilará sin un calificador de propiedad, ya que no forma parte de un selector donde el propietario podría ser "propio". –

+0

No estoy seguro de lo que quiere decir con "porque no es parte de un selector donde el propietario podría ser 'uno mismo'". El "propietario" de un objeto asignado en un método es la pila misma, no el valor de 'self'. También tenga en cuenta que no puede colocar punteros de objeto '__strong' (o' __suave') en una estructura C en ARC, debe usar '__unsafe_unretained' y administrar la memoria explícitamente (por ejemplo, con algún código que no sea ARC o con' CFRetain() '/'CFRelease()'). –

Respuesta

13

El bloqueo se debe a que estás transfiriendo memoria malloc a una matriz C de objetos. En el momento en que intente asignar uno de los espacios, ARC lanzará el valor anterior, que será memoria basura. Intente usar calloc() en lugar de malloc() para obtener la memoria puesta a cero y debería funcionar.

Tenga en cuenta que su llamada realloc() también no cero llenar cualquier nueva memoria que se asigna, por lo que si usted necesita el realloc() entonces es posible que desee estar usando un void* puntero temporal que luego un relleno de cero manualmente antes de asignar a su objeto formación.

+3

dang. sutil. realmente debe saber mucho sobre retener/liberar/C para usar ARC en esta instancia. – nielsbot

+0

Gracias Kevin, eso fue todo. –

+0

@nielsbot: Siempre que te apegues a Obj-C no deberías tener un problema. Este tipo de cosas solo surgen cuando se intenta combinar elementos C básicos (como 'malloc()') con ARC. –

8

La función malloc no pone a cero la memoria que asigna. La memoria puede contener basura al azar.

De la guía Clang Automatic Reference Counting, sección 4.2:

Para __strong objetos, el nuevo pointee se retiene primero; segundo, el lvalue está cargado de semántica primitiva; tercero, el nuevo punto se almacena en el valor l con semántica primitiva; y finalmente, se lanza el antiguo pointee.

Entonces, lo que probablemente esté sucediendo aquí es malloc devolviendo memoria que contiene valores aleatorios distintos de cero. ARC intenta usar ese valor aleatorio como un puntero a un objeto y lanzarlo, pero no es un puntero de objeto válido. Choque.