Why does this give a segmentation fault? - c

I'm stunned, why does this code give me a segmentation fault?
#include <stdio.h>
#define LIMIT 1500000
typedef struct {
int p;
int a;
int b;
} triplet;
int main(int argc, char **argv) {
int i;
triplet triplets[LIMIT];
for (i = 0; i < LIMIT; i++) {
triplets[i].p = 9; // remove this line and everything works fine
}
printf("%d\n", triplets[15].p);
return 0;
}
EDIT: After changing LIMIT to 150 I no longer get a segmentation fault, it prints random numbers instead.
EDIT2: Now I know what the site name stands for :) I made the array global and everything works fine now.

Stack overflow! Allocating 1500000 records at 12 bytes per record (assuming 4-byte int), requires more than 17 MB of stack space. Make your triplets array global or dynamically allocate it.
As to your edit - shrinking the array will probably stop the stack overflow, but your printf() call will still print uninitialized data - triplets[15].p could be anything at the time you print it out.

When you do
triplet triplets[LIMIT];
you're allocating that on the stack. Which is apparently too big for your system.
If you do
triplet* triplets=(triplet*)malloc(LIMIT*sizeof(triplet));
you'll allocate it on the heap and everything should be fine. Be sure to free the memory when you're done with it
free(triplets);

Related

Array Allocation on the Heap in C

