Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does a stack overflow occur at varying stack usage each run instead of a fixed amount?

I am running a program with a recursive call on a Debian OS. My stack size is

-s: stack size (kbytes)             8192

As far as I've learned, the stack size must be fixed, and should be the same that must be allocated to a program at every run unless it is explicitly changed with ulimit.

The recursive function is a decrements a given number until it reaches 0. This is written in Rust.

fn print_till_zero(x: &mut i32) {
    *x -= 1;
    println!("Variable is {}", *x);
    while *x != 0 {
        print_till_zero(x);
    }
}

and the value is passed as

static mut Y: i32 = 999999999;
unsafe {
    print_till_zero(&mut Y);
}

Since the stack allocated to the program is fixed, and theoretically must not change, I was expecting a stack overflow at the same value each time, but it is not, which means the stack allocation is variadic.

Run 1:

====snip====
Variable is 999895412
Variable is 999895411

thread 'main' has overflowed its stack
fatal runtime error: stack overflow

Run 2:

====snip====
Variable is 999895352
Variable is 999895351

thread 'main' has overflowed its stack
fatal runtime error: stack overflow

Although the difference is subtle, shouldn't it be ideally causing the stack overflow at the same variable? Why is it happening at different times, implying different stack size for each run? This is not specific to Rust; a similar behavior is observed in C:

#pragma GCC push_options
#pragma GCC optimize ("O0")
#include<stdio.h>
void rec(int i){
    printf("%d,",i);
    rec(i-1);
    fflush(stdout);
}
int main(){
setbuf(stdout,NULL);
rec(1000000);
}
#pragma GCC pop_options

Output:

Run 1:

738551,738550,[1]    7052 segmentation fault

Run 2:

738438,738437,[1]    7125 segmentation fault
like image 575
nohup Avatar asked Mar 24 '17 07:03

nohup


People also ask

What is a stack overflow?

Stack overflow in computer programming occurs when more items than a stack can hold are added. Explore errors, exceptions, and causes of stack overflow and learn about stack push, pop, underflow, and overflow.

What are the causes of Stack Overflow?

Oops. Another cause of stack overflow is when there simply isn't enough physical memory, even if we allocated plenty for our stack (stacks usually grow up or down and eventually run into other stuff in memory). The most likely culprit though, is something known as recursion.

How much is too much stack for a function?

The only valid answer is vague: "too much is when the stack overflows." Unless you are in complete control over the implementation of every line of code between the program's entry point and the function in question, you can make no assumptions about how much stack is available.

What happens if you exceed the size of a stack variable?

If the sum of your stack variables (including low-level overhead such as return addresses, stack-based arguments, return value placeholders and alignment bytes) in the entire call stack exceeds that limit, you get a stack overflow, which typically takes down your program without any chance at recovery. A few kilobytes are usually fine.


1 Answers

Most probably this is due to ASLR.

The base address of the stack is randomized at each run to make certain types of exploits more difficult; on Linux this has a granularity of 16 bytes (which is the biggest alignment requirement on x86 and almost any other platform I know).

On the other hand, the page size is (normally) 4 KB on x86, and the system detects the stack overflow when you touch the first forbidden page; this means that you'll always have available a partial page first (with the offset depending from ASLR), and then two full pages before the system detects a stack overflow. Hence the total usable stack size is at least the 8192 bytes you requested, plus the first partial page, whose available size is different at each run.1


  1. All this in the "regular" case where the offset is nonzero; if you are very lucky and the random offset is zero you probably get exactly two pages.
like image 177
Matteo Italia Avatar answered Sep 26 '22 22:09

Matteo Italia