2009-10-04 8 views
0

Si je libère une instance de NSOperation avant de lui envoyer -init, j'obtiens un segmentation fault.Existe-t-il un bogue dans NSOperation sous Mac OS X 10.6?

raisons je pense que ce code est valide:

  • Apple fait cela dans its documentation.
  • Gnustep le fait dans son implementation of NSNumber, donc il est assez certain que c'est aussi dans le code d'Apple. (Au moins était.)
  • NSObject s -init ne fait rien, donc -release, qui appartient à NSObject devrait fonctionner avant cela.
// gcc -o test -L/System/Library/Frameworks -framework Foundation test.m 

#import <Foundation/Foundation.h> 

int main(int argc, char *argv[]) { 
    NSOperation *theOperation = [NSOperation alloc]; 
    [theOperation release]; 
} 
  • Que pensez-vous, est-ce un bug?
  • Pouvez-vous me montrer un exemple d'une autre classe qui a le même comportement?
  • Une idée de pourquoi cela se passe-t-il?
+0

@gs S'il vous plaît lire mon commentaire en réponse à la vôtre sur ma réponse :) –

+0

Mon point encore debout :). Je suis sûr que '-init' de NSOperation alloue un pointeur (à une structure ou à n'importe quoi d'autre). La valeur du pointeur n'est pas définie sur NULL par le runtime, donc l'appel '-release' libère un pointeur qui n'a pas été initialisé et dont la valeur est 0 (quelque part où vous n'avez pas accès: D) –

Répondre

7

Envoi de message autre que init à un objet qui n'a pas été initialisé est valide pas le code AFAIK. Appelez l'initialiseur de la superclasse, puis relâchez et je parie que ça ne va pas planter (bien que l'initialisation d'une classe retourne une classe complètement indépendante qui me frappe comme doubleplusungood).

+1

. Plus de détails à l'esprit. J'ai en fait compilé un projet de test pour m'assurer que ce n'était pas un bug latent quelque part. Ce n'est pas. – bbum

+0

Renvoyer une classe complètement indépendante est juste pour l'exemple. Je ne le fais pas dans mon code de travail. La classe 'NSNumber' de Gnustep envoie aussi' -release' avant l'initialisation. '-initWithCoder' n'appelle jamais' -init' aussi loin que je le sache. –

+0

'initWithCoder:' les méthodes appellent normalement jusqu'à super. – Chuck

2

Il n'y a rien de valide à propos de ce code.

Ressaisissez votre -init comme:

- (id) init 
{ 
    if (self = [super init]) { 
     [self release]; 

     NSNumber *number = [[NSNumber alloc] initWithInteger:6]; 
     return number; 
    } 
    return self; 
} 

Bien sûr, le code est encore un non-sens, mais il ne tombe pas en panne.

Vous devez toujours appeler par au initialiseur de super avant la messagerie auto. Et vous devez toujours le faire avec le motif ci-dessus.

+1

J'ai changé le code pour éviter d'autres discussions sur le code. La publication avant l'initialisation est valide: http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/ObjectiveC/Articles/ocAllocInit.html#//apple%5Fref/doc/uid/TP30001163-CH22-SW13 –

1

Je pensais que vous devez initialiser votre superclasse avant d'appeler la version, mais selon this example dans les documents d'Apple ce n'est pas le cas.

Donc ce peut être un bug, mais certainement pas important.

+1

Je pense que vous avez trouvé un bug de documentation. – Chuck

1

Mon analyse précédente n'était pas vraiment correcte.

Cependant, je tiens à souligner que ce problème peut se produire avec des classes différentes. Cela dépend en fait de la classe que vous sous-classez. Subclassing NSObject a pas de problème, mais le sous-classement NSOperation, NSOperationQueue et NSThread est un problème, par exemple.

Et cela se produit parce que tout comme vous pourriez faire, les classes que vous sous-classe peut affecter des choses dans leur méthode -init. Et c'est aussi là que vous définissez à nil les variables que vous ne l'avez pas encore attribués (et peut-être faire plus tard dans votre code). Ainsi, en appelant le -release sur vous-même sans le précédent -init, vous pourriez provoquer la libération par l'une de vos classes parentes de l'objet qu'elle n'avait pas alloué.Et ils ne peuvent pas vérifier si leur objet est nil, car il n'a même pas eu l'occasion d'initier chaque objet/valeur dont il a besoin.

Cela pourrait aussi être la raison pour laquelle libérer NSOperation sans init a fonctionné sur 10.5 et ne fonctionne pas sur 10.6. L'implémentation 10.6 a été réécrite pour utiliser des blocs et Grand Central Dispatch, et donc, leurs méthodes init et dealloc ont pu changer considérablement, créant un comportement différent sur ce morceau de code.

+0

L'envoi de '-release' à un objet nul ne devrait rien faire. De plus, libérer des pointeurs 'NULL' est supposé ne rien faire. http://www.opengroup.org/onlinepubs/009695399/functions/free.html Par conséquent, je pense que c'est un bug. –

+0

@gs: Je sais free() et libère le travail sur les objets NULL. Cependant, quand voulez-vous exactement définir le pointeur sur NULL/nil quand vous ne les laissez même pas initier leur objet? (ce qui est mon point dans cette réponse). Allouer le pointeur sur la pile ne le définit pas à NULL/nil. C'est pourquoi je pense que ce n'est pas un bug. –

+1

Les Ivars sont automatiquement définis sur zéro dans alloc. – Chuck