0

I'm writing some code for a statistics package, and I start off by reading in data to a pointer array. I initialize the pointer and allocate sufficient memory using malloc; however, I sometimes get an error in the memory allocation at the end of the code below.

#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include "stats.h"

int main(int argc, char **argv) {
FILE *fp, *outFile, *outBin;    // create a file identifier
size_t n, nbins; // # of data points
double *data; // pointer to hold data
double average, variance, *med; // stat returns
int medianComplete, histComplete, i; // return 1 on success
hist_t *Histogram;

// read in the number of bins from exe arguments
nbins = atoi(argv[1]);
nbins = (size_t)nbins;

// open the binary datafile and read in first value
// which is number of data points
// use exe input for filename
fp = fopen(argv[2],"rb");
fread(&n, sizeof(size_t),1,fp);

// allocate enough memory to hold all data
data = (double*)malloc(sizeof(double)*n);
if (!data)
    printf("Memory allocation error");
fread(data,sizeof(double),n,fp);

This program compiles and runs well on my personal machine (MacOSX), but fails due to a segmentation error when I try to run it on a Linux server. I used Valgrind to see if I could track down the error and I receive the following result.

==8641== Warning: silly arg (-501426814648844128) to malloc()
==8641== Invalid write of size 1
==8641==    at 0x4C2B20D: mempcpy (mc_replace_strmem.c:956)
==8641==    by 0x4EA2F15: _IO_file_xsgetn (fileops.c:1423)
==8641==    by 0x4E971D2: fread (iofread.c:44)
==8641==    by 0x40086D: main (runstats.c:28)
==8641==  Address 0x0 is not stack'd, malloc'd or (recently) free'd

This is the first program I've ever written that uses pointers, and I'm at a loss for why it would work on one system but not the other.

oHo
  • 51,447
  • 27
  • 165
  • 200
dwv5009
  • 33
  • 4
  • Added in a test of the file pointer, and fopen() is successful. Valgrind indicates that the error occurs when I allocate memory to data. The check I perform on data fails on the server, but passes on my own computer. – dwv5009 Feb 03 '12 at 08:29
  • First thouht that comes when I see the question is: "Why is he doing this in C, when there are dozens of more suitable languages?.." – vines Feb 03 '12 at 08:35

2 Answers2

5

The sizeof(size_t) is platform dependent. On OSX with the default 32 bit code, size_t is 4 bytes. On 64 bit Linux, size_t is 8 bytes. If you're running on 64 bit Linux, you're reading a different n that you're reading on 32 bit OSX.

If you must use a binary data format, don't use the size of platform specific types as the field size. Decide whether the file header is 4 or 8 bytes, little or big endian, and use that consistently.

See: What's sizeof(size_t) on 32-bit vs the various 64-bit data models?

Community
  • 1
  • 1
Adrian Cox
  • 6,204
  • 5
  • 41
  • 68
  • Ah! of course. That solved that bug. Thanks! Now the error I'm getting from Valgrind is: "Uninitialised value was created by a stack allocation" pointing to my main declaration. – dwv5009 Feb 03 '12 at 08:57
  • Are you reading with `fread` into a `size_t` still? If you're reading 4 bytes, consider using `fread` into a `uint32_t` from `stdint.h`. – Adrian Cox Feb 03 '12 at 09:04
2

You should definitely format your source prior to posting...

Use a debugger or printf the value of n after performing fread(&n, sizeof(size_t),1,fp);. Seems you don't get the value you expected.

Axel
  • 13,939
  • 5
  • 50
  • 79
  • Sorry about the formatting, I'll definitely do that in the future. I've checked this, n=20 as expected. – dwv5009 Feb 03 '12 at 08:22
  • @dwv5009 Valgrind says it is not, assuming the code you posted is the one valgrind complains about. Did you check that n=20 by adding `printf("n=%zu\n", n);` right after the call to `fread(&n, sizeof(size_t),1,fp);` ? – nos Feb 03 '12 at 08:56
  • @nos Yes, I did exactly that. The result is "n=20". The answer below fixed it - the input file was written using size_t on a 32 bit system (4 bytes) and when I attempted to read in on the 64 bit system size_t was the incorrect size for my input file. – dwv5009 Feb 03 '12 at 09:05
  • You should format your source prior to anything, you should __always__ format your source when coding. – Eregrith Feb 03 '12 at 09:07
  • @dwv5009 that line wouldn't print 20 on the 64 bit machine if so. (but if you used printf("%u\n", n); , or even "%d" instead of "%zu" , you might have seen 20, even if n wasn't actually 20) – nos Feb 03 '12 at 11:54