Подтвердить что ты не робот

Узнайте, указывает ли указатель на стек, кучу или текст программы?

Есть ли способ узнать, указывает ли указатель на местоположение в:

  • стек
  • куча
  • или программы (и если да, то какой раздел, например, эльф .text)?

Кроме того, это можно сделать портативно (Linux 64/32 бит, OSX и Windows 7 +)?

отслеживание:

Я не пытаюсь выяснить, что-то было malloc'd.

Я хочу эффективно отличать указатели void * от функций в программе от указателей void * до данных в стеке или куче.

Это для языковой среды исполнения, написанной на C, а не для "нормальной" программы C.

Этот ответ был наиболее полезным до сих пор: Проверка того, что что-то было выделено

4b9b3361

Ответ 1

Вы не можете делать то, что хотите, переносимым образом, поскольку стандарт языка C не указывает стек, область программы и кучу в качестве отдельных областей. Их местоположение может зависеть от архитектуры процессора, операционной системы, загрузчика, компоновщика и компилятора. Попытка угадать, куда указывает указатель, - это нарушение абстракции, предоставляемой C, поэтому вы, вероятно, не должны этого делать.

Тем не менее, есть способы написать код, который сделает правильное предположение для конкретной среды. Вы делаете это, исследуя адреса существующих объектов и ищите шаблоны. Рассмотрим следующую программу.

#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;
}

Изучая его вывод, вы можете увидеть шаблон, например, следующий в x64 Linux.

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

Из вышесказанного вы можете определить, что (возможно) куча растет с 0x1675010, все, что ниже, это программный код (или статические данные, о которых вы не упоминали), и что стек растет непредсказуемым образом (возможно из-за рандомизации стека) вокруг очень большого адреса, например 0x7fff282c783c.

Сравните это с выходом под 32-разрядным Intel Linux:

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

Microsoft Windows и 32-разрядный компилятор Microsoft C:

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

gcc под Windows Cygwin:

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

gcc в Intel 32-bit FreeBSD:

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

gcc в Intel 64-bit FreeBSD:

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

gcc под SPARC-64 FreeBSD:

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

PowerPC работает под MacOS X:

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

PowerPC под управлением Linux:

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

StrongARM работает с NetBSD:

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

и ARMv6 под управлением Linux:

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

Как вы видите, возможности бесконечны.

Ответ 2

Вы можете определить местоположение, обычно говорящее о стеке и куче, хотя насколько это будет большим будет другая история...

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;
}

Немного грубо, и вы не будете знать направление или размер расширения для абсолютной уверенности, если вы не имеете дело с определенными платформами.