2012-02-02 10 views
5

Ho lavorato a un progetto da qualche tempo e ho deciso di passare a ARC. Mi sono imbattuto in un codice che stava bombardando ogni volta, e mi piacerebbe sapere perché. Sono riuscito a semplificare il basso per questo frammento di codice: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; 
} 

Io non sono molto sicuro di quello che sta accadendo qui, stanco questo in 4 progetti diversi, e tutti fallire. C'è qualcosa di sbagliato nella mia chiamata malloc? A volte restituisce null e altre volte restituisce un puntatore a cui non riesco ad accedere.

+0

Perché il typedef? I puntatori di oggetti che non sono qualificati in altro modo sono considerati "__strong". –

+0

Perché nel progetto attuale, 'MYID' è una parte di una struct (ccCArray di cocos2d). Inoltre, il codice non verrà compilato senza un qualificatore per la proprietà, perché non fa parte di un selettore in cui il proprietario potrebbe essere 'self'. –

+0

Non sono sicuro di cosa intendi con "perché non fa parte di un selettore in cui il proprietario potrebbe essere 'sé'". Il "proprietario" di un oggetto allocato in un metodo è lo stack stesso, non il valore di "self". Si noti inoltre che non è possibile posizionare i puntatori di oggetto '__strong' (o' __weak') in una struttura C in ARC, è necessario utilizzare '__unsafe_unretained' e gestire la memoria esplicitamente (ad esempio con un codice non ARC o con' CFRetain() '/'CFRelease()'). –

risposta

13

L'arresto è dovuto al fatto che stai trasmettendo la memoria di malloc'd a un array C di oggetti. Nel momento in cui si tenta di assegnare a uno degli slot, ARC rilascerà il valore precedente, che sarà la memoria inutile. Prova a utilizzare calloc() anziché malloc() per ottenere la memoria azzerata e dovrebbe funzionare.

Nota che la chiamata realloc() inoltre non zero riempire qualsiasi nuova memoria che è allocata, quindi se avete bisogno del realloc() quindi si consiglia di utilizzare un puntatore temporanea void* che poi zero riempire manualmente prima di assegnare al vostro oggetto array.

+3

dang. sottile. in questo caso devi davvero sapere molto su retain/release/C per usare ARC. – nielsbot

+0

Grazie Kevin, è andata così. –

+0

@nielsbot: Finché ci si attiene a Obj-C non si dovrebbe avere un problema. Questo genere di cose emerge solo quando si cerca di combinare elementi di base in C (come 'malloc()') con ARC. –

8

La funzione malloc non azzera la memoria allocata. La memoria può contenere rifiuti casuali.

Dalla guida Clang Automatic Reference Counting, paragrafo 4.2:

Per __strong oggetti, la nuova pointee viene dapprima trattenuto; in secondo luogo, il lvalue è caricato con semantica primitiva; in terzo luogo, il nuovo pointee è immagazzinato nel lvalue con semantica primitiva; e infine, il vecchio pointee viene rilasciato.

Quindi quello che probabilmente sta succedendo qui è malloc restituisce memoria contenente valori casuali diversi da zero. ARC tenta di utilizzare quel valore casuale come puntatore a un oggetto e di rilasciarlo, ma non è un puntatore di oggetto valido. Crash.