2012-01-05 2 views
0

J'ai une classe modèle appelée OrdinalObjectList qui est simplement une carte avec une clé de pointeurs int et object. Son but est de fournir une collection de pointeurs d'objets accessibles par une clé ordinale. Voici la classe:EXC_BAD_ACCESS lors de la tentative de suppression du pointeur valide (xcode C++)

template <typename O> 
class OrdinalObjectList { 

public: 
    std::map<int, O*> List; 
    OrdinalObjectList() {}; 
    virtual ~OrdinalObjectList() 
    { 
     // Need to delete the objects in the map 
     typename std::map<int, O*>::iterator i; 
     for (i = List.begin(); i != List.end(); i++) 
     { 
      O* d = i->second; 
      delete d; 
     } 
    }; 

sur la destruction du OrdinalObjectList, les boucles destructor à travers la carte et supprime les objets. Cela a bien fonctionné jusqu'à présent, mais il reçoit actuellement une erreur EXC_BAD_ACCESS lors de la suppression du deuxième des deux objets de la collection.

Sur le premier passage d est 'FSCE :: Client' * 0x10088e600 qui supprime est sans problème. Sur la deuxième passe, d est 'FSCE :: Customer' * 0x100897e00 qui, lorsque supprime 'd provoque l'EXC_BAD_ACCESS. Je peux accéder aux membres du second 'd' dans le débogueur. c'est-à-dire d-> lifeid int 2, indiquant que l'objet FSCE :: Customer est un objet valide et que 'd' est un pointeur valide.

Quelles sont les étapes à suivre pour déterminer la cause de EXC_BAD_ACCESS?

+2

Exécutez le code en utilisant un outil destiné à détecter l'accès après libre, comme 'valgrind'. Très probablement, une opération précédente malloc/free/new/delete est en train de corrompre le tas, provoquant l'échec de cette suppression. –

+0

Je le fais maintenant. Valgrind pour OSX n'est pas complet, mais je vais voir ce qu'il doit rapporter. Je devrais également noter que l'erreur ne se produit pas si j'exécute le programme monothread, il se produit seulement après le traitement multi-thread. Je me demande si les threads de traitement ne se sont pas détachés correctement et bloquent l'objet. –

Répondre

0

Éditer: Ci-dessous est incorrect.

Pas vraiment une réponse, mais quand j'ai réduit le nombre de threads à 4, le problème disparaît. Auparavant, j'avais défini le nombre de threads à 8, le boxen est Core i7, qui est de 4 cœurs avec Hyper Threading.

Je ne peux que supposer qu'il y a un problème avec Hyper Threading, soit dans le noyau OSX ou LLVM. J'ai des optimisations réglées sur O3, à un moment donné, je vais désactiver les optimisations et voir si cela fonctionne sur 8 threads, mais en attendant, 4 threads est seulement 10% plus lent que 8, donc je vais continuer avec ça.

Le problème était avec un grand tableau dans les objets que je supprimais. Le tableau a été créé dans le constructeur et supprimé dans la destructor similaire à ce (données des noms de membres ont été modifiés):

Matrix::Matrix(int maxa, int maxb, int maxc) 
{ 
    asize = maxa; 
    bsize = maxb; 
    csize = maxc; 
    matrixsize = a * b * c; 
    matrix = new double [matrixsize]; 
} 
Matrix::~Matrix() 
{ 
    delete [] matrix; 
} 

Jusqu'à présent, si bon, mais dans la définition des valeurs dans la matrice, j'ai eu un bug.

void Matrix::SetValue(int a,int b,int c,double value) 
{ 
    int index = (a * asize) + (b * bsize) + c; 
    matrix[index] = value; 
} 

Le bug dans une autre partie du code qui a mis « MAXC » signifiait que l'indice serait parfois supérieur à matrixsize que j'ai découvert en ajoutant un chèque et le jeter.

void Matrix::SetValue(int a,int b,int c,double value) 
{ 
    int index = (a * asize) + (b * bsize) + c; 
    if (index >= matrixsize) throw; 
    matrix[index] = value; 
} 

Cela se traduirait par un accès à la mémoire en dehors de ce qui a été attribué dans le constructeur, et quand la suppression a été appelé, l'erreur de EXC_BAD_ACCESS être élevé. La chose curieuse est pourquoi EXC_BAD_ACCESS n'a pas été élevé dans Matrix :: SetValue pendant l'exécution, mais je suppose que la réponse a quelque chose à voir avec le fait qu'il n'y ait aucune vérification des limites sur les offsets d'index de tableau. Si quelqu'un peut faire la lumière sur ce que je serais le plus intéressé, mais pour l'instant, cette réponse est pour quiconque trouve cette réponse à partir d'une recherche sur le Web.

+0

Il n'y a pas de vérification d'index par langue. La protection de la mémoire au niveau du système d'exploitation fonctionne également uniquement sur les limites de page MMU, par ex. il n'est déclenché que lorsque vous essayez d'accéder à une page MMU qui ne vous a pas été attribuée. Ce qui s'est probablement passé, c'est que vous avez écrit sur les métadonnées de la pile de tas qui résident habituellement juste avant le bloc de tas alloué, en fonction de l'implémentation. Donc, lors de la libération d'un bloc avec des métadonnées corrompues, il en résulte un mauvais accès. – laalto

+0

Notez également que votre calcul d'index n'est probablement pas ce que vous vouliez - par ex. pour la matrice 3x3x3, les deux (1,2,3) et (2,1,3) partagent le même index. – laalto

+0

Désolé, j'ai tapé cela de la mémoire, c'est effectivement: (a * bsize * csize) + (b * csize) + c; . Merci pour votre commentaire sur les limites de la page MMU. –

0

Je ne peux pas dire avec certitude, mais est-il possible que vous supprimiez le 1er et les 2èmes éléments (inexistants), plutôt que les 0ème et 1er éléments? Assurez-vous de supprimer ce que vous pensez supprimer.

+0

Non, il supprime les éléments corrects. Je viens de remarquer que si je réduis les threads de traitement (le code ci-dessus est exécuté dans le thread principal) à 1, je n'obtiens pas l'erreur, et les objets corrects sont supprimés sans problème. –

0

EXC_BAD_ACCESS peut facilement être tracé en activant des objets zombie.

Pour XCode 4.x voir How do I set up NSZombieEnabled in Xcode 4?

Pour les autres versions de XCode, vous pouvez le trouver sur Internet.

+0

Je pensais que NSZombieEnabled était seulement pour Objective-C, je ne savais pas qu'il pourrait être activé pour C++. En regardant cela: http://www.cocoabuilder.com/archive/cocoa/226062-instance-variables-not-destructed-if-nszombieenabled.html Il pourrait être préférable d'utiliser malloc gardé. Merci pour votre réponse. –

+0

Merci Thompson. :) –

Questions connexes