Array & segmentation fault - c

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?

Related

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
[...]

Proc crashes even if it allocates less memory than limited by ulimit

I have set stack size to 2000Kb by ulimit -s 2000 and ulimit -Ss 2000 for hard limit. And in the below program i have allocated appox 2040000(510000 x 4) bytes which is less than i limited i.e,. 2048000(2000*4)bytes but i see that my program crashes! Can anybody suggest why this happens.
#include <stdio.h>
#include <malloc.h>
int main()
{
int a[510000] = {0};
a[510000] = 1;
printf("%d", a[510000]);
fflush(stdout);
sleep(70);
}
EDIT 1: Crash is not because of the array index out of bound as i tried lower index and still crashes. This happens only when i limit by ulimit.
int a[510000] will be an array with index from 0 to 509999. a[510000] is outside the array range.
The problem here is, in below mentioned statements
a[510000] = 1;
printf("%d", a[510000]);
you're having off-by-one index. The above statements are accessing array out of bounds. This in turn invokes undefined behaviour. One of the side effects of UB, other than getting a nasal demon is segmentation fault (The "Crash!!").
Remember, C uses 0-based array indexing.
You're corrupting the stack in
a[510000] = 1;
because the last index in that array is one less than 510000. So that assignment overwrites data on the stack and once other statements try to use that data your application crashes.

Segmentation Fault & printing an array without loops

I'm Just trying to run a simple program to count the number of spaces, digits and other characters using arrays. Below is my program:
void main(){
int digit_holders[10]={0};
int ch;
int i, white_space=0,other=0;
while((ch=getchar())!=EOF){
if(isspace(ch))
white_space++;
else if(isdigit(ch))
digit_holders[ch-'0']++;
else
other++;
}
digit_holders[12]=20;
printf("\n White spaces=%d\n Other=%d\n",white_space,other);
for(i=0;i<=9;i++)
printf("\ndigit_holders[%d]=%d\n",i,digit_holders[i]);
printf("\n digit_holder[12]=%d\n",digit_holders[12]);
}
2 Questions:
Why does digit_holders[12] still manage to print the assigned vale despite it being outside the range? Why doesn't it display a segmentation fault ?The same happens when I change the for loop check to i<=11 it manages to print digit_holders[11]=0 ( which it shouldn't) .. however when I replace 11/10 with 1100 i.e digit_holders[1100] in either of the case, the program crashes ( segmentation fault). Why so ?
Is there an easier way to print the elements of this array without using for loop ?
-Thanks!
There is no range checking in C so it gives it is best shot (I.e enough rope to hang yourself and the rest of the family).
Segmentation fault occurs from the OS. i.e. trying to access memory not assigned to the process.
As I wrote in the comment:
You will need a loop of some kind to print the content of your array in C.
You are assigning the 13th element of an array with only 10 elements declared, its risky to do and will be unstable, but wont necessarily result in a seg fault because if the OS hasnt modified it in the time between write and read, your pointer will resolve the value without error. But again, risky.
If you had declared an array with 13 elements, all 13 will be reserved in memory and there will be no chance of a seg fault. You are likely to get a seg fault if you interrogate an array outside of its declared limits, more so the further you go away from the range you defined.
It's possible to print "out-of-range" array indices in C because digit_holders[12] is handled as though digit_holders were a pointer with an offset of 12 * sizeof(int) added on to it.
This won't necessarily cause a segmentation fault, since the memory address being read might still be earmarked as being "available" to the program. A good example of this is a struct containing an array:
typedef struct {
int some_array[12];
int another_int;
} my_struct;
If you were to read the value of some_array[12], you'd get the contents of another_int instead, since it's stored directly after the last "valid" index of some_array.
As for the printing out of arrays: I'm not aware of any way to print out an array without using a loop in C, though it is possible in some other languages. For example, you could easily print out a list of strings in Python using print(", ".join(["This", "That", "The other"]))

Need help tracking down an illegal write. valgrind not noticing it

ive got a C program that gets caught in a for loop that it shouldn't, running it with
valgrind --tool=memcheck --leak-check=yes a.out
doesnt return anything even up until the program gets caught. is there a way to change the settings of valgrind to help me find the leak? as many have pointed out, it wouldnt be considered a leak, apologies
thanks in advance
here is the loop in question
int clockstate=0;
int clocklength=0;
int datalength=0;
int datastate=0;
int dataloc = 9;
((((some other code that i don't think is important to this part))))
int dataerr[13] = {0};
int clockerr[13] = {0}; // assumes that spill does not change within an event.
int spill=0;
int k = 0;
spill = Getspill(d+4*255+1); // get spill bit from around the middle
//printf("got spill: %d \n", spill); // third breakpoint
for( k = 0; k < 512; k++)
{
// Discardheader(d); // doesnt actually do anything, since it's a header.f
int databit = Getexpecteddata(d+4*k+1);
printf("%d ",k);
int transmitted = Datasample(&datastate, &datalength, d+4*k+2,dataerr,dataloc, databit);
printf("%d ",k);
Clocksample(&clockstate, &clocklength, d+4*k+3,clockerr, transmitted);
printf("%d \n",k);
// assuming only one error per event (implying the possibility of multi-error "errors"
// we construct the final error at the very end of the (outside this loop)
}
and the loop repeats after printing
254 254 254
255 255 255
256 256 1 <- this is the problem
2 2 2
3 3 3
edit** so i've tracked down where it is happening, and at one point in
void Clocksample (int* state, int* length, char *d, int *type, int transbit);
i have code that says *length = 1; so it seems that this command is somehow writing onto int k. my question now is, how did this happen, why isnt it changing length back to one like i want, and how do i fix it. if you want, i can post the whole code to Clocksample
Similar to last time, something in one of those functions, Clocksample() this time, is writing to memory that doesn't belong to the data/arrays that the function should be using. Most likely an out of bounds array write. Note: this is not a memory leak, which is allocating then losing track of memory blocks that should be freed.
Set a breakpoint at the call to Clocksample() for when k is 256. Then step into Clocksample(), keeping a watch on k (or the memory used by k). You can probably also just set a hardware memory write breakpoint on the memory allocated to k. How you do any of this depends on the debugger you're using.
Now single-step (or just run to the return of Clocksample() if you have a hardware breakpoint set) and when k changes, you'll have the culprit.
Please note that Valgrind is exceedingly weak when it comes to detecting stack buffer overflows (which is what appears to be happening here).
Google address-sanitizer is much better at detecting stack overflows, and I suggest you try it instead.
So your debugging output indicates that k is being changed during the call to your function Clocksample. I see that you are passing the addresses of at least two variables, &clockstate and &clocklength into that call. It seems quite likely to me that you have an array overrun or some other wild pointer in Clocksample that ends up overwriting the memory location where k is stored.
It might be possible to narrow down the bug if you post the code where k is declared (and whatever other variables are declared nearby in the same scope). For example if clocklength is declared right before k then you probably have a bug in using the pointer value &clocklength that leads to writing past the end of clocklength and corrupting k. But it's hard to know for sure without having the actual layout of variables you're using.
valgrind doesn't catch this because if, say, clocklength and k are right next to each other on the stack, valgrind can't tell if you have a perfectly valid access to k or a buggy access past the end of clocklength, since all it checks is what memory you actually access.

Array Allocation causing terminal to hang

I came across this code accidentally:
#include<stdio.h>
int main()
{
int i;
int array[3];
for(i=0;i<=3;i++)
array[i]=0;
return 0;
}
On running this code my terminal gets hanged - the code is not terminating.
When I replace 3 by 2 code runs successfully and terminates without a problem.
In C there is no bound checking on arrays, so what's the problem with the above code that is causing it to not terminate?
Platform - Ubuntu 10.04
Compiler - gcc
Just because there's no bound checking doesn't mean that there are no consequences to writing out of bounds. Doing so invokes Undefined Behavior, so there's no telling what may happen.
This time, on this compiler, on this architecture, it happens that when you write to array[3], you actually set i to zero, because i was positioned right after array on the stack.
Your code is reading beyond the bound of array and causing an Undefined Behavior.
When you declare an array of size 3. The valid index range is from 0 to 2.
While your loop runs from 0 to 3.
If you access anything beyond the valid range of an array then it is Undefined Behavior and your program may hang or crash or show any behavior. The c standard does not mandate any specific behavior in such cases.
When you say C does not do bounds checking it actually means that it is programmers responsibility to ensure that their programs do not access beyond the beyonds of the allocated array and failing to do so results in all safe bets being off and any behavior.
int array[3];
This declares an array of 3 ints, having indices 0, 1, and 2.
for(i=0;i<=3;i++)
array[i]=0;
This writes four ints into the array, at indices 0, 1, 2, and 3. That's a problem.
Nobody here can tell exactly what you're seeing -- you haven't even specified what platform you're working on. All we can say is that the code is broken, and that leads to whatever result you're seeing. One possibility is that i is stored right after array, so you end up setting i back to 0 when you do array[3]=0;. But that's just a guess.
The highest valid index for array is 2. Writing past that index invokes undefined behaviour.
What you're seeing is a manifestation of the undefined behaviour.
Contrast this with the following two snippets, both of which are correct:
/* 1 */
int array[3];
for(i=0;i<3;i++) { array[i] = 0; }
/* 2 */
int array[4];
for(i=0;i<4;i++) { array[i] = 0; }
You declared array of size 3 which means (0,1,2 are the valid indexes)
if you try to set 0 to some memory location which is not for us unexpected (generally called UB undefined behavior) things can happen
The elements in an array are numbered 0 to (n-1). Your array has 3 spots, but is initializing 4 location (0, 1, 2, 3). Typically, you'd have you for loop say i < 3 so that your numbers match, but you don't go over the upper bound of the array.

Resources