Почему Valgrind жалуется на fgets? - PullRequest
3 голосов
/ 25 марта 2020

У меня есть простой C код.

main. c

int main() {
    FILE *stream = fopen("../input.txt", "r");
    cube test_cube;
    cube_initialization(&test_cube, stream);

/* and some code with free memory which is not needed to understand the situation */

}

cube. c

/* just the function valgrind complains about */

void cube_initialization(cube *cube, FILE *input_file) {
    int side_length;
    char buffer[BUF_SIZE];
    char waste_buffer[BUF_SIZE];


    fgets(buffer, BUF_SIZE, input_file);
    fgets(waste_buffer, BUF_SIZE, input_file); /* empty line */
    side_length = (int) strtol(buffer, NULL, 10);
    cube->side_length = side_length;
    cube->cube_array = malloc(side_length * sizeof(int **));
    int z;
    for (z = 0; z < side_length; z++) {
        cube->cube_array[z] = malloc(side_length * sizeof(int *));
        int y;
        for (y = 0; y < side_length; y++) {
            cube->cube_array[z][y] = malloc(side_length * sizeof(int));
        }
    }
}

и вывод valgrind

==8251== Invalid read of size 4
==8251==    at 0x48F3727: fgets (iofgets.c:47)
==8251==    by 0x1093C2: cube_initialization (cube.c:11)
==8251==    by 0x10928D: main (main.c:11)
==8251==  Address 0x0 is not stack'd, malloc'd or (recently) free'd
==8251== 
==8251== 
==8251== Process terminating with default action of signal 11 (SIGSEGV)
==8251==  Access not within mapped region at address 0x0
==8251==    at 0x48F3727: fgets (iofgets.c:47)
==8251==    by 0x1093C2: cube_initialization (cube.c:11)
==8251==    by 0x10928D: main (main.c:11)
==8251==  If you believe this happened as a result of a stack
==8251==  overflow in your program's main thread (unlikely but
==8251==  possible), you can try to increase the size of the
==8251==  main thread stack using the --main-stacksize= flag.
==8251==  The main thread stack size used in this run was 8388608.
==8251== 
==8251== HEAP SUMMARY:
==8251==     in use at exit: 0 bytes in 0 blocks
==8251==   total heap usage: 1 allocs, 1 frees, 488 bytes allocated
==8251== 
==8251== All heap blocks were freed -- no leaks are possible
==8251== 
==8251== For lists of detected and suppressed errors, rerun with: -s
==8251== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
Segmentation fault (core dumped)

Я не понимаю, почему Valgrind жалуется на fgets(). Я читаю данные из файла и использую fgets с указателем на большой буфер (256), но он нужен мне только для чтения коротких строк размером 1-6 символов (мне нужен fgets, потому что он останавливается, когда находит '\ n' в конце линия). Возможно, проблема в том, что fgets () пытается прочитать строку из 256 символов и останавливается после 1-5 и '\ n'?

Ответы [ 2 ]

3 голосов
/ 25 марта 2020

Valgrind жалуется на неправильное чтение в fgets(). Маловероятно, что проблема заключается в размере массива назначения, который может вызвать недопустимую запись, но на самом деле это массив из BUF_SIZE байтов, который, по вашему мнению, имеет разумное значение 256. Проблема более вероятна с указателем потока , который может быть нулевым, как сообщает Valgrind:

Address 0x0 is not stack'd, malloc'd or (recently) free'd`

Вы должны исправить потенциально неопределенное поведение в вашем коде:

  • проверьте, вернул ли fopen() верный FILE*, чтобы избежать неопределенного поведения при попытке чтения из input_file.
  • , убедитесь, что fgets() успешно (не возвращает NULL), чтобы избежать неопределенного поведения при чтении из целевого массива.
3 голосов
/ 25 марта 2020

Valgrind жалуется на неправильный адрес 0x0 доступ:

Адрес 0x0 не в стеке, mallo c 'd или (недавно) free'd

В вашем fgets() вызове

fgets(buffer, BUF_SIZE, input_file);

buffer параметр в порядке, потому что он расположен в стеке. Единственным ответственным может быть параметр input_file, исходя из main(). Этот параметр является потоком, полученным из вызова fopen(). Вы не проверяли его до перехода к cube_initialization()!

Проверьте его, а затем поймете, почему он возвращает NULL (возможно, вы пытаетесь открыть путь, который не существует).

int main() {
    FILE *stream = fopen("../input.txt", "r");
    cube test_cube;
    if( stream != NULL )
    {
        cube_initialization(&test_cube, stream);

        /* Continue execution*/
    }
}
...