0

Please can someone explain why I get a segmentation fault?

The code below works for check50 but ideally I'd like to use the function write_header to write the first file.

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

typedef uint8_t BYTE;

const int BLOCK = 512;
void write_header(FILE *infile, char *file_name, int *file_count, BYTE *buffer);

int main(int argc, char *argv[])
{
    //only proceed if correct number of command line arguments
    if (argc != 2)
    {
        printf("Usage: ./recover file.raw\n");
        return 1;
    }

    //open memory card and check not null
    FILE *pinput = fopen(argv[1], "r");
    if (pinput == NULL)
    {
        printf("Could not open file.\n");
        return 2;
    }

    //create buffer of 512 bytes
    BYTE buffer[BLOCK];

    int file_count = 0;

    //8 byte array of characters for 000.jpg\0

    char *filename = malloc(sizeof(char) * 8);

    FILE *poutput = NULL;

    while (fread(buffer, BLOCK, 1, pinput))
    {
        if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && (buffer[3] & 0xf0) == 0xe0)
        {
            //if 1st jpeg (only difference is not to close a file)
            if (file_count == 0)
            {
                sprintf(filename, "%03i.jpg", file_count);
                poutput = fopen(filename, "w");
                fwrite(buffer, BLOCK, 1, poutput);
                file_count++;
            }
            else
            {
                fclose(poutput);
                write_header(poutput, filename, &file_count, buffer);
            }

        }
        //dont do this if 1st one
        else if (file_count > 0)
        {
            fwrite(buffer, BLOCK, 1, poutput);
        }

    }
    //close remaining files and free up malloc
    free(filename);
    fclose(pinput);
    fclose(poutput);

    return 0;
}

void write_header(FILE *infile, char *file_name, int *file_count, BYTE *buffer)
{
    sprintf(file_name, "%03i.jpg", *file_count);
    infile = fopen(file_name, "w");
    fwrite(buffer, BLOCK, 1, infile);
    *file_count = *file_count + 1;
}

If I replace this:

while (fread(buffer, BLOCK, 1, pinput))
    {
        if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && (buffer[3] & 0xf0) == 0xe0)
        {
            //if 1st jpeg (only difference is not to close a file)
            if (file_count == 0)
            {
                sprintf(filename, "%03i.jpg", file_count);
                poutput = fopen(filename, "w");
                fwrite(buffer, BLOCK, 1, poutput);
                file_count++;
            }
            else
            {
                fclose(poutput);
                write_header(poutput, filename, &file_count, buffer);
            }

        }
        //dont do this if 1st one
        else if (file_count > 0)
        {
            fwrite(buffer, BLOCK, 1, poutput);
        }

    }

with this:

while (fread(buffer, BLOCK, 1, pinput))
    {
        if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && (buffer[3] & 0xf0) == 0xe0)
        {
            //if 1st jpeg (only difference is not to close a file)
            if (file_count == 0)
            {
                write_header(poutput, filename, &file_count, buffer);
            }
            else
            {
                fclose(poutput);
                write_header(poutput, filename, &file_count, buffer);
            }

        }
        //dont do this if 1st one
        else if (file_count > 0)
        {
            fwrite(buffer, BLOCK, 1, poutput);
        }

    }

I get a segmentation fault and can't work out why. Please help!

Using debug50 it seems that the fault occurs on this line for would-be file 000.jpg:

        else if (file_count > 0)
        {
            fwrite(buffer, BLOCK, 1, poutput);
        }

Thanks in advance!

1 Answer 1

1

The write_header function is partially working. It is creating the file, but that's where it stops working. It's failing to write the buffer to the file. That means that there's an issue accessing the data in the buffer. Maybe you should look for an issue with the passing of the buffer to the function.

Next, the segfault. Once the signature block is processed, the subsequent blocks need to be written to the output file by the else if code. Unfortunately, the output file is opened in the write_header function. That means that the file pointer only exists in that function and not in main, and as soon as the code exits the function, the output file pointer ceases to exist. (Remember, the pointer in the function is not the same pointer var in main.) It might exist in main (hint) if the function returned a file pointer.

This should give you enough to make it work. ;-)

If this answers your question, please click on the check mark to accept. Let's keep up on forum maintenance. ;-)

3
  • Thanks Cliff, all working now! Can I ask why the write_header function appeared to work for 001.jpg onwards? In that scenario the output file had been opened in main but closed as soon as the start of the second file was found, then the writing of the jpegs was delegated to write_header again. I don't see how this managed to avoid the seg fault, but it did seem to
    – Tim Swinn
    Commented Feb 22, 2021 at 9:03
  • It's not getting to the 2nd file. It's seg faulting on the 2nd block of the first file. The file pointer poutput for the open file is NULL in main, so, when the code tries to write to a nonexistent pointer, the write fails. (The poutput pointer in the write_header() function is not the same pointer. It's loaded with the output file info but only exists in the function.) Also, note the file size of 000.jpg is 0 bytes. That means that, although the file is created, nothing is written to it. If the first block containing the signature were being written, it would be 512 bytes.
    – Cliff B
    Commented Feb 22, 2021 at 10:33
  • Thanks- great explanation
    – Tim Swinn
    Commented Feb 22, 2021 at 16:38

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .