21

Is there a way to find out whether a pointer is pointing at a location in:

  • the stack
  • the heap
  • or the program (and if so, which section e.g. elf .text)?

Also, can this be done portably (Linux 64/32 bit, OSX and Windows 7+)?

follow up:

I'm not trying to find out if something has been malloc'd.

I want to efficiently distinguish void* pointers to functions in the program from void* pointers to data on the stack or heap.

This is for a language runtime written in C, not a "normal" C program.

This answer has been the most useful so far: Checking if something was malloced

2
  • 2
    See the answers to this question. Commented May 3, 2013 at 14:02
  • On Windows, you can use WinDbg's !address extension to determine this for you. I don't know about *nix-based operating systems. Commented May 3, 2013 at 14:24

2 Answers 2

36

You cannot do what you want in a portable way, because the C language standard does not specify the stack, program area, and heap as distinct areas. Their location can depend on the processor architecture, the operating system, the loader, the linker, and the compiler. Trying to guess where a pointer is pointing is breaking the abstraction provided by C, so you probably you shouldn't be doing that.

Nevertheless, there are ways to write code that will make a correct guess for a specific environment. You do that by examining the addresses of existing objects, and looking for patterns. Consider the following program.

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

By examining its output you can see a pattern, such as the following on x64 Linux.

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

From the above you can determine that (probably) the heap grows up from 0x1675010, anything below it is program code (or static data, which you didn't mention), and that the stack grows in an unpredictable manner (probably due to stack randomization) around a very large address, like 0x7fff282c783c.

Compare this with the output under 32-bit Intel Linux:

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

Microsoft Windows and the 32-bit Microsoft C compiler:

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

gcc under Windows Cygwin:

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

gcc under Intel 32-bit FreeBSD:

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

gcc under Intel 64-bit FreeBSD:

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

gcc under SPARC-64 FreeBSD:

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

PowerPC running MacOS X:

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

PowerPC running Linux:

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

StrongARM running NetBSD:

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

and ARMv6 running Linux:

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

As you can see the possibilities are endless.

Sign up to request clarification or add additional context in comments.

2 Comments

Under Linux, /proc/self/maps gives me all the info I need.
Did you somehow forget the line of code for creating heap2?
0

You can determine the location generally speaking of the stack and heap, though how large it is will be another story...

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

A bit rude and you won't know the expansion direction or size of either for absolute sure unless you are dealing with specified platforms.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.