views:

319

answers:

8

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")

+1  A: 

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.

WhirlWind
+5  A: 

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.

unwind
I though of that, but I still can't figure with the third code works if that's the case.Anyway, I tried to check for malloc() results, apparently they're all succeeding.
Snogzvwtr
+2  A: 

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).

Prasoon Saurav
+2  A: 

Try to increase heap and stack limits in GCC:

gcc -Wl,--stack=xxxxx -Wl,--heap=yyyyy
Juliano
Tried, but got an "unrecognized option '--stack'".From what I checked, apparently, those options are only for Windows. I'm on Linux.
Snogzvwtr
Actually, in Linux, these options are available only for i386 PE targets.
Juliano
A: 

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.

mouviciel
I do have (much) more than 120MB of available memory. There must be a way of doing this right. (Actually, the matrices I'll need on my actual program are even lager -- this just a toy example to help figure out what's going wrong).
Snogzvwtr
A: 

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.

TheJuice
A: 

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.

Martin
Thanks, I think now I understand the problem. I didn't realize before that acessing the stack (to create b) *after* allocating that much space to a is what could cause the segfault.
Snogzvwtr
A: 

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.

Andrew O'Reilly
Making 'a' a global variable indeed did the trick. Thanks! (the real program I'm working on is actually much more complex than this toy example, but same principle applies, so I think now I can go back to it).
Snogzvwtr