42 votes

0xDEADBEEF équivalent pour le développement 64 bits?

Pour le développement C++ pour des systèmes 32 bits (que ce soit Linux, Mac OS ou Windows, PowerPC ou x86) j'ai initialisé des pointeurs qui seraient sinon indéfinis (par exemple, ils ne peuvent pas immédiatement avoir une valeur propre) de cette manière :

int *pInt = reinterpret_cast(0xDEADBEEF);

(Pour éviter de taper et de rester DRY, le côté droit serait normalement dans une constante, par exemple BAD_PTR.)

Si pInt est déréférencé avant d'avoir une valeur propre, alors il crashera immédiatement sur la plupart des systèmes (au lieu de planter bien plus tard lorsque certaines mémoires sont écrasées ou que l'on entre dans une boucle infinie).

Évidemment, le comportement dépend du matériel sous-jacent (récupérer un entier de 4 octets à partir de l'adresse impaire 0xDEADBEEF d'un processus utilisateur peut être parfaitement valide), mais le crash a été à 100% fiable pour tous les systèmes pour lesquels j'ai développé jusqu'à présent (Mac OS 68xxx, Mac OS PowerPC, Linux Redhat Pentium, Windows GUI Pentium, Windows console Pentium). Par exemple, sur PowerPC, il est illégal (défaut d'accès) de récupérer un entier de 4 octets à partir d'une adresse impaire.

Quelle est une bonne valeur pour cela sur les systèmes 64 bits ?

5 votes

J'ai vu des systèmes où les premiers 1K de mémoire sont définis comme non valides. Donc, si un pointeur NULL est déréférencé, le processus mourra rapidement. 0xDEADBEEF pourrait être une position valide.

2 votes

@Robert : J'ai vu des systèmes où le vecteur d'interruption commence à 0, donc déréférencer un pointeur de fonction NULL semble simplement redémarrer le système (mais ne réinitialise pas les piles, etc.). N'importe quelle adresse pourrait être un emplacement valide pour quelque chose.

9 votes

@bk1e: IVT ne doit JAMAIS être accessible depuis le mode utilisateur. Mais vous avez raison en disant qu'il n'y a aucune raison pour laquelle l'adresse 0 ne peut pas être mappée. Sous Linux, il est facile de mapper vers l'adresse 0 en modifiant une option dans le kernel. En tout cas, la leçon apprise ici est de ne pas utiliser des schémas stupides pour marquer les pointeurs comme invalides, utilisez null ou un drapeau distinct dans la structure. Supposer que ça va juste planter est complètement irresponsable et ignorant, si vous avez de la chance, vous aurez seulement une segfault, il est probable que cela pourrait conduire à une exécution de code à distance, et cela l'a déjà fait de nombreuses, nombreuses fois dans le passé.

70voto

chaos Points 69029

0xBADC0FFEE0DDF00D

5 votes

Cette particularité a l'avantage que vous avez besoin de yottaoctets de mémoire pour réellement faire de cette valeur une valeur saine car le noyau de la pile descend alors que la pile de l'utilisateur monte.

8 votes

@Joshua : 1. Je peux mapper mes pages où je veux. 2. C'est une hypothèse très dangereuse à faire (peut-être que c'est vrai avec votre système d'exploitation actuel sur une configuration x86, mais cela dépend de l'implémentation), que se passerait-il si la pile commençait à 0xBADCOFFEE0DFOOD-0x1000 ? La pile commence déjà à des endroits aléatoires, cela est fait pour essayer de rendre l'exploitation plus difficile et pour des raisons techniques en dehors de cela.

0 votes

Comment avez-vous arrivé à ce numéro?

54voto

Thomas Owens Points 45042

Selon Wikipedia, BADC0FFEE0DDF00D est utilisé sur les systèmes IBM RS/6000 64 bits pour indiquer des registres CPU non initialisés.

26voto

Zack Points 44583

La plupart des systèmes actuels 64 bits vous permettent d'utiliser uniquement les 248 – 252 bits les plus faibles de l'espace d'adressage; les bits plus élevés de l'adresse doivent être tous à zéro. Certains processeurs (par exemple amd64) vous permettent également d'utiliser les 248 – 252 bits les plus élevés. Les adresses en dehors de ces plages ne peuvent jamais être mappées vers une mémoire accessible ; le matériel ne le permet tout simplement pas.

