printf command causing a seg fault? [duplicate] - c

This question already has answers here:
Getting a stack overflow exception when declaring a large array
(8 answers)
Closed 9 years ago.
When I try to initialize a large double dimensional character array, it works perfectly fine. But when I add a simple print command, it gives me a segmentation fault. Any ideas as to why this is happening?
#include<stdio.h>
int main(void)
{
printf("!");
char f[10000][10000];
}
It works fine without the printf command, or even if the printf command prints nothing, (i.e. ""). If I make it print anything at all it gives the error.
Any help?

This is probably because you are exceeding the stack. Your definition of f takes 100MB Stack space (10000x10000 bytes) and probably as soon as you actually use the stack, the system will find that there isn't that much room on the stack and segfault. You'll probably find the same with calling any other function.
Allocations of that size should be done through malloc().
char *f= malloc(10000*10000);
// access two dimensionally (equivalent of f[5][8])
char z= f[5*10000 + 8];

You are exceeding an unspecified limit of your C implementation, in particular, the total size of objects with automatic storage duration (aka "local variables"). The size of f[] is 100.000.000 bytes. Many C implementation keep automatic variables on the stack, which usually is a limited resource. On my Unix system (FreeBSD) I can inspect this limit:
$ ulimit -a
-t: cpu time (seconds) unlimited
-f: file size (blocks) unlimited
-d: data seg size (kbytes) 33554432
-s: stack size (kbytes) 524288
[...]
and if higher powers allow, increase it with ulimit -s number.

Related

When I enter the value 200000 as an input for a long variable, C program crashes, why?

For the simple code below, whenever I enter the value 200,000 (or any other high value), the program crashes:
long size;
printf("Enter the size of the array to be sorted: ");
scanf("%ld",&size);
Can anybody tell me why?
as based on my information, the range of long is much greater than 200,000
TIA
Edit:
the prev piece of code is followed by those declarations.
int arrMerge[size];
int arrQuick[size];
int arrSelect[size];
int arrInsert[size];
When I've commented the whole program except those lines (and the ones above) it has crashed. The following terminating message was given:
Process returned -1073741571 (0xC00000FD) execution time : 2.419 s
Press any key to continue.
According to this Microsoft documentation, the status code 0xC00000FD stands for STATUS_STACK_OVERFLOW. Your program is failing due to a stack overflow.
By default, a Windows program has a maximum stack size of about 1 megabyte. If you enter the number 200000, then your variable-length arrays will exceed this limit, causing the stack overflow.
You may want to consider allocating the memory for the arrays on the heap instead of the stack, for example using the function malloc. The heap does not have the limitation of only being able to allocate up to a single megabyte. It is able to store much larger amounts of data.
After size is set to 200,000, these definitions:
int arrMerge[size];
int arrQuick[size];
int arrSelect[size];
int arrInsert[size];
create arrays with automatic storage duration and size 800,000 bytes each, assuming int is four bytes, which is common today. That is a total of 3.2 MB.
Automatic storage duration is typically implemented using a stack (except for effects of optimization), and default stack sizes are 8 MiB on macOS, 2 MiB on Linux, and 1 MiB on Microsoft Windows.1 Thus, the arrays overrun the space set for the stack, and the program crashes.
Footnote
1 “MB” stands for megabyte, 1,000,000 bytes. “MiB” stands for Mebibyte, 220 bytes = 1,048,576 bytes.

