2015-11-19 1 views
7

У меня есть требование определить, находится ли данный адрес в куче или в стеке. Есть ли надежный способ сделать это в Linux?Как определить, находится ли данный адрес в куче или в стеке

Я подумал о следующем подходе, предполагая, что стек будет расти вниз, а куча вырастет до стека. Насколько надежным является это решение? Мы не используем gcc split-stack.

is_stack (void *addr) { 
    int a; 
    if(&a < addr) return stack; 
    else return heap 
} 

[править - я видел подобный вопрос, но это более теоретический характер]

+1

Почему именно вы спрашиваете? –

+1

[См. ASLR] (https://en.wikipedia.org/wiki/Address_space_layout_randomization). – user3386109

+0

@BasileStarynkevitch :-) Потому что я вижу, что он разбит на некоторых платформах (все Linux с незначительными изменениями). – joe

ответ

4

Во-первых, вы можете иметь несколько стеков в вашем process, в частности, если она является многопоточной (и некоторые библиотеки могут начинать темы, если вы не просите их). И ваш процесс «virtual address space может иметь больше сегментов, чем просто куча & стек.

Вы можете разобрать псевдо-файл /proc/self/maps. См. proc(5). Обратите внимание, что поскольку это псевдофайл, который генерируется ядром, нет физического ввода-вывода, и чтение & синтаксического анализа того, что файл /proc/self/maps должен быть очень быстрым.

адрес карты вашего процесса можно изменить, вызвав mmap(2), munmap, execve, mprotect и некоторые другие системные вызовы (см syscalls(2) , чтобы получить список из них); используйте strace(1), чтобы понять, какие системные вызовы выполнены. Любой вызов malloc (внутренне вызываемый многими функциями, включая fopen ...) или free (и до dlopen и т. Д. И т. Д.) может (но не всегда) использовать их, поэтому кэширование результата разбора /proc/self/maps не является надежным вариантом.

Попробуйте сначала команду cat /proc/$$/maps в терминале (показывая вам описание виртуального адресного пространства вашей оболочки).

Как многие прокомментировали, из-за ASLR вы не имеете представления об относительном положении стека и кучи, даже если есть один стек. Возможным трюком может быть запуск вашего main с чем-то, помещающим адрес некоторой локальной переменной (или даже mainargc первый аргумент, или argv[0]) в некотором глобальном void*stackbottom;, а затем сравнить адрес, как вы, то есть тест if(&a < addr && &a > stackbottom). Обратите внимание, что Boehm's garbage collector выполняет аналогичные действия.

Но самый надежный способ для чтения и анализа /proc/self/maps, и это должно быть довольно быстро и, безусловно, является программным решением (ядро динамически дает информацию о своем состоянии и состоянии процесса через /proc/ и не физического IO участвует в чтении).

И все же, быть в стеке или находиться в куче слабовыраженной свойство указателей (другими словами, стек или куча является гораздо более сложным понятием, чем то, что вы себе представить). Вы должны быть более точными о том, что вы действительно хотите сделать.

В дополнение, переопределите свои собственные malloc, free и т. Д. И у вас есть malloc управляйте некоторой картой памяти.

+0

благодарит за ответ! Предположим, что это управляемая однопоточная среда. Нет, proc не является решением. Я хочу сделать это программно. Не забудьте прокомментировать решение, которое я разместил? – joe

+3

Наоборот, чтение '/ proc/self/maps' является самым надежным программным решением. –

+0

Спасибо за трюк. Эта логика будет в очень высокой производительности. Исходя из этого, мне нужно освободить определенную память. Разбор proc/map каждый раз не похож на решение. Разбор проб/карт один раз и сохранение данных кажется прекрасным. – joe

2

стандарт C не имеет понятие кучи или стек, так что язык сам по себе не может сказать.

Но вы говорите об Linux так, чтобы все не было потеряно - вы можете добиться этого с честной работой.

Если вы определяете кучи как память, выделенную malloc, вы могли подумать о создании собственной системы распределения памяти. Многие компиляторы C позволяют вам различать malloc во время соединения для всех библиотек, связанных с вашей программой, поэтому такой подход вполне возможен. (См. LD_PRELOAD). Конечно, основные кишки вашей замены malloc просто вызовут стандартную функцию. Но другая часть будет поддерживать таблицу выделенной памяти. Вы можете использовать эту информацию в тестовой функции, которую вам нужно будет написать.

Вам нужно будет сделать то же самое для calloc, free, & c.

+0

Спасибо за предложение. Я ищу что-то столь же простое, как решение, которое я разместил. Можете ли вы сказать мне, почему это не сработает? – joe

+2

Почему * бы * это? Он основан на вашем предположении, которое вы не можете оправдать в контексте стандарта. Мне также не нравится '& a Bathsheba

+0

нет. Сначала рассмотрите его как псевдокод. И мы пытаемся сравнить адреса здесь. Давайте не будем беспокоиться о типе. Точка будет ли логика работать или нет. – joe

Смежные вопросы