Plantage bizarroà¯de ; un objet perd son identité
J'ai un méchant plantage bien bizarre, et après quelques heures de patiente enquête je me suis aperçu que certains des objets de l'application "perdent" leur identité. Ils ne sont plus reconnus comme des objets Objective-C mais leur contenu semble pourtant correct.
Lorsqu'un objet n'est plus "reconnu" l'appel d'une méthode quelconque plante (EXC_BAD_ACCESS code 1).
Ci après un exemple où je fais "po" et "p" sur l'un de ces objets.
Je précise que cet objet est un "singleton" créé selon les préceptes du modern Objective-C (avec dispatch_once, sous Xcode 4.4.1), et que tout fonctionne correctement si j'utilise un objet initialisé par "new" ; malheureusement j'ai vraiment besoin d'un singleton sur ce coup là .
Lorsque le singleton est pourri, plusieurs objets à l'intérieur de celui-ci se pourrissent aussi (pas tous).
Quelqu'un a déjà rencontré ce problème ? Et l'aurait résolu ?
Quelqu'un peut m'aider à aller plus loin dans mon enquête ? j'aimerais bien obtenir une alerte ou un genre de breakpoint lorsque une zone mémoire (celle qui contient mon objet) est modifiée, mais je n'ai pas trouvé comment faire sous lldb.
Je ne peux pas rester trop longtemps sur ce problème, alors je vais transformer toutes mes méthodes en méthodes de classe pour simuler un singleton. Mais je n'aime pas trop laisser un point obscur derrière moi.
Lorsqu'un objet n'est plus "reconnu" l'appel d'une méthode quelconque plante (EXC_BAD_ACCESS code 1).
Ci après un exemple où je fais "po" et "p" sur l'un de ces objets.
<br />
(lldb) po materialListManager<br />
(SKWMaterialListManager *) $60 = 0x07918e60 [no Objective-C description available]<br />
(lldb) p *materialListManager<br />
(SKWMaterialListManager) $61 = {<br />
(SKWPersistentListManager) SKWPersistentListManager = {<br />
(NSObject) NSObject = {<br />
(Class) isa = SKWMaterialListManager<br />
}<br />
(NSString *) _propertyListName = 0x00050d9c @"MaterialLists"<br />
(NSMutableDictionary *) _lists = 0x07c48cc0<br />
(NSMutableSet *) _persistentLists = 0x07c4e210<br />
(NSMutableDictionary *) _modifiedLists = 0x07a67e90<br />
}<br />
}<br />
(lldb)<br />
Je précise que cet objet est un "singleton" créé selon les préceptes du modern Objective-C (avec dispatch_once, sous Xcode 4.4.1), et que tout fonctionne correctement si j'utilise un objet initialisé par "new" ; malheureusement j'ai vraiment besoin d'un singleton sur ce coup là .
Lorsque le singleton est pourri, plusieurs objets à l'intérieur de celui-ci se pourrissent aussi (pas tous).
Quelqu'un a déjà rencontré ce problème ? Et l'aurait résolu ?
Quelqu'un peut m'aider à aller plus loin dans mon enquête ? j'aimerais bien obtenir une alerte ou un genre de breakpoint lorsque une zone mémoire (celle qui contient mon objet) est modifiée, mais je n'ai pas trouvé comment faire sous lldb.
Je ne peux pas rester trop longtemps sur ce problème, alors je vais transformer toutes mes méthodes en méthodes de classe pour simuler un singleton. Mais je n'aime pas trop laisser un point obscur derrière moi.
Connectez-vous ou Inscrivez-vous pour répondre.
Réponses
1) Utilises-tu ARC ou non ?
2) Quel est ton niveau en gestion mémoire ?
3) As-tu essayé d'activer les Zombies (edites ton scheme avec le menu Product -> Edit Schemes, et dans le scheme de Debug, va dans l'onglet "Diagnostics" pour activer les zombies)
4) Pour mettre un watchpoint sur une variable globale avec lldb, pour qu'il s'arrête quand la variable est modifiée (-w write), la commande c'est "[font=Verdana, Geneva, Arial, Helvetica, sans-serif]watchpoint set variable -w write global_var[/font]". Si c'est pour mettre sur autre chose qu'une variable globale, le plus simple est de récupérer à un moment l'adresse mémoire que tu veux surveiller et utiliser la commande "[font=Verdana, Geneva, Arial, Helvetica, sans-serif]watchpoint set expression -w write -- my_addr[/font]" en remplaçant my_addr par l'adresse à surveiller en écriture
Avec les Zombies ceci dit tu devrais trouver plus facilement ton erreur, à savoir où l'objet a été désalloué avant que tu ne tentes de le réutiliser.
2) En principe je n'ai pas de souci mémoire, je passe régulièrement un coup de Leaks pour vérifier mais j'ai rarement des soucis
3) J'ai activé les zombies mais j'ai toujours un plantage (pas au même endroit cette fois, mais sur le même appel de méthode sur le même objet)
4) Je vais explorer le coup des watchpoints ça me parait très prometteur ; je te tiens au courant
Après avoir relancé le bazar, pour trouver le méchant qui me la modifie subrepticement : tiny_free_list_add_ptr
Une fonction qui apparemment est impliquée dans la gestion du tas ; la piste du problème de gestion mémoire semble se confirmer ...
Et ça ne me permet pas trop d'avancer car la pile est vide à ce moment là dans le thread principal (UIApplicationMain, c'est tout).
Truc vraiment bizarre, ce Singleton est un bête (pas si bête que ça en fait) container initialisé avec une property list. Il contient principalement un NSMutableDictionary qui contient des NSMutableArray. Il contient des fonctions qui permettent de modifier des listes existantes ou d'en ajouter de nouvelles (il faut bien utiliser les mutables !) mais ces fonctions ne sont pas du tout utilisées entre l'initialisation de la liste et le plantage. Les objets contenus sont donc tous retenus, et en ARC je ne peux pas faire de release.
En fait le plantage a lieu dans les tests unitaires, chaque test fait moins de 10 lignes de code. L'environnement n'est donc pas trop compliqué à maà®triser. Le premier test passe sans encombre, au setUp de mon deuxième test le Singleton est tout pourri et le test plante (EXC_BAD_ACCESS).
Je continue l'enquête.
Ma propriété helpText était assign au lieu de strong. ça fait des semaines que c'est comme ça et ça marchait très bien car cette propriété prend toujours une String constante comme valeur, mais pas dans ces nouveaux tests de mon nouveau Singleton. Je regardais pas au bon endroit !
Merci Ali de m'avoir mis sur la piste. Et puis ça m'a au moins permis d'apprendre à utiliser les watchpoints, ça me resservira certainement.