Je vous recommande donc d'utiliser une valeur proche de 263, qui n'est nulle part près des espaces potentiellement utilisables. Si les quatre premiers chiffres hexadécimaux sont 7ff8, la valeur sera un NaN en double précision à virgule flottante, ce qui est pratique. Alors ma phrase hexadécimale mignonne suggérée est 0x7FF8BADFBADFBADF.

En passant, vous ne souhaitez vraiment pas utiliser une valeur proche de 0, car cela rend difficile de distinguer un déréférencement de décalage de NULL — un accès à un membre de structure, par exemple — d'un déréférencement du motif poison.

1 votes

La plupart des systèmes 64 bits actuels ne vous permettent d'utiliser que les 48 à 52 bits les plus bas de l'espace d'adressage et le matériel ne le permet tout simplement pas.

3 votes

Le manuel d'architecture de chaque CPU d'intérêt vous dira combien de bits de l'espace d'adressage sont utilisables. Par exemple, le Manuel du programmeur AMD64 Architecture, Volume 2 (Programmation système) indique dans la section 1.1.3 que tous les bits de l'espace d'adressage ne sont pas forcément utilisables et que les bits élevés inutilisables doivent être tous à zéro ou tous à un, puis dans la section 5.3.3 montre que les implémentations actuelles n'autorisent l'utilisation que des 48 bits les moins significatifs.

1 votes

Je ne suis pas au courant d'aucune vue d'ensemble répertoriant les processeurs avec adressage sur 64 bits et leurs plages d'adresses utilisables, mais la seule exception à ma déclaration d'origine que je trouve est PowerPC en mode de table de pages hachées. Avec des tables de pages structurées en arbre, chaque six à huit bits supplémentaires d'espace d'adresse virtuelle ajoutent un niveau d'arbre et rendent les erreurs TLB plus lentes, donc les concepteurs d'architecture sont réticents à rendre plus d'espace utilisable que ce dont les gens ont réellement besoin en ce moment, qui est de 48 à 52 bits (sauf pour les systèmes d'exploitation à espace d'adresse unique exotiques).

25voto

Noah Watkins Points 2179

En général, peu importe exactement quel motif vous écrivez, ce qui importe est que vous puissiez identifier le motif afin de déterminer où les problèmes se produisent. Il se trouve juste que dans le noyau Linux, ils sont souvent choisis de telle sorte qu'ils peuvent être piégés si les adresses sont déréférencées.

Jetez un œil dans le noyau Linux à include/linux/poison.h. Ce fichier contient différentes valeurs empoisonnées pour de nombreux sous-systèmes du noyau. Il n'y a pas de valeur empoisonnée appropriée.

De plus, vous pouvez consulter les fichiers d'inclusion par architecture dans l'arborescence source du noyau Linux pour des informations sur ce qui est utilisé sur des architectures spécifiques.

14voto

Michael Koval Points 3597

Je suppose que vous avez déjà exclu NULL (c'est-à-dire 0 sans le transtypage). C'est certainement le choix le plus sûr, car, en théorie, un pointeur valide pourrait pointer vers l'adresse mémoire 0xDEADBEEF (ou toute autre adresse mémoire non-NULL).

0 votes

Je pense qu'un des points de l'utilisation de 0xDEADBEEF ou d'une autre valeur mal connue est que c'est assez évident lors du débogage du fichier core résultant (ou équivalent) que vous traitez avec un pointeur non initialisé, plutôt que des données erronées/invalides/correctes. Je suggérerais que les chances que 0xDEADBEEF pointe réellement vers une adresse mémoire valide sont suffisamment faibles pour être largement dépassées par les avantages.

5 votes

Pour les pointeurs, toujours utiliser NULL/0. Les valeurs hexadécimales 0xDEADBEEF et autres sont utilisées pour remplir les régions de mémoire récemment allouées mais non initialisées, que les fonctions du gestionnaire de tas (cela peut également être vrai pour la pile) ont libérées et ne doivent plus être accédées.

1 votes

Avez-vous déjà vu un mappage de mémoire à NULL?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X