1

In both the functions defined below, it tries to allocate 10M of memory in the stack. But the segmentation fault happens only in the second case and not it the first and I am trying to understand why so.

Function definition 1:

a(int *i)
{
    char iptr[50000000]; 
    *i = 1;
}

Function definition 2:

a()
{
    char c;
    char iptr[5000000];

    printf("&c     = 0x%lx, iptr = 0x%x  ...  ", &c, iptr);
    fflush(stdout); 
    c = iptr[0]; 
    printf("ok\n");
}

According to my understanding in case of local variables that are not alloted memory dynamically are stored in stack section of the program. So I suppose, during compile time itself the compiler checks if the variable fits in the stack or not.

Hence if above stated is true, then segmentation fault should occur in both the cases (i.e. also in case 1).

The website (http://web.eecs.utk.edu/courses/spring2012/cs360/360/notes/Memory/lecture.html) from where I picked this states that the segfault happens in function 2 in a when the code attempts to push iptr on the stack for the printf call. This is because the stack pointer is pointing to the void. Had we not referenced anything at the stack pointer, our program should have worked.

I need help understanding this last statement and my earlier doubt related to this.

Prashant Kumar
  • 20,069
  • 14
  • 47
  • 63
  • 6
    Are you sure `iptr` isn't being optimized out in the first case? You don't use it... The statement about "had we not referenced anything at the stack pointer" is just saying that allocating huge amounts of memory on the stack probably won't cause a crash (because the "allocation" generally consists just of incrementing the stack pointer by the allocation size), but trying to *use* the stack afterwards will cause a crash, because it's past the end of the actual reserved stack space. – Cameron Dec 03 '13 at 18:18
  • 1
    The compiler is free to place variables where ever it likes, there are no guarantees that a local variable will not be implicitly heap allocated. The only requirement is that the compiler clean them up. – Mgetz Dec 03 '13 at 18:19
  • 3
    I explain this in [Error accessing pointers when succesfully allocated array is too big](http://stackoverflow.com/questions/19846401/error-accessing-pointers-when-succesfully-allocated-array-is-too-big/19846618#19846618), basically it will adjust the stack pointer but if it does not actually attempt to use it there is no problem. – Shafik Yaghmour Dec 03 '13 at 18:19
  • @ShafikYaghmour : Thanks for pointing to that. But this mapping of variables to stack is done during compile time the segfault should occur in both cases right ?? Even if there is no access trial in first case but still mapping is done ... – Aaditya Gavandalkar Dec 03 '13 at 18:26
  • @AadityaGavandalkar allocating on the stack at least for `gcc` on `x86` will just be a `sub` of the stack pointer which does not require an out of bounds memory access. This will depends on a specific implementation of course but it most likely explains the behavior you are seeing but may not work the same way on different platforms and this is not behavior you should reply on anyway. – Shafik Yaghmour Dec 03 '13 at 18:29
  • The stack size, (at least for main), is set by the linker - the compiler does not know how much stack is too much. – Martin James Dec 03 '13 at 18:44
  • @ShafikYaghmour okay. Thank you now its more clear. – Aaditya Gavandalkar Dec 03 '13 at 18:45
  • @MartinJames: It may not even be set by the linker. In some OSs as linux the stack for the main thread grows as needed at runtime until it hits the limit configured for the user. Playing with `ulimit -s` you can make it smaller or larger. – David Rodríguez - dribeas Dec 06 '13 at 13:57

4 Answers4

4

So I suppose, during compile time itself the compiler checks if the variable fits in the stack or not.

No, that cannot be done. When compiling a function, the compiler does not know what the call stack will be when the function is called, so it will assume that you know what you are doing (which might or not be the case). Also note that the amount of stack space may be affected by both compile time and runtime restrictions (in Linux you can set the stack size with ulimit on the shell that starts the process).

I need help understanding this last statement and my earlier doubt related to this.

I would not attempt to look too much into that statement, it is not standard but rather based on knowledge of a particular implementation that is not even described there, and thus is built on some assumptions that are not necessarily true.

It assumes that the act of allocating the array does not 'touch' the allocated memory (in some debug builds in some implementations that is false) and thus whether you attempt to allocate 1 byte or 100M if the data is not touched by your program the allocation is fine --this need not be the case.

It also assumes that the arguments of the function printf are passed in the stack (this is actually the case in all implementations I know, due to the variadic arguments nature of the function). With the previous assumption, the array would overflow the stack (assuming an stack of <10M), but would not crash as the memory is not accessed, but to be able to call printf the value of the argument would be pushed to the stack beyond the array. This will write to memory and that write will be beyond the allocated space for the stack and crash.

Again, all this is implementation, not defined by the language.

David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
0

Error in your code is being thrown by the following code:

; Find next lower page and probe
cs20:
        sub     eax, _PAGESIZE_         ; decrease by PAGESIZE
        test    dword ptr [eax],eax     ; probe page. "**This line throws the error**"
        jmp     short cs10

_chkstk endp

        end

From chkstk.asm file, which Provide stack checking on procedure entry. And this file explicitically defines:

_PAGESIZE_      equ     1000h

Now as a explanation of your problem This Question tells everything you need as mentioned by: Shafik Yaghmour

Community
  • 1
  • 1
deeiip
  • 3,319
  • 2
  • 22
  • 33
0

Your printf format string assumes that pointers, ints (%x), and longs (%lx) are all the same size; this may be false on your platform, leading to undefined behavior. Use %p instead. I intended to make this a comment, but can't yet.

kero
  • 10,647
  • 5
  • 41
  • 51
Todd Fleming
  • 216
  • 2
  • 4
0

I am surprised no one noticed that the first function allocates 10 times the space than the second function. There are seven zeros after 5 in the first function whereas the second function has six zeros after 5 :-)

I compiled it with gcc-4.6.3 and got segmentation fault on the first function but not on the second function. After I removed the additional zero in the first function, seg fault went away. Adding a zero in the second function introduced the seg fault. So at least in my case, the reason of this seg fault is that the program could not allocate the required space on the stack. I would be happy to hear about the observations that differ from the above.