20 votes

Déterminer si un pointeur pointe sur la pile, le tas ou le texte du programme ?

Existe-t-il un moyen de savoir si un pointeur pointe vers un endroit dans.. :

  • la pile
  • le tas
  • ou le programme (et si oui, quelle section, par exemple elf .text) ?

En outre, cela peut-il être fait de manière portative (Linux 64/32 bits, OSX et Windows 7+) ?

suivi :

Je n'essaie pas de savoir si quelque chose a été malloqué.

Je veux distinguer efficacement les pointeurs void* vers les fonctions du programme des pointeurs void* vers les données de la pile ou du tas.

Il s'agit d'un runtime de langage écrit en C, et non d'un programme C "normal".

Cette réponse a été la plus utile jusqu'à présent : Vérifier si quelque chose a été malloqué

35voto

Diomidis Spinellis Points 8417

Vous ne pouvez pas faire ce que vous voulez de manière portable, car la norme du langage C ne spécifie pas la pile, la zone de programme et le tas comme des zones distinctes. Leur emplacement peut dépendre de l'architecture du processeur, du système d'exploitation, du chargeur, de l'éditeur de liens et du compilateur. Essayer de deviner où pointe un pointeur revient à briser l'abstraction fournie par le langage C, et vous ne devriez donc probablement pas le faire.

Néanmoins, il existe des moyens d'écrire du code qui fera une estimation correcte pour un environnement spécifique. Pour cela, il faut examiner les adresses des objets existants et rechercher des modèles. Considérons le programme suivant.

#include <stdlib.h>
#include <stdio.h>

void
function()
{
    int stack2;

    printf("stack2:  %15p\n", &stack2);
}

int
main(int argc, char *argv[])
{
    int stack;
    void *heap = malloc(1);
    void *heap2 = malloc(1);

    printf("program: %15p\n", main);
    printf("heap:    %15p\n", heap);
    printf("heap2:   %15p\n", heap2);
    printf("stack:   %15p\n", &stack);
    function();
    return 0;
}

En examinant sa sortie, vous pouvez voir un modèle, tel que le suivant sur x64 Linux.

program:        0x400504
heap:          0x1675010
heap2:         0x1675030
stack:    0x7fff282c783c
stack2:   0x7fff6ae37afc

A partir de ce qui précède, vous pouvez déterminer que (probablement) le tas se développe à partir de 0x1675010, que tout ce qui se trouve en dessous est du code de programme (ou des données statiques, ce que vous n'avez pas mentionné), et que la pile se développe de manière imprévisible (probablement à cause de la randomisation de la pile) autour d'une très grande adresse, comme 0x7fff282c783c.

Comparez cela avec le résultat sous Linux Intel 32 bits :

program:       0x804842f
heap:          0x804b008
heap2:         0x804b018
stack:        0xbf84ad38
stack2:       0xbf84ad14

Microsoft Windows et le compilateur Microsoft C 32 bits :

program:        01271020
heap:           002E3B00
heap2:          002E3B10
stack:          0024F978
stack2:         0024F964

gcc sous Windows Cygwin :

program:        0040130B
heap:           00A41728
heap2:          00A417A8
stack:          0028FF44
stack2:         0028FF14

gcc sous FreeBSD Intel 32 bits :

program:       0x8048524
heap:          0x804b030
heap2:         0x804b040
stack:        0xbfbffb3c
stack2:       0xbfbffb1c

gcc sous FreeBSD Intel 64 bits :

program:        0x400770
heap:        0x801006058
heap2:       0x801006060
stack:    0x7fffffffdaec
stack2:   0x7fffffffdabc

gcc sous SPARC-64 FreeBSD :

program:        0x100860
heap:         0x40c04098
heap2:        0x40c040a0
stack:     0x7fdffffe9ac
stack2:    0x7fdffffe8dc

PowerPC fonctionnant sous MacOS X :

program:          0x1ed4
heap:           0x100120
heap2:          0x100130
stack:        0xbffffba0
stack2:       0xbffffb38

PowerPC fonctionnant sous Linux :

program:      0x10000514
heap:         0x100c6008
heap2:        0x100c6018
stack:        0xbff45db0
stack2:       0xbff45d88

StrongARM exécutant NetBSD :

program:          0x1c5c
heap:             0x5030
heap2:            0x5040
stack:        0xefbfdcd0
stack2:       0xefbfdcb4

et ARMv6 sous Linux :

program:          0x842c
heap:           0xb63008
heap2:          0xb63018
stack:        0xbe83eac4
stack2:       0xbe83eaac

Comme vous pouvez le constater, les possibilités sont infinies.

0voto

Erich Horn Points 13

Vous pouvez déterminer l'emplacement général de la pile et du tas, mais la taille de ces derniers est une autre histoire...

void *heap_locations;
void *stack_location;

void determine_locations (int any_int) {
   free(heap_location = malloc(248));
   stack_location = &any_int;
}

int main(int argc, char *argv[]) {
  determine_locations(argc);
      .
      .
      .
  return 0;
}

C'est un peu grossier et vous ne connaîtrez pas la direction de l'expansion ou la taille de l'un ou l'autre avec certitude, à moins que vous n'ayez affaire à des plateformes spécifiques.

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