memory location patterns on stack and heap - c

I'm just curious if there is any correlation between the length of the address of a variable (pointer) on stack and heap. On many occasions I have seen that those regarding stack variables are usually longer when compared to heap. For example consider the following simple test:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int i = 0;
int *j = malloc(sizeof(int)); *j = 0;
printf("&i = %p\n j = %p\n", &i, j);
free(j);
return 0;
}
output:
&i = 0x7fffe9c7fa5c
j = 0x100e010
These results are obtained in linux using gcc; could this be OS/compiler dependent?

The results depend on positions of the heap(s) and stack(s) in the address space of the program. These are determined by linker and processor architecture.
Due to ASLR, the exact numbers should be random on modern systems.
Nevertheless, heaps will usually grow upwards, and stacks downwards. Additionally, for performance and memory management reasons, both heaps and stacks will always start on page boundaries.

I believe it's because of the physical parts of the memory which we decide that they're called stack and heap. Since they start at opposite ends and grow towards the middle, it makes sense that one is lower and the other higher. It would be interesting to see what happens if you allocate 2 consecutive vars on the stack and 2 consecutive ones on the heap. This would help see which way the stack and heap grow. Actually I think for this to work you need to make a new stack frame (a new method) and allocate the second vars there, otherwise you remain in the same stack frame.

Related

Is the stack pre-allocated in a process?

Well, my question is as follows, I saw somewhere that a linux process allocates 8 MiB on the stack to be used, if I have a C program for example, that I only allocate two variables on the stack, it is right to say that I allocated or is it better to say that I just reused that space? Since a process allocates 8 MiB on the stack it does not depend on the size that I am going to use in my program, as long as it does not exceed my stack, that is, whichever term is appropriate, I will allocate a data on the stack or I will reuse a data that has already been allocated by a linux process?
#include <stdio.h>
void f() {
int x = 5;
printf("Value = %d End = %p\n", x, &x);
}
void g() {
int y = 10;
printf("Value = %d End = %p\n", y, &y);
}
int main(){
f();
g();
return 0;
}
See that the addresses will be the same, because I reused the size that had already been allocated, the same wouldn't happen with malloc, summarizing the term Allocated right data in the Stack isn't very correct?
Is the stack pre-allocated in a process?
On a stack-based architecture, a process will have stack space available to it from the beginning of its execution. That could be described as "pre-allocated". However, do note that in some contexts, it may be possible for a process's stack to be extended during the lifetime of the process. Perhaps that changes how you would view it?
In any case, that has little to do with whether the process of assigning storage space for automatic variables should be described as "allocation". Although it has technical implications, it is of little account linguistically that such space may be carved out of the stack, as opposed to out of some other area of memory controlled by the process. The lifetimes of such objects do obey different rules than the lifetimes of mallocated objects, but so what?
if I have a C program for example, that I only allocate two variables on the stack, it is right to say that I allocated or is it better to say that I just reused that space?
People are likely to understand you just fine either way. Although I'm sure there are some who would quibble over whether "allocate" is technically correct for automatic variables, it is nevertheless widely used for them. If you are conversing with people, as opposed to writing technical documentation to which the distinction is important, then I would not hesitate to use "allocate" to describe assigning storage space to automatic variables.

Storage class of referenced memory [duplicate]

