Восстановление CS50 — почему я продолжаю получать ошибку сегментации?

#c #segmentation-fault #cs50 #recover

#c #ошибка сегментации #cs50 #восстановить

Вопрос:

Я полный новичок в программировании, и я действительно не могу понять, где я ошибся. Я просмотрел код других людей и изменил множество вещей, но ничего не сработало : / Любая помощь была бы оценена!

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

int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        printf("Usage ./recover imagen");
        return 1;
    }

    FILE *card = fopen(argv[1], "r");

    if (card == NULL)
    {
        printf("ERRORn");
        return 1;
    }

    int jpeg_num = 0;
    typedef uint8_t BYTE;
    BYTE buffer[512];
    char filename[10];
    FILE *image = NULL;

    while (fread(buffer, sizeof(BYTE), 1, card) == 1)
    {
        if (buffer[0] == 0xff amp;amp; buffer[1] == 0xd0 amp;amp; buffer[2] == 0xff amp;amp; (buffer[3] amp; 0xf0) == 0xe0)
        {

            if (jpeg_num > 0)
            {
                fclose(image);
            }

            sprintf(filename, "i.jpeg", jpeg_num);
            image = fopen(filename, "w");
            fwrite(buffer, sizeof(BYTE), 1, image);
            jpeg_num  ;
        }

        else
        {
            fwrite(buffer, sizeof(BYTE), 1, image);
        }
    }

    fclose(image);
    fclose(card);
    return 0;
}
  

Комментарии:

1. Если вы запускаете свой код через отладчик, он должен остановить вас на точной строке, где произошел сбой в сегментации (это может быть не та строка, в которой находится ваша ошибка, но если вы проверите значения определенных переменных в этот момент, вы сможете определить это из контекста.)

2. fread(buffer, sizeof(BYTE), 1, card) считывается только один байт , но вы просматриваете другие байты в буфере. Всегда записывайте возвращаемое значение из fread , чтобы вы знали, сколько нужно записать.

3. fwrite(buffer, sizeof(BYTE), 1, image); в предложении else может / будет срабатывать против NULL указателя на файл изображения в этом коде. Если предложение if не выполнено хотя бы один раз, image будет равно null, и этот код вызывает неопределенное поведение.

Ответ №1:

CS50 заставляет программы компилироваться с использованием средства очистки адресов ( -fsanitize=address ), верно? Если это так, вы должны были получить что-то вроде следующего:

 ASAN:DEADLYSIGNAL
=================================================================
==4179==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000 (pc 0x7f280eabf92e bp 0x000000000001 sp 0x7fffc6e02bd0 T0)
==4179==The signal is caused by a READ memory access.
==4179==Hint: address points to the zero page.
    #0 0x7f280eabf92d in _IO_fwrite (/lib/x86_64-linux-gnu/libc.so.6 0x7f92d)
    #1 0x7f281020107f in main /.../a.c:45
    #2 0x7f280ea61b96 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6 0x21b96)
    #3 0x7f2810200c79 in _start (/.../a 0xc79)

AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV (/lib/x86_64-linux-gnu/libc.so.6 0x7f92d) in _IO_fwrite
==4179==ABORTING
  

(Это из, gcc а не clang , но clang средство очистки адресов должно выдавать нечто подобное.)

Итак, вы попытались прочитать с нулевого адреса. Это может быть NULL или инициализированный указатель. Мы даже знали, что это произошло при вызове fwrite в строке 45!

Передаются два указателя на fwrite , buffer и image . buffer это автоматически выделяемый массив, поэтому он является допустимым указателем. image с другой стороны, инициализируется следующим образом:

 FILE *image = NULL;
  

Возможно ли, что он никогда не менялся до достижения неудачного вызова fwrite ? ДА. Это плохо.

Комментарии:

1. Спасибо за вашу помощь! Я понимаю, в чем проблема, но где / как мне изменить ее перед fwrite? Извините, я просто не могу понять, что мне нужно добавить :/