1

Note: I am new to learning C and this might have a completely easy solution which I am ignorant of. In that case, please enlighten me SO.

I am having issues debugging a C program, which I received from a colleague. In essence, I managed to trace the segfault error to a failing call to calloc() if n is bigger than 46341:

float *v = (float*) calloc(n * (n - 1)/2, sizeof(float));

Here is set of minimal code that triggers the problem:

#include <stdio.h>
#include <stdlib.h>
int main(int argc, const char * argv[]){

    int ngenes = 46341;

    float *v = (float*) calloc(ngenes * (ngenes - 1)/2, sizeof(float));
    if(v) printf("Allocation succeeded\n");
    free(v);

    ngenes++;

    v = (float*) calloc(ngenes * (ngenes - 1)/2, sizeof(float));
    if(v) printf("Allocation succeeded\n");
    free(v);

    return 0;
}

Same code on ideone.

AFAIK, this evaluates to exactly 4GiB, which is why I am suspicious. The systems I've tried this on are all 64bit, so the allocation shouldn't be a problem. Searching around on SO has brought up the idea that calloc() might be failing to find a contiguous space, so I tried several calls to calloc(), and also tried to call realloc(). Finally, I tried to implement the allocation n C++ with calls to float *v = new float[n * (n - 1)/2]() which throws a bad_alloc error.

The system I've been trying this on:

$ uname -a
Linux picea 3.13.0-35-generic #62-Ubuntu SMP Fri Aug 15 01:58:42 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux
$ free
             total       used       free     shared    buffers     cached
Mem:     396222336  368621612   27600724      32320     281536  346677332
-/+ buffers/cache:   21662744  374559592
Swap:    125061116   64894524   60166592

I have tried compiling with:

gcc -m64 ...

to no avail. Running printf("%lu\n",SIZE_MAX); returns 18446744073709551615

Honestly, I am out of ideas.

1 Answers1

8

You're most likely compiling this on an LP64 architecture, where int is 32-bit, but long and pointers are 64-bit. The size calculation ends up being done at integer precision, then promoted to 64-bit, thus yielding incorrect size (negative, or much shorter than intended).

Solution is to use

size_t ngenes = 46341;

instead. size_t is the type you should use for sizes and lengths of in-memory objects.

Nominal Animal
  • 38,216
  • 5
  • 59
  • 86
  • 2
    Thanks a lot, I swear I had tried this already, but after your suggestion I tried to verify it and it's working. I blame the 4th glass of red wine. – Bastian Schiffthaler Aug 13 '15 at 22:47