Stumbled upon this interview question somewhere,
In C,
Given a variable x, how do you find out if the space for that variable is allocated on the stack or heap?
(Is there any way to find it out programatically and not having to go through the symbol table, etc? And does finding if the space is allocated in stack or heap has any practical implications?)
No, not in general.
Do you know of gcc -fsplit-stack ?
It is up to the implementation to decide whether to allocate a contiguous stack or a stack where blocks are interleaved with heap blocks in memory. Good luck figuring out whether a block was allocated for the heap or the stack when the latter is split.
If you are working on an architecture that stores the stack on a larger address than the heap, you could compare the variable address with the bottom of the stack. Using the pthread threading API, this comparison would look like this:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <inttypes.h>
int is_stack(void *ptr)
{
pthread_t self = pthread_self();
pthread_attr_t attr;
void *stack;
size_t stacksize;
pthread_getattr_np(self, &attr);
pthread_attr_getstack(&attr, &stack, &stacksize);
return ((uintptr_t) ptr >= (uintptr_t) stack
&& (uintptr_t) ptr < (uintptr_t) stack + stacksize);
}
The test:
int main()
{
int x;
int *p1 = malloc(sizeof(int));
int *p2 = &x;
printf("%d %d\n", is_stack(p1), is_stack(p2));
return 0;
}
...prints 0 1, as expected.
The above code will not detect storage from stacks in other threads. To do that, the code would need to track all created threads.
This is NOT guaranteed by any standard BUT
on most platforms the stack grows down from highest address available, and heap grows up from the bottom if the most significant byte of the address is in the top half of the available memory space for your platform, and you haven't allocated gigabytes of memory, it's a pretty good bet it's on the stack.
#include <iostream>
#include <stdlib.h>
int main()
{
int x = 0;
int* y = new int;
unsigned int a1 = (int) &x;
unsigned int a2 = (int) y;
std::cout<<std::hex<<a1<<" "<<a2<<std::endl;
}
gives the output ffbff474 21600 on the machine I'm typing this.
It might be a trick question. Variables have either automatic or static storage duration[*]. You can fairly safely say that automatics are allocated "on the stack", at least assuming they aren't optimized into registers. It's not a requirement of the standard that there be "a stack", but a conforming C implementation must maintain a call stack and associate automatic variables with the levels of the call stack. So whatever the details of what it actually does, you can pretty much call that "the stack".
Variables with static storage duration generally inhabit one or more data sections. From the POV of the OS, data sections might be allocated from the heap before the program starts, but from the POV of the program they have no relation to the "free store".
You can tell the storage duration of a variable by examining its definition in the source -- if it's in function scope then it's automatic unless marked static. If it's not in function scope then it has static duration regardless of whether or not it is marked static (since the static keyword means something different there).
There is no portable way to tell the storage duration of a variable from its address, but particular implementations might provide ways to do it, or tools that you can use with greater or lesser reliability to take a guess.
Objects can also have dynamic storage duration (which generally is what "allocated on the heap" is intended to mean), but such objects are not variables, so that would be the trick if there is one.
[*] Or thread-local in C11 and C++11.
I don't think it has solutions. The code may adjust var's address by stack(heap) address scope, but it's would not be an exact way. At most, the code can only run in some certain platforms.
No it's not possible to determine that by memory location, the compiler would have to support it with isstack() to be portable.
One possible way to track memory allocation SPECIFICALY ON THE HEAP in C++ is overloading the new operator to keep tracking that for you. Then you know that if the memory is not allocated on the heap, it must be allocated on the stack.
#include <iostream>
#include <string>
// Variable to track how many allocations has been done.
static uint32_t s_alloc_count = 0;
void* operator new(size_t size){
s_alloc_count++;
std::cout << "Allocating " << size << " bytes\n";
return malloc(size);
}
Tracking the variable s_alloc_count you should be capable of see how many allocations on the heap has been done and have the size of these allocations printed on the console. Using debug tools like breakpoints, running the code "step-by-step" and console logging is one way to track where are these allocations. This is not an automated way but is a way to do that.
OBS: This tip should be only used for tests, avoid this type of code in production code.