what's the memory structure detail of a very simple process, and what's the detail of the crash [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 1 year ago.
Improve this question
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]=%d\n", 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.
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 is 0x7ffcd39df7a0, and the stack is mapped into the address range 7ffcd39c0000-7ffcd39e1000, beyond which is a gap of unmapped addresses. Subtracting, a is 6240 bytes from the top of the stack. Each int is 4 bytes, so that's 1560 ints. Thus accessing a[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.)
why a[1864] will cause crash.
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):
<- inaccessible memory
0x...C000 <- top of stack (page-aligned)
0x...B... <- stack frame for _start
... <- other stack frames, such as __libc_start_main
0x...A... <- stack frame for main (where a[] is located).
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 of ints between &a[0] and top of stack depends on the factors I listed.
Using a powerful debugging tool, I was able to find the source of your troubles.
lstrand#styx:~/tmp$ insure gcc -g -o simple simple.c
lstrand#styx:~/tmp$ ./simple >/dev/null
[simple.c:8] **READ_BAD_INDEX**
>> printf("a[%d]=%d\n", i, a[i]);
Reading array out of range: a[i]
Index used : 4
Valid range: 0 thru 2 (inclusive)
Stack trace where the error occurred:
main() simple.c, 8
[simple.c:9] **WRITE_BAD_INDEX**
>> a[i] = 0;
Writing array out of range: a[i]
Index used : 4
Valid range: 0 thru 2 (inclusive)
Stack trace where the error occurred:
main() simple.c, 9
**Memory corrupted. Program may crash!!**
**Insure trapped signal: 11**
Stack trace where the error occurred:
main() simple.c, 8
Segmentation violation
** TCA log data will be merged with tca.log **
Segmentation fault (core dumped)
lstrand#styx:~/tmp$
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:
void recurse()
{
char buf[1024];
recurse();
}
int main()
{
recurse();
return 0;
}
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.
(gdb) r
Starting program: /home/lstrand/tmp/so
Program received signal SIGSEGV, Segmentation fault.
0x0000000000400df2 in recurse () at so.c:5
5 recurse();
(gdb) where
#0 0x0000000000400df2 in recurse () at so.c:5
#1 0x0000000000400e79 in recurse () at so.c:5
#2 0x0000000000400e79 in recurse () at so.c:5
#3 0x0000000000400e79 in recurse () at so.c:5
[...]

Why am I not getting a segfault error with this simple code?

I have to show an error when I access an item outside of an array (without creating my own function for it). So I just thought it was necessary to access the value out of the array to trigger a segfault but this code does not crash at all:
int main(){
int tab[4];
printf("%d", tab[7]);
}
Why I can't get an error when I'm doing this?
When you invoke undefined behavior, anything can happen. You program may crash, it may display strange results, or it may appear to work properly.
Also, making a seemingly unrelated change such as adding an unused local variable or a simple call to printf can change the way in which undefined behavior manifests itself.
When I ran this program, it completed and printed 63. If I changed the referenced index from 7 to 7000, I get a segfault.
In short, just because the program can crash doesn't mean it will.
Because the behavior when you do things not allowed by the spec is "undefined". And because there are no bounds checks required in C. You got "lucky".
int tab[4]; says to allocate memory for 4 integers on the stack. tab is just a number of a memory address. It doesn't know anything about what it's pointing at or how much space as been allocated.
printf("%d", tab[7]); says to print out the 8th element of tab. So the compiler does...
tab is set to 1000 (for example) meaning memory address 1000.
tab represents a list of int, so each element will be sizeof(int), probably 4 or 8 bytes. Let's say 8.
Therefore tab[7] means to start reading at memory position (7 * 8) + 1000 = 1056 and for 8 more bytes. So it reads 1056 to 1063.
That's it. No bounds checks by the program itself. The hardware or OS might do a bounds check to prevent one process from reading arbitrary memory, have a look into protected memory, but nothing required by C.
So tab[7] faithfully reproduces whatever garbage is in 1056 to 1063.
You can write a little program to see this.
int main(){
int tab[4];
printf("sizeof(int): %zu\n", sizeof(int));
printf("tab: %d\n", tab);
printf("&tab[7]: %d\n", &tab[7]);
/* Note: tab must be cast to an integer else C will do pointer
math on it. `7 + tab` gives the same result. */
printf("(7 * sizeof(int)) + (int)tab: %d\n", (7 * sizeof(int)) + (int)tab);
printf("7 + tab: %d\n", 7 + tab);
}
The exact results will vary, but you'll see that &tab[7] is just some math done on tab to figure out what memory address to examine.
$ ./test
sizeof(int): 4
tab: 1595446448
&tab[7]: 1595446476
(7 * sizeof(int)) + (int)tab: 1595446476
7 + tab: 1595446476
1595446476 - 1595446448 is 28. 7 * 4 is 28.
An array in C is just a pointer to a block of memory with a starting point at, in this case, the arbitrary location of tab[0]. Sure you've set a bound of 4 but if you go past that, you just accessing random values that are past that block of memory. (i.e. the reason it is probably printing out weird numbers).

Array & segmentation fault