I have already worked with the stack and the heap, and in the memory management topic generally, but there is a lot of thing's i can't understand
Like, if i'm allocating an array of integer using the heap with malloc and realloc how can i determine the exact size of the array i want to work with?
This Example:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char* argv[]){
int *array = (int *)malloc(2);
array[0] = 2;
array[1] = 1;
//What? i have allocated just 2 to be the size
array[2] = 3;
array[3] = 4;
array[4] = 4;
array[5] = 6;
//there is no segmentation fault
for(int i = 0; i < sizeof(array); i++){
printf("%d\n",array[i]);
}
}
And the wierd result i'm getting is:
2
1
3
4
4
6
1041 // ???
0
So, can someone explain to me how can i use malloc in the 100% correct way?
To correctly allocate an array using malloc, use sizeof to determine the size of each element in your array, then multiply by the number of each that you need.
Your code is only allocating 2 bytes of memory in heap, so when you write these integers (which take 4 bytes each on my machine), you are overwriting the values of unrelated state within the heap located beyond those two bytes, thus corrupting the machine state and creating undefined (that's bad) behavior.
In addition, your for loop was looping on the size of array pointer, which is typically 8 bytes. So your for loop would have tried to walk over 8 int elements, in an array of 6 ints in which you had only allocated 2 byte instead of the 24 bytes needed. Lots of bad undefined behaviour to go around here!
You may or may not get a segmentation fault due to this. A segmentation fault means you are dereferencing a pointer to an invalid page (segment) of memory, and this is caught by the hardware.
When you corrupt memory, you may not see the result of your error immediately as a segmentation fault if the memory you are writing is valid memory. Worse, if you corrupt the stack or a pointer, it may take a long time to get an actual fault to help detect the corruption created. This makes it hard to connect the fault to the event that caused the exception since your code could run for a long time before getting a segmentation fault.
#include <stdio.h>
#include <stdlib.h>
#define NUM_INTS_WANTED 6
int main(int argc, char* argv[]){
// No more trampling memory since array allocated to correct size
int *array = malloc(sizeof(int)*NUM_INTS_WANTED);
// Always check if malloc succeeded by checking that pointer is not NULL
if (array != NULL) {
array[0] = 2;
array[1] = 1;
array[2] = 3;
array[3] = 4;
array[4] = 4;
array[5] = 6;
// No more seeing 8 ints since you stop after 6 ints now
for(int i = 0; i < NUM_INTS_WANTED; i++){
printf("%d\n",array[i]);
}
} else {
// malloc failed! Report it.
printf("malloc failed!\n");
}
}
You can't. It's impossible.
Once upon a time a certain heap manager exposed this information by providing another function that would indeed return the real size. (It's padded up to the next block size.) They took it out after it was discovered to have caused more bugs than it prevented.
On most heap managers, the real size in bytes can be found at a small negative offset, but not all of them. Don't write this code. You will regret it if you have to maintain it. The heap manager can be swapped out from under you and you won't know what went wrong.

Getting segmentation fault when indexing a 'mallocced' array

I've been struggling with this one for a few hours now and I'm at a loss as to what's happening. This is the code for program.c:
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#define SPACE 32
#define INITIAL 4
typedef struct {
char *town;
char *country;
} town_t;
typedef struct {
int num_towns, current_size;
town_t **towns_list;
} index_t;
int main(int argc, char *argv[]) {
index_t town_index;
town_index.current_size = INITIAL;
town_index.towns_list = malloc(town_index.current_size * sizeof(*(town_index.towns_list)));
assert(town_index.towns_list != NULL);
printf("Step: %d\n", 1);
town_index.towns_list[0]->town = malloc(4 * sizeof(*(town_index.towns_list[0]->town)));
printf("Step: %d\n", 2);
assert(town_index.towns_list[0]->town != NULL);
return 0;
}
On Linux this is how it runs:
./program
Step: 1
Segmentation fault
but on Windows it prints out
program.exe
Step: 1
Step: 2
as I'd expect, which really isn't helping. For the Linux output, however, clearly the first print statement is being executed but not the second, which would lead me to think that the line between is that one at fault. Particularly, I think doing town_index.towns_list[0] is causing me issues, but I cannot say why.
This is a relatively complex data structure, so maybe I'm getting lost at some point. Basically town_index is meant to be a index struct that contains the current number of towns in towns_list and current_size which reflects the space currently available to save towns. It also contains an array of pointers to town_ts which contain the name and country as strings.
I've tried to use Valgrind, but it's really not helping out much. Here's a Pastebin for those who want to see.
This is a simplified scenario of what I was experiencing in another program, so don't any mind magic numbers and whatnot.
This is on VirtualBox Linux Mint 64-bit.
Unrelated question, if anyone can: How do I get Valgrind to display the precise lines? I see that everywhere else online, but my output just tells me the folder in which the program and function is, which isn't much help.
You initialized town_index.towns_list, but not town_index.towns_list[0], so town_index.towns_list[0]->town is undefined behaviour.
You missed something like
for (int i = 0; i < town_index.current_size; ++i)
town_index.towns_list[i] = malloc(sizeof **town_index.towns_list);
for the second dimension.
town_index.towns_list and town_index.towns_list[0] are not the same. You initialize town_index.towns_list but town_index.towns_list[0] is equal to 0. The crash caused by dereferencing town_index.towns_list[0]

Segmentation fault in a well compiled C program

I am solving a problem on USACO. In the problem, I have to take two strings as inputs and calculate the numerical values modulo 47. If the values are same, then GO is to be printed otherwise STAY has to be printed. The initial numerical value will be calculated by taking the product of the numerical values of the alphabets ( 1 for A and similarily 26 for Z ) and then the final number will be calculated by using modulo.
My program is being compiled withour any error and running well on my computer. However, it is showing a segmentation fault as the execution error by the grader computer. The program and the output is as follows:-
Program:-
#include<stdio.h>
#include<string.h>
main()
{
int cal(char *ptr);
char *comet,*group;
int a,b;
scanf("%s",comet);
a=cal(comet);
scanf("%s",group);
b=cal(group);
if(a==b)
printf("GO");
else
printf("STAY");
return 0;
}
int cal(char *ptr)
{
int i=0,c,prod=1,mod;
while(ptr[i]!='\0')
{
if(ptr[i]>='A'&&ptr[i]<='Z')
{
c=ptr[i]-'#';
prod=prod*c;
i++;
}
}
mod=prod%47;
return mod;
}
OUTPUT:-
My question is how to pinpoint the segmentation fault. I have read about this fault but don't know what to do in this program. Any help would be great.
char *comet,*group;
int a,b;
scanf("%s",comet);
comet pointer is uninitialized. You need to allocate memory and makes comet points at this allocated memory otherwise scanf will write bytes in a random location which will likely crash your system.
Both comet and group are uninitialized pointers which do not have any memory allocated for storing the input strings.
Your program should be doing this at least. Increase the size of MAX_STRING_SIZE per your needs.
#define MAX_STRING_SIZE 100
char comet[MAX_STRING_SIZE];
char group[MAX_STRING_SIZE];
You still have the risk of buffer overflow with scanf. You can look at this post for some possible ways to avoid buffer overflow.
Your while is highly suspect: i is increased only if ptr[i] is an uppercase letter. What should happen if it isn't? How does If you have an ironclad guarantee that only uppercase letters will show up, you could write:
prod = 1;
while(*ptr) {
prod *= *ptr - 'A' + 1;
ptr++;
}
(Your ptr[i] - '#' had me scratching my head until I broke out ascii(7). I believe my version is clearer, and any halfway competent compiler will give the same code.)
Or, more idiomatically:
int cal(char *ptr)
{
int prod = 1;
while(*ptr)
prod *= *ptr++ - 'A' + 1;
return prod % 47;
}
Just be careful that the product does't overflow, perhaps do the modulus each character:
int cal(char *ptr)
{
int prod = 1;
while(*ptr) {
prod *= *ptr++ - 'A' + 1;
prod %= 47;
}
return prod;
}
You never allocate space for comet or group. Use malloc() or similar to set aside memory for those pointers, so that you can actually store something in what they point to.
#define MAX_STRING_LENGTH 256
...
char *comet, *group;
int a, b;
comet = NULL;
comet = malloc(MAX_STRING_LENGTH);
if (!comet) {
fprintf(stderr, "ERROR: Could not allocate memory to comet\n");
return EXIT_FAILURE;
}
scanf("%s",comet);
/* repeat for other pointers, as needed */
/* ... */
/* free up allocated memory at the end of the program to help prevent leaks */
free(comet);
comet = NULL;
"running well on my computer" this is not possible in your case as you are not using any compiler specific code (like getch for turbo c)
You didn't allocate memory for storing the string.The pointers comet and group don't point to anything.scanf requires an address to write the input but the pointers do not contain an address and that is why you are getting a segmentation fault.
You can allocate memory using malloc (or calloc) or you can define a character array.
The corrected code is
#include<stdio.h>
#include<string.h>
#define MAXLENGTH 100
int main()
{
int cal(char *ptr);
char comet[MAXLENGTH],group[MAXLENGTH];
int a,b;
scanf("%s",comet);
a=cal(comet);
scanf("%s",group);
b=cal(group);
if(a==b)
printf("GO");
else
printf("STAY");
return 0;
}
int cal(char *ptr)
{
int i=0,c,prod=1,mod;
while(ptr[i]!='\0')
{
if(ptr[i]>='A'&&ptr[i]<='Z')
{
c=ptr[i]-'#';
prod=prod*c;
i++;
}
}
mod=prod%47;
return mod;
}

"Status stack overflow" in C with simple iteration

I started to learn C recently. I use Code::Blocks with MinGW and Cygwin GCC.
I made a very simple prime sieve for Project Euler problem 10, which prints primes below a certain limit to stdout. It works fine until roughly 500000 as limit, but above that my minGW-compiled .exe crashes and the GCC-compiled one throws a "STATUS_STACK_OVERFLOW" exception.
I'm puzzled as to why, since the code is totally non-recursive, consisting of simple for loops.
#include <stdio.h>
#include <math.h>
#define LIMIT 550000
int main()
{
int sieve[LIMIT+1] = {0};
int i, n;
for (i = 2; i <= (int)floor(sqrt(LIMIT)); i++){
if (!sieve[i]){
printf("%d\n", i);
for (n = 2; n <= LIMIT/i; n++){
sieve[n*i] = 1;
}
}
}
for (i; i <= LIMIT; i++){
if (!sieve[i]){
printf("%d\n", i);
}
}
return 0;
}
Seems like you cannot allocate 550000 ints on the stack, allocate them dynamically instead.
int * sieve;
sieve = malloc(sizeof(int) * (LIMIT+1));
Your basic options are to store variables in data segment when your memory chunk is bigger than stack:
allocating memory for array in heap with malloc (as #Binyamin explained)
storing array in Data/BSS segments by declaring array as static int sieve[SIZE_MACRO]
All the memory in that program is allocated on the stack. When you increase the size of the array you increase the amount of space required on the stack. Eventually the method cannot be called as there isn't enough space on the stack to accomodate it.
Either experiement with mallocing the array (so it's allocated on the heap). Or learn how to tell the compiler to allocate a larger stack.

Memory allocation for a matrix in C

Why is the following code resulting in Segmentation fault? (I'm trying to create two matrices of the same size, one with static and the other with dynamic allocation)
#include <stdio.h>
#include <stdlib.h>
//Segmentation fault!
int main(){
#define X 5000
#define Y 6000
int i;
int a[X][Y];
int** b = (int**) malloc(sizeof(int*) * X);
for(i=0; i<X; i++){
b[i] = malloc (sizeof(int) * Y);
}
}
Weirdly enough, if I comment out one of the matrix definitions, the code runs fine. Like this:
#include <stdio.h>
#include <stdlib.h>
//No Segmentation fault!
int main(){
#define X 5000
#define Y 6000
int i;
//int a[X][Y];
int** b = (int**) malloc(sizeof(int*) * X);
for(i=0; i<X; i++){
b[i] = malloc (sizeof(int) * Y);
}
}
or
#include <stdio.h>
#include <stdlib.h>
//No Segmentation fault!
int main(){
#define X 5000
#define Y 6000
int i;
int a[X][Y];
//int** b = (int**) malloc(sizeof(int*) * X);
//for(i=0; i<X; i++){
// b[i] = malloc (sizeof(int) * Y);
//}
}
I'm running gcc on Linux on a 32-bit machine.
Edit: Checking if malloc() succeeds:
#include <stdio.h>
#include <stdlib.h>
//No Segmentation fault!
int main(){
#define X 5000
#define Y 6000
int i;
int a[X][Y];
int* tmp;
int** b = (int**) malloc(sizeof(int*) * X);
if(!b){
printf("Error on first malloc.\n");
}
else{
for(i=0; i<X; i++){
tmp = malloc (sizeof(int) * Y);
if(tmp)
b[i] = tmp;
else{
printf("Error on second malloc, i=%d.\n", i);
return;
}
}
}
}
Nothing is printed out when I run it (expect of course for "Segmentation fault")
Your a variable requires, on a 32-bit system, 5000 * 6000 * 4 = 120 MB of stack space. It's possible that this violates some limit, which causes the segmentation fault.
Also, it's of course possible that malloc() fails at some point, which might casue you to dereference a NULL pointer.
You are getting a segmentation fault which means that your program is attempting to access a memory address that has not been assigned to its process. The array a is a local variable and thus allocated memory from the stack. As unwind pointed out a requires 120 Mbytes of storage. This is almost certainly larger than the stack space that the OS has allocated to your process. As soon as the for loop walks off the end of the stack you get a segmentation fault.
In Linux the stack size is controlled by the OS not the compiler so try the following:-
$ ulimit -a
In the response you should see a line something like this:-
stack size (kbytes) (-s) 10240
This means that each process gets 10Mbyte of storage, nowhere near enough for your large array.
You can adjust the stack size with a ulimit -s <stack size> command but I suspect it will not allow you to select a 120Mbyte stack size!
The simplest solution is to make a a global variable instead of an local variable.
Try to increase heap and stack limits in GCC:
gcc -Wl,--stack=xxxxx -Wl,--heap=yyyyy
Those are sizable allocations. Have you tried checking to make sure malloc() succeeds?
You might use malloc() for all your arrays, and check to make sure it succeeds each time.
A stack overflow (how appropriate!) can result in a segmentation fault which is what it seems you're seeing here.
In your third case the stack pointer is being moved to an invalid address but isn't being used for anything since the program then exits. If you put any operation after the stack allocation you should get a segfault.
Perhaps the compiler is just changing the stack pointer to some large value but never using it, and thus never causing a memory access violation.
Try initializing all of the elements of A in your third example? Your first example tries to allocate B after A on the stack, and accessing the stack that high (on the first assignment to B) might be what's causing the segfault.
Your 3rd code doesn't work either (on my system at least).
Try allocating memory to array a on the heap rather(when dimensions are large).
Both matrices don't fit in the limits of your memory. You can allocate only one at a time.
If you define Y as 3000 instead of 6000, your program should not issue segfault.

Resources