K. Vu K. Vu - 6 months ago 32
C Question

Segmentation fault with sscanf on big number

I am fairly new in C and I'm trying to read a large file (>30m lines) line by line and store some values of each line into an array. The format of the input file is:

1. inode 100660 uid 66322 gid 66068 bytes 5848 blks 128
2. inode 100662 uid 66492 gid 66076 bytes 159 blks 0
3. inode 100647 uid 66419 gid 66068 bytes 235 blks 0
4. inode 100663302 uid 66199 gid 66068 bytes 131 blks 0
5. inode 100663311 uid 66199 gid 66068 bytes 134 blks 0


And this is my code:

void loadArrayFromFile(char * filename) {
long bytesArray[380000000];
FILE * myfile;
myfile = fopen(filename, "r");
char line[1024];
char inodeText[10];
long int inode = 0;
int mybytes = 0;

if(myfile == NULL) {
printf("No file found \n");
exit(EXIT_FAILURE);
}

while(fgets(line, sizeof(line), myfile)) {
int x = (sscanf(line, "%s %ld %*s %*d %*s %*d %*[bytes] %d %*[^\n]", inodeText, &inode, &mybytes));
if(x > 1) {
bytesArray[inode] = mybytes;
}
}


This code works fine for the first 3 lines, however when it reaches line 4 I get a Segmentation Fault (core dumped) error. I suspect it has something to do with the inode value being too large to store into an int even though the max value an int can store is 2147483647. Can anyone help me out as to what the issue is?

Answer Source

You're using the inode number as the index bytesArray. You don't show how big this array is, but I'm betting it's much smaller than 100663302. So you're writing past the end of the array. This invokes undefined behavior.

Rather than using the inode number as an index, use a struct which contains both the inode number and the file size, and use an array of those along with a count of the element in the array.

struct entry {
    int inode;
    int nbytes;
};

struct entry entryArray[10];   // assuming there are no more than 10 lines in the file
int arrayLen = 0;

...

while(fgets(line, sizeof(line), myfile)) {
    int x = (sscanf(line, "%s %ld %*s %*d %*s %*d %*[bytes] %d %*[^\n]", inodeText, &inode, &mybytes));
    if(x > 1) {
        entryArray[arrayLen].inode = inode;
        entryArray[arrayLen].nbytes = mybytes;
        arrayLen++;
    }
}
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download