local variable memory and malloced memory location [closed]

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 9 years ago.
I was playing up with malloced memory and local variables to see how stack and Heap grows. From my understanding heap grows upwards and the stack grows downwards. All the memory allocated using malloc is allocated in the heap and local variables are allocated on the stack in a function.
In following program :
#include <stdio.h>
#include <stdlib.h>
#define SIZE 999999999
void tot(){
static int c =0;
int k;
c++;
int *pp = malloc(sizeof(int) * SIZE);
if(pp==NULL){
fprintf(stderr,"NO memory allocated after call : %d\n",c);
return;
}
printf("%p %d %p\n",&k,c,pp);
tot();
}
int main(int argc, char *argv[]){
int k;
int *pp = malloc(sizeof(int) * 99999);
if(pp ==NULL){
fprintf(stderr,"No memory allocated\n");
return;
}
printf("%p %p\n",&k,pp);
tot();
return 0;
}
I have created one local variable in the function tot() which will be 4 bytes and one pointer variable of type int* which will increase the total stack size for each call to slightly greater than 4 bytes. Also I have allocated some memory using malloc and assigned the allocated memory to local pointer variable. Since this malloced memory is allocated on the heap, the stack size should still be just over 4 bytes but according to my observation in the above program, the stack size is increased by a large amount. After some maths on that large amount I found out that the stack frame is including the malloced memory created in each function call.
Though removing the line
int *pp = (int*)malloc(sizeof(int) * SIZE);
which is responsible for allocating this large memory in each function call reduces the stack frame size back to ~4 bytes which is perfectly fine.
Stack frame is growing downwards in both situations though.
Why I am getting such output. Is my belief that dynamic memory is allocated on the heap is wrong. Why malloced memory is increasing the size of the stack frame ?
EDIT :
I also tried accessing the allocated memory in one stack frame in other stack frame by passing the pointer to memory allocated in one stack frame to the other function call (another stack frame) so that the memory allocated in one frame can be used in other call just to verify if the compiler is not internally converting the malloc to alloca (which could have been the reason for large stack frames) but that didn't make any difference. The results are still same.
Many Linux systems have ASLR so the result of malloc might not be reproducible from one execution to the next; you can disable ASLR thru /proc/sys/kernel/randomize_va_space.
Actually, recent malloc implementations are using more the mmap(2) syscall than the sbrk or brk one. So the heap is actually made of several non-contiguous virtual memory segments. Usually, later calls to free mark the freed region as reusable by malloc (but don't necessarily munumap(2) it).
You can have a look at the address space of some process of pid 1234 by looking into /proc/1234/maps. Read proc(5) man page (and try cat /proc/self/maps which shows the address space of the process running that cat).
And you tot function being tail recursive, most GCC compilers would optimize it as a loop.... (if you are compiling with gcc -O1 or more). However, stack frames are usually required to be aligned (e.g. to 16 bytes) and contain also the previous frame pointer, some space to spill registers, etc...
C is a low-level language, but it still defines things loosely enough that specific details can vary between platforms. For instance, the compiler is free to allocate varying amounts of stack space as it sees fit (typically "extra" space), so long as the results of the running program are not altered.
This may be done in the name of performance [1] or to support certain calling conventions. So even though an int may only need for bytes of space, the compiler may allocate 16 bytes on the stack to preserve a favorable memory alignment.
If the "large" increases in stack size are small compared to SIZE, then the difference is probably just due to padding of this sort. (Note that there is also more data on the stack than just the local variables - the return address of the calling function will usually be stored there, as well as the contents of any registers the compiler decided should be stored from the caller.)
If it actually looks like malloc is allocating to the stack (i.e. the stack is increasing in jumps of SIZE), that's surprising, but probably still "correct" on behalf of the compiler. By definition malloc allocates memory; there is no guarantee that this is allocated from the heap, although that is certainly the normal implementation. Since the results of malloc are never accessed outside of the stack frame in which it's invoked, the compiler could in principle optimize this to an alloca call; but, again, I'd be very surprised to see that.
[1] Example: http://software.intel.com/en-us/articles/data-alignment-when-migrating-to-64-bit-intel-architecture

Understanding memory allocation, test program crashing

I am just about finished reading K&R, and that is all the C that I know. All my compilation is done from Windows command line using MinGW, and I have no knowledge of advanced debugging methods (hence the "ghetto debug" comment in my 2nd program below).
I am trying to make a few small test programs to help me better understand how memory allocation works. These first couple programs do not use malloc or free, I just wanted to see how memory is allocated and de-allocated for standard arrays local to a function. The idea is that I watch my running processes RAM usage to see if it corresponds with what I understand. For this first program below, it does work as I expected. The alloc_one_meg() function allocates and initializes 250,000 4-byte integers, but that MB is de-allocated as soon as the function returns. So if I call that function 1000000 times in a row, I should never see my RAM usage go much above 1MB. And, it works.
#include <stdio.h>
#include <stdlib.h>
void alloc_one_meg() {
int megabyte[250000];
int i;
for (i=0; i<250000; i++) {
megabyte[i] = rand();
}
}
main()
{
int i;
for (i=0; i<1000000; i++) {
alloc_one_meg();
}
}
For this second program below, the idea was to not allow the function to exit, to have 1000 copies of the same function running at once, which I accomplished with recursion. My theory was that the program would consume 1GB of RAM before it de-allocated it all after the recursion finished. However, it doesn't get past the 2nd loop through the recursion (see my ghetto debug comment). The program crashes with a pretty non-informative (to me) message (a Windows pop-up saying ____.exe has encountered a problem). Usually I can always get to the bottom of things with my ghetto debug method... but it's not working here. I'm stumped. What is the problem with this code? Thanks!
#include <stdio.h>
#include <stdlib.h>
int j=0;
void alloc_one_meg() {
int megabyte[250000];
int i;
for (i=0; i<250000; i++) {
megabyte[i] = rand();
}
j++;
printf("Loop %d\n", j); // ghetto debug
if (j<1000) {
alloc_one_meg();
}
}
main()
{
alloc_one_meg();
}
Followup question posted here.
You're running into a stack overflow.
Local automatic storage variables (such as megabyte) are allocated on the stack, which has limited amount of space. malloc allocates on the heap, which allows much larger allocations.
You can read more here:
http://en.wikipedia.org/wiki/Stack_overflow
(I should note that the C language does not specify where memory is allocated - stack and heap are implementation details)
The size of the stack in a Windows program is usually around 1 MB, so on the second recursion, you're overflowing the stack. You shouldn't be allocating such large arrays on the stack, use malloc and free to allocate and deallocate the memory on the heap (there's no way to get around malloc for such sizes of arrays):
void alloc_one_meg() {
int *megabyte = malloc(sizeof(int) * 250000); // allocate space for 250000
// ints on the heap
int i;
for (i=0; i<250000; i++) {
megabyte[i] = rand();
}
j++;
printf("Loop %d\n", j); // ghetto debug
if (j<1000) {
alloc_one_meg();
}
free(megabyte); // DO NOT FORGET THIS
}
That said, you can actually change the stack size of a program and make it bigger (though I'd only do so as an educational exercise, not in production code). For Visual Studio you can use the /F compiler option, and on linux you can use setrlimit(3). I'm not sure what to use with MinGW though.
The memory you are allocating via the recursive functional calls is allocated from the stack. All of the stack memory must be contiguous. When your process starts a thread, Windows will reserve a range of virtual memory address space for that thread's stack. The amount of memory to be reserved is specified in your EXE file's "PE header." PE stands for "Portable Executable."
Using the dumpbin utility included with Visual Studio, with itself (dumpbin.exe) as the input file:
dumpbin /headers dumpbin.exe
... there is some output, and then:
100000 size of stack reserve
2000 size of stack commit
The "100000" is a hexadecimal number equal to 1,048,576, so this represents around 1MB.
In other words, the operating system will only reserve a 1MB address range for the stack. When that address range is used up, Windows may or may not be able to allocate further consecutive memory ranges to increase the stack. The result depends on whether further contiguous address range is available. It is very unlikely to be available, due to the other allocations Windows made when the thread began.
To allocate a maximum amount of virtual memory under Windows, use the VirtualAlloc family of functions.
StackOverflow. Is this a trick question?

how to find stack is increasing or decreasing in C?

stack is increasing or decreasing using C program ?
Right, in C usually variables in function scope are realized by means of a stack. But this model is not imposed by the C standard, a compiler could realize this any way it pleases. The word "stack" isn't even mentioned in the standard, and even less if it is in- or decreasing. You should never try to work with assumptions about that.
False dichotomy. There are plenty of options other than increasing or decreasing, one of which is that each function call performs the equivalent of malloc to obtain memory for the callee's automatic storage, calls the callee, and performs the equivalent of free after it returns. A more sophisticated version of this would allocate large runs of "stack" at a time and only allocate more when it's about to be exhausted.
I would call both of those very bad designs on modern machines with virtual memory, but they might make sense when implementing a multiprocess operating system on MMU-less microprocessors where reserving a range of memory for the stack in each process would waste a lot of address space.
How about:
int stack_direction(void *pointer_to_local)
{
int other_local;
return (&other_local > pointer_to_local) ? 1 : -1;
}
...
int local;
printf("direction: %i", stack_direction(&local);
So you're comparing the address of a variable at one location on the call stack with one at an outer location.
If you only like to know if the stack has been changed you can keep the last inserted object to the stack, peek at the top of it and compare the two.
EDIT
Read the comments. It doesn't seem to be possible to determine the stack direction using my method.
END EDIT
Declare an array variable on the stack and compare the addresses of consecutive elements.
#include <stdio.h>
#include <stdlib.h>
int
main(void)
{
char buf[16];
printf("&buf[0]: %x\n&buf[1]: %x\n", &buf[0], &buf[1]);
return 0;
}
The output is:
misha#misha-K42Jr:~/Desktop/stackoverflow$ ./a.out
&buf[0]: d1149980
&buf[1]: d1149981
So the stack is growing down, as expected.
You can also monitor ESP register with inline assembly. ESP register holds address to unallocated stack. So if something is pushed to stack - ESP decreases and if pop'ed - ESP increases. (There are other commands which modifies stack, for example function call/return).
For example what is going on with stack when we try to compute recursive function such as Fibonacci Number (Visual Studio):
#include <stdio.h>
int FibonacciNumber(int n) {
int stackpointer = 0;
__asm {
mov stackpointer, esp
}
printf("stack pointer: %i\n", stackpointer);
if (n < 2)
return n;
else
return FibonacciNumber(n-1) + FibonacciNumber(n-2);
}
int main () {
FibonacciNumber(10);
return 0;
}

Resources