I'm creating the below array:
int p[100];
int
main ()
{
int i = 0;
while (1)
{
p[i] = 148;
i++;
}
return (0);
}
The program aborts with a segmentation fault after writing 1000 positions of the array, instead of the 100. I know that C doesn't check if the program writes out of bounds, this is left to the OS. I'm running it on ubuntu, the size of the stack is 8MB (limit -s). Why is it aborting after 1000? How can I check how much memory my OS allocates for an array?
Sorry if it's been asked before, I've been googling this but can't seem to find a specific explanation for this.
Accessing an invalid memory location leads to Undefined Behavior which means that anything can happen. It is not necessary for a segmentation-fault to occur.
...the size of the stack is 8MB (limit -s)...
variable int p[100]; is not at the stack but in data area because it is defined as global. It is not initialized so it is placed into BSS area and filled with zeros. You can check that printing array values just at the beginning of main() function.
As other said, using p[i] = 148; you produced undefined behaviour. Filling 1000 position you most probably reached end of BSS area and got segmentation fault.
It appear that you clearly get over the 100 elements defined (int p[100];) since you make a loop without any limitation (while (1)).
I would suggest to you to use a for loop instead:
for (i = 0; i < 100; i++) {
// do your stuff...
}
Regarding you more specific question about the memory, consider that any outside range request (in your situation over the 100 elements of the array) can produce an error. The fact that you notice it was 1000 in your situation can change depending on memory usage by other program.
It will fail once the CPU says
HEY! that's not Your memory, leave it!
The fact that the memory is not inside of the array does not mean that it's not for the application to manipulate.
The program aborts with a segmentation fault after writing 1000 positions of the array, instead of the 100.
You do not reason out Undefined Behavior. Its like asking If 1000 people are under a coconut tree, will 700 hundred of them always fall unconscious if a Coconut smacks each of their heads?

Is there any hard-wired limit on recursion depth in C

The program under discussion attempts to compute sum-of-first-n-natural-numbers using recursion. I know this can be done using a simple formula n*(n+1)/2 but the idea here is to use recursion.
The program is as follows:
#include <stdio.h>
unsigned long int add(unsigned long int n)
{
return (n == 0) ? 0 : n + add(n-1);
}
int main()
{
printf("result : %lu \n", add(1000000));
return 0;
}
The program worked well for n = 100,000 but when the value of n was increased to 1,000,000 it resulted in a Segmentation fault (core dumped)
The following was taken from the gdb message.
Program received signal SIGSEGV, Segmentation fault.
0x00000000004004cc in add (n=Cannot access memory at address 0x7fffff7feff8
) at k.c:4
My question(s):
Is there any hard-wired limit on recursion depth in C? or does the recursion depth depends on the available stack memory?
What are the possible reasons why a program would receive a reSIGSEGV signal?
Generally the limit will be the size of the stack. Each time you call a function, a certain amount of stack is eaten (usually dependent on the function). The eaten amount is the stack frame, and it is recovered when the function returns. The stack size is almost almost fixed when the program starts, either from being specified by the operating system (and often adjustable there), or even being hardcoded in the program.
Some implementations may have a technique where they can allocate new stack segments at run time. But in general, they don't.
Some functions will consume stack in slightly more unpredictable ways, such as when they allocate a variable-length array there.
Some functions may be compiled to use tail-calls in a way that will preserve stack space. Sometimes you can rewrite your function so that all calls (Such as to itself) happen as the last thing it does, and expect your compiler to optimise it.
It's not that easy to see exactly how much stack space is needed for each call to a function, and it will be subject to the optimisation level of the compiler. A cheap way to do that in your case would be to print &n each time its called; n will likely be on the stack (especially since the progam needs to take its address -- otherwise it could be in a register), and the distance between successive locations of it will indicate the size of the stack frame.
1)Consumption of the stack is expected to be reduced and written as tail recursion optimization.
gcc -O3 prog.c
#include <stdio.h>
unsigned long long int add(unsigned long int n, unsigned long long int sum){
return (n == 0) ? sum : add(n-1, n+sum); //tail recursion form
}
int main(){
printf("result : %llu \n", add(1000000, 0));//OK
return 0;
}
There is no theoretical limit to recursion depth in C. The only limits are those of your implementation, generally limited stack space.
(Note that the C standard doesn't actually require a stack-based implementation. I don't know of any real-world implementations that aren't stack based, but keep that in mind.)
A SIGSEGV can be caused by any number of things, but exceeding your stack limit is a relatively common one. Dereferencing a bad pointer is another.
The C standard does not define the minimum supported depth for function calls. If it did, which is quite hard to guarantee anyway, it would have it mentioned somewhere in section 5.2.4 Environmental limits.

Resources