I’m trying to trigger a stack-overflow crash.
most probably, the crash value is not 1684 in you sandbox. but you will find your own value when running.
I just want to know a way to figure these out.
The program is compiled in CentOS 8, using a GNU compiler.
#include <stdio.h>
int main() {
int a[3];
for(int i=4;i<100000;i++){
printf("a[%d]=%dn", i, a[i]);
a[i] = 0;
}
return 0;
}
Then 1864 will be the first I value which will cause a crash.
I known stack-overflow will cause undefined behavior.
I just want to know the memory structure of this process. why a[1864] will cause a crash.
3
Answers
This particular value is by no means guaranteed or reliable. It will depend on the compiler and libc version, compilation flags, and a host of other variables.
In general, the memory layout looks like this (on machines where stack grows down, which is the majority of current machines):
You start overwriting stack from
&a[0]
, and continue going until you hit the top of the stack and step into inaccessible memory. The number ofint
s between&a[0]
and top of stack depends on the factors I listed.You crash when you access an address that’s not mapped into your address space, which happens when you run off the top of the stack.
You can get some insight by looking at the address of
a
as well as your program’s memory mappings, which you can see by reading/proc/self/maps
from within your program. See https://godbolt.org/z/1e5bvK for an example. In my test,a
is0x7ffcd39df7a0
, and the stack is mapped into the address range7ffcd39c0000-7ffcd39e1000
, beyond which is a gap of unmapped addresses. Subtracting,a
is 6240 bytes from the top of the stack. Eachint
is 4 bytes, so that’s 1560int
s. Thus accessinga[1560]
should crash, and that’s exactly what happened.The addresses and offsets will change from run to run due to ASLR and variation in how the startup code uses the stack.
(Just to be clear for other readers: accessing beyond the end of the stack is what will cause an immediate segfault. But as soon as you write even one element beyond the declared size of your array, even though that write instruction may not itself segfault, it is still overwriting other data that is potentially important. That is very likely to cause some sort of misbehavior further along, maybe very soon or maybe much later in your program’s execution. The result could eventually be a segfault, if you overwrote a pointer or a return address or something of the kind, or it could be something worse: data corruption, granting access to an intruder, blowing up the machine you’re controlling, becoming Skynet, etc.)
Using a powerful debugging tool, I was able to find the source of your troubles.
Edit:
To clarify, your program seems to assume that you can grow an array in C/C++ simply by writing past the end, as in JavaScript. There is also the subtle suggestion that you are coming from a Fortran background. The first past-the-end array location is at index 3, not 4.
In other words, your test program declares a fixed-size array on the stack. An array of size 3: with valid elements a[0], a[1], and a[2]. At the very first iteration of the loop, you are corrupting the stack.
The proper way to cause a stack overflow, as people on this site should well know, is to do something like this:
On Linux/x86_64, this still produces SIGSEGV when you run out of stack, but on other platforms (e.g., Windows) you will get a stack overflow violation.