5
votes

Pourquoi les pointeurs non initialisés provoquent des violations d'accès mem proche de 0?

On dit que souvent (mais pas toujours) lorsque vous obtenez un AV dans un emplacement mémoire proche de zéro (comme 89 $), vous avez un pointeur non initialisé.
Mais j'ai vu cela aussi dans les livres Delphi ... Hm ... ou ils ont tous été écrits par le (s) même (s) auteur (s) ???


Mise à jour:
Citation du "Guide des développeurs C ++ builder 6" par Bob Swart et tous, page 71:

Lorsque l'adresse mémoire ZZZZZZZZZ est proche de zéro, la cause est souvent un pointeur non initialisé auquel on a accédé.

Pourquoi en est-il ainsi? Pourquoi les pointeurs non initialisés contiennent des nombres faibles? Pourquoi pas de gros nombres comme $ FFFFFFF ou des nombres aléatoires simples? Est-ce un mythe urbain?


8 commentaires

"on dit" est un peu générique. Pouvez-vous créer un lien vers certaines ressources indiquant cela?


Non initialisé signifie que la variable contient une valeur indéterminée . Période. Indéterminé est indéterminé, cela peut être n'importe quoi.


La zone des variables globales est initialisée par des zéros, donc la valeur initiale des pointeurs globaux est zéro. Les variables locales peuvent avoir n'importe quelle valeur.


@GPhilo - Guide des développeurs C ++ Builder 6 par Bob Swart et All, page 71


@GPhilo - Et bien d'autres endroits. J'ai entendu cela 30 fois maintenant. C'est vraiment étonnant que vous ne l'ayez pas encore entendu. MÊME si cela s'avère être une légende urbaine.


Jamais entendu cela auparavant (bien que je vois le raisonnement derrière cela), c'est pourquoi j'ai demandé des références;)


Notez que la plupart des compilateurs en mode débogage préréglent tranquillement des valeurs non définies sur des valeurs hexadécimales CDCDCDCD ou quelque chose de similaire. Votre cas est l'utilisation d'un pointeur qui ne pointe vers rien, qui est généralement un nullptr égal à zéro.


La règle est à sens unique: les adresses faibles sont le signe de pointeurs non initialisés. Cela n'implique pas l'inverse, que tous les pointeurs non initialisés sont à des adresses basses. C'est simplement que les pointeurs valides sur le tas ou la pile ont généralement des valeurs plus élevées. Cela n'implique pas non plus que les adresses élevées sont le signe de pointeurs initialisés appropriés.


3 Réponses :


7
votes

Pourquoi les pointeurs non initialisés contiennent des nombres faibles?

Ils ne le font pas. Ils peuvent contenir n'importe quelle valeur.

Pourquoi pas de gros nombres comme $ FFFFFFF?

Ils peuvent parfaitement contenir des valeurs telles que $ FFFFFFF.

ou des nombres aléatoires simples?

Les variables non initialisées ont tendance à ne pas être vraiment aléatoires. Ils contiennent généralement tout ce qui a été écrit dans cet emplacement de mémoire la dernière fois qu'il a été utilisé. Par exemple, il est très courant que des variables locales non initialisées contiennent la même valeur à chaque fois qu'une fonction est appelée car l'historique d'utilisation de la pile est répétable.

Il convient également de souligner que le terme aléatoire est un mot souvent mal utilisé. Les gens disent souvent aléatoire quand ils veulent dire distribués au hasard avec une distribution uniforme. Je suppose que c'est ce que vous vouliez dire lorsque vous avez utilisé le terme aléatoire.


5 commentaires

Non initialisé est UB, pas aléatoire. Particulièrement significatif dans le cadre des optimisations.


@PasserBy j'ai explicitement dit pas aléatoire


J'ai apparemment utilisé les mauvais mots. Je voulais dire qu'ils ne détiennent aucune valeur. Ils ne sont pas définis.


@PasserBy Ce n'est pas ce que signifie indéfini. Ils détiennent définitivement une valeur, il n'y a tout simplement aucune garantie sur cette valeur.


@PasserBy: un pointeur ou un entier non initialisé contiendra très certainement une valeur. Mais pas forcément valable ou utile.



13
votes

Ceci confond les "pointeurs non initialisés" avec des références nulles ou des pointeurs nuls. L'accès aux champs d'un objet, ou aux index dans un pointeur, sera représenté comme un décalage par rapport au pointeur de base. Si cette référence est nulle, les décalages seront généralement des adresses proches de zéro (pour les décalages positifs) ou des adresses proches de la valeur maximale de la taille du pointeur natif (pour les décalages négatifs).

Les violations d'accès aux adresses avec ces valeurs caractéristiques petites (ou grandes) indiquent que vous avez une référence nulle ou un pointeur nul < / em> , en particulier, et pas simplement un pointeur non initialisé . Une référence non initialisée peut avoir une valeur nulle, mais peut également avoir une autre valeur selon la façon dont elle est allouée.


11 commentaires

Vous pouvez éventuellement ajouter que certains compilateurs initialiseront la mémoire "non initialisée", pour faciliter exactement ce type d'analyse post-mortem


@Caleth Une ventilation complète des détails d'implémentation d'allocation de mémoire pour tous les modes et plates-formes de tous les compilateurs possibles pour delphi et C ++ ne rentrerait pas dans cette réponse, je pense.


Mes excuses les plus sincères - j'ai mal lu cette réponse et l'ai rejetée. Maintenant converti en vote positif. Pour moi, cela semble être une explication très plausible.


La citation du livre référencé dans les commentaires mentionne spécifiquement un pointeur non initialisé plutôt qu'un décalage par rapport à un pointeur nul.


@DavidHeffernan Je ne pense pas que cela change la réponse. La citation du livre souffre de la même idée fausse, je pense. La seule mise en garde à laquelle je puisse penser a été brièvement mentionnée dans un commentaire (maintenant supprimé), et qui entoure la distribution statistique des valeurs dans la mémoire périmée. Je pense que la discussion est une extension valide de cette réponse, mais au premier ordre, je pense que c'est principalement une confusion sur la différence entre une valeur nulle et une valeur non initialisée.


Je pense que le fait est que ce n'est pas tant le demandeur qui confond les choses, mais plus probablement l'auteur de la citation. Bien sûr, le fait que le demandeur n'ait pas fait référence à la citation n'est pas très utile.


@DavidHeffernan Je ne sais toujours pas où vous voulez en venir. Souhaitez-vous que je remplace le mot «Vous» au début de ma réponse par autre chose? Que dis-tu de ça?


Oui, je pense que c'est mieux. Je pense que le demandeur a été induit en erreur par une mauvaise écriture dans le texte référencé


@DavidHeffernan Les efforts que je fais parfois pour apaiser votre TOC, je jure, lol. De rien ;)


@J ... - Ok, donc "Si cette référence est nulle alors ..." a un rôle très important dans cette équation.


ajout de la citation exacte du livre.



5
votes

Votre déclaration sur AV proche de zéro est vraie pour le déréférencement d'un pointeur nul. Il est égal à zéro ou proche de zéro car vous déréférencer le pointeur nul:

struct Data
{
  int field1;
  int field2;
};

Data* p{};
const auto v = p->field2; // AV at memory location = 4

ou accéder à un élément du tableau:

char* p{};
const auto v = p[100]; // <--AV at memory location = 100

ou une structure champ:

int* p{};
const auto v = *p; // <-- AV at memory location = 0


0 commentaires