Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to programmatically get the address of the heap on Linux

I can get the address of the end of the heap with sbrk(0), but is there any way to programmatically get the address of the start of the heap, other than by parsing the contents of /proc/self/maps?

like image 384
jchl Avatar asked Aug 25 '10 11:08

jchl


People also ask

How do I know if my address is stack or heap?

Try first the cat /proc/$$/maps command in a terminal (showing you a description of your shell's virtual address space). As many commented, because of ASLR, you don't have any idea of the relative position of stack and heap, even if there is one single stack.

How does malloc know where the heap is?

When the OS loads a process into memory it initializes the stack pointer to the virtual address it has decided where the stack should go in the process's virtual address space and program code uses this register to know where stack variables are.

What is heap memory in Linux?

6.1. Heap Memory. “Heap” memory, also known as “dynamic” memory, is an alternative to local stack memory. Local memory is quite automatic. Local variables are allocated automatically when a function is called, and they are deallocated automatically when the function exits.

How do you tell if an address is on the stack?

On the other hand, the stack starts at the "top" of memory and grows downwards towards the current end of the heap. So it would be very easy to tell if something is on the stack or not. You'd simply test whether the address is greater than the address of the last variable added to the stack.


1 Answers

I think parsing /proc/self/maps is the only reliable way on the Linux to find the heap segment. And do not forget that some allocators (including one in my SLES) do use for large blocks mmap() thus the memory isn't part of the heap anymore and can be at any random location.

Otherwise, normally ld adds a symbol which marks the end of all segments in elf and the symbol is called _end. E.g.:

extern void *_end;
printf( "%p\n", &_end );

It matches the end of the .bss, traditionally the last segment of elf. After the address, with some alignment, normally follows the heap. Stack(s) and mmap()s (including the shared libraries) are at the higher addresses of the address space.

I'm not sure how portable it is, but apparently it works same way on the Solaris 10. On HP-UX 11 the map looks different and heap appears to be merged with data segment, but allocations do happen after the _end. On AIX, procmap doesn't show heap/data segment at all, but allocations too get the addresses past the _end symbol. So it seems to be at the moment quite portable.

Though, all considered, I'm not sure how useful that is.

P.S. The test program:

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

char *ppp1 = "hello world";
char ppp0[] = "hello world";
extern void *_end; /* any type would do, only its address is important */

int main()
{
    void *p = calloc(10000,1);
    printf( "end:%p heap:%p rodata:%p data:%p\n", &_end, p, ppp1, ppp0 );
    sleep(10000); /* sleep to give chance to look at the process memory map */
    return 0;
}
like image 162
Dummy00001 Avatar answered Nov 13 '22 00:11

Dummy00001