2017-07-12 2 views
0

Voici deux traces de pile de Crashlytics, les deux contenant la même ligne de mon code, mais aboutissant à deux crashs différents.iOS Crash sur la copie d'un NSArray EXC_BAD_ACCESS KERN_PROTECTION_FAILURE

# OS Version: 10.3.2 (14F90) 
# Device: iPad 5 
# RAM Free: 3.8% 
# Disk Free: 90.7% 

#0. Crashed: com.apple.main-thread 
0 libsystem_platform.dylib  0x18d365090 _platform_memset + 126 
1 libsystem_malloc.dylib   0x18d2ebd00 _nano_malloc_check_clear + 584 
2 libsystem_malloc.dylib   0x18d2eacb0 nano_calloc + 80 
3 libsystem_malloc.dylib   0x18d2dc4e8 malloc_zone_calloc + 168 
4 libsystem_malloc.dylib   0x18d2dc41c calloc + 40 
5 libobjc.A.dylib    0x18cd18160 class_createInstance + 76 
6 CoreFoundation     0x18e2b2928 __CFAllocateObject + 28 
7 CoreFoundation     0x18e29c064 +[__NSSingleObjectArrayI __new::] + 28 
8 CoreFoundation     0x18e18cd18 -[NSArray initWithArray:range:copyItems:] + 400 
9 MyApp       0x10010003c -[ConstituentDownload currentProgress] (ConstituentDownload.m:117) 
10 MyApp       0x1001000b4 -[ConstituentDownload currentProgress] (ConstituentDownload.m:118) 
11 MyApp       0x1001000b4 -[ConstituentDownload currentProgress] (ConstituentDownload.m:118) 
12 MyApp       0x1001000b4 -[ConstituentDownload currentProgress] (ConstituentDownload.m:118) 
13 MyApp       0x1001000b4 -[ConstituentDownload currentProgress] (ConstituentDownload.m:118) 
14 MyApp       0x1001000b4 -[ConstituentDownload currentProgress] (ConstituentDownload.m:118) 
15 MyApp       0x1001000b4 -[ConstituentDownload currentProgress] (ConstituentDownload.m:118) 
16 MyApp       0x1001000b4 -[ConstituentDownload currentProgress] (ConstituentDownload.m:118) 
17 MyApp       0x1001000b4 -[ConstituentDownload currentProgress] (ConstituentDownload.m:118) 
18 MyApp       0x1001000b4 -[ConstituentDownload currentProgress] (ConstituentDownload.m:118) 
19 MyApp       0x1001000b4 -[ConstituentDownload currentProgress] (ConstituentDownload.m:118) 
20 MyApp       0x100100234 -[ConstituentDownload sendProgressNotification] (ConstituentDownload.m:141) 
... button press stuff... 

et:

# OS Version: 10.3.1 (14E304) 
# Device: iPad 4 
# RAM Free: 4.7% 
# Disk Free: 12.2% 

#0. Crashed: com.apple.main-thread 
0 libobjc.A.dylib    0x1bc38692 objc_retain + 1 
1 CoreFoundation     0x1c8acf39 +[__NSArrayI __new:::] + 74 
2 CoreFoundation     0x1c8ae9f1 -[__NSArrayM copyWithZone:] + 174 
3 MyApp       0x189407 -[ConstituentDownload currentProgress] (ConstituentDownload.m:117) 
4 MyApp       0x18999f -[ConstituentDownload userInfoForProgressNotification] (ConstituentDownload.m:180) 
5 MyApp       0x189611 -[ConstituentDownload sendProgressNotification] (ConstituentDownload.m:144) 
...button press stuff... 

Et voici la méthode qui provoque l'accident:

- (float)currentProgress { 

    float sections = [self.childDownloads count] + 1; 
    float referencedProgress = 0.; 
    // This line causes the crash - where we copy the property array 
    for(ConstituentDownload *d in [self.childDownloads copy]) { 
     referencedProgress += d.currentProgress; 
    } 
    float progress = (super.currentProgress + referencedProgress)/sections; 
    return progress; 
} 

Le self.childDownloads est un objet contenant NSMutableArray du même type que cette méthode réside dans: le ConstituentDownload. Il est accédé à partir d'autres threads et peut avoir des éléments ajoutés, c'est pourquoi je le copie d'abord avant de le parcourir. Ce tableau a tendance à contenir 0-20 objets.

Ce blocage peut-il être causé par la mutation du tableau dans un thread différent, même si je le copie ici?

Cela peut-il être causé par une sorte de corruption de la mémoire? Si oui, pouvez-vous me diriger dans la bonne direction pour comprendre cela?

Cela peut-il être dû au fait qu'il n'y a plus de RAM sur l'appareil? Si oui, pourquoi cela n'aurait-il pas été signalé comme une erreur de mémoire au lieu de générer un rapport d'erreur?

Oui, cette méthode est récursive, dans un sens. Le parent ConstituentDownload appelle currentProgress sur chacun de ses téléchargements enfants, qui à son tour l'appellent sur chacun de leurs téléchargements enfants. La pile de crash a parfois seulement 1 appel récursif, et parfois environ 10, comme on le voit dans ces deux piles de crash.

Ce plantage n'a été observé que sur les appareils exécutant iOS 9 et iOS 10, mais probablement parce que presque tous mes utilisateurs utilisent ces deux versions du système d'exploitation.

Que signifie KERN_PROTECTION_FAILURE de toute façon?

Répondre

1

Je ne trouve pas de référence spécifique qui le précise, mais je pense que vous devez supposer qu'il n'est pas sûr de copier un tableau mutable de cette façon.

En règle générale, il n'est pas sûr de parcourir une NSMutableArray dans un thread, alors qu'il est muté à partir d'un autre thread. Quelle que soit la manière dont copy est implémenté sous le capot, il doit parcourir le tableau d'une certaine manière pour faire son travail. De votre description, il semble que vous ajoutiez/supprimiez des éléments de plusieurs threads différents. Utilisez-vous une sorte de verrouillage ou de sérialisation pour rendre ce thread-safe? Sinon, cela pourrait également provoquer l'accident à ce stade.

Et si vous l'êtes, vous devez utiliser ce même verrouillage pour protéger cette opération copy.