Ошибка сегментации (сброс ядра) при чтении двоичного файла, memmove-vec-unaligned-erms.S: Нет такого файла или каталога

Я пытаюсь отладить фрагмент кода, который читает созданные мной двоичные файлы. Кажется, что когда количество считываемых элементов превышает определенный порог, написанный мной сценарий дает сбой.

Файл содержит следующую структуру: для каждого времени t он имеет время t, затем структуру N частиц (каждая из которых содержит некоторую информацию об этой частице, положении, скорости и т. д., вероятно, не имеет значения).

Файл создается с помощью

int update_binary_file(const char *name, particle *P, parameters par, double *time)
{

    FILE *file;
    file = fopen(name, "a+");

    if (!file)
    {
        return 1;
    }

    fwrite(time, sizeof(double), 1, file);
    fwrite(P, sizeof(particle), par.N, file);
    fclose(file);
    return 0;
}

Где частица — это структура, определенная следующим образом:

typedef struct
{
    double x, y, z;    // position
    double vx, vy, vz; // velocity
    double wx, wy, wz; // acceleration
    int next_inbox;

} particle;

Параметры — это еще одна структура, но она здесь не имеет значения. Я использую ее только для передачи значения par.N (количества частиц в системе).

Наконец я прочитал файл следующим образом:

void read_binaryfile(parameters par, char *filename, double *x, double *y, double *z, double *vx, double *vy, double *vz, double *wx, double *wy, double *wz, double *t)
{
    int dump;
    
    FILE *file;
    file = fopen(filename, "rb");
    if (!file)
    {
        printf("ERROR: invalid file %s\n", filename);
        return;
    }
    else
    {   
        for (int line = 0; line < par.Nsnap; line++)
        {
            if (fread(&t[line], 1, sizeof(double), file) != sizeof(double))
                break;
            printf("%f\n", t[line]);
            for(int n = 0; n < par.N; n++){
                int lin_index = linear_index(n, line);
                if (fread(&x[lin_index], 1, sizeof(double), file) != sizeof(double)){
                    printf("ERROR reading file!\n");
                    break;
                }
                if (fread(&y[lin_index], 1, sizeof(double), file) != sizeof(double))
                {
                    printf("ERROR reading file!\n");
                    break;
                }
                if (fread(&z[lin_index], 1, sizeof(double), file) != sizeof(double))
                {
                    printf("ERROR reading file!\n");
                    break;
                }
                if (fread(&vx[lin_index], 1, sizeof(double), file) != sizeof(double))
                {
                    printf("ERROR reading file!\n");
                    break;
                }
                if (fread(&vy[lin_index], 1, sizeof(double), file) != sizeof(double))
                {
                    printf("ERROR reading file!\n");
                    break;
                }
                if (fread(&vz[lin_index], 1, sizeof(double), file) != sizeof(double))
                {
                    printf("ERROR reading file!\n");
                    break;
                }
                if (fread(&wx[lin_index], 1, sizeof(double), file) != sizeof(double))
                {
                    printf("ERROR reading file!\n");
                    break;
                }
                if (fread(&wy[lin_index], 1, sizeof(double), file) != sizeof(double))
                {
                    printf("ERROR reading file!\n");
                    break;
                }
                if (fread(&wz[lin_index], 1, sizeof(double), file) != sizeof(double))
                {
                    printf("ERROR reading file!\n");
                    break;
                }
                if (fread(&dump, 1, sizeof(int), file) != sizeof(int))
                {
                    printf("ERROR reading file!\n");
                    break;
                }
                if (fread(&dump, 1, sizeof(int), file) != sizeof(int))
                {
                    printf("ERROR reading file!\n");
                    break;
                }
            }
 
        }
    }

    fclose(file);
}

По сути, он считывает все значения структуры частиц одно за другим, вместо чтения самой структуры (потому что это более практично). Скрипт хорошо работает с небольшими файлами, и я могу читать их с помощью Python. Когда общее количество элементов в файле больше, я получаю ошибку сегментации. Более конкретно в GDB:

Program received signal SIGSEGV, Segmentation fault.
__memmove_avx_unaligned_erms () at ../sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S:418
418 ../sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S: No such file or directory.
(gdb) where
#0  __memmove_avx_unaligned_erms () at ../sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S:418
#1  0x00007ffff788b423 in __GI__IO_file_xsgetn (fp=0x55555556cea0, data=<optimized out>, n=8) at ./libio/fileops.c:1295
#2  0x00007ffff787fba9 in __GI__IO_fread (buf=0x7ffdf7ad6af8, size=1, count=8, fp=0x55555556cea0) at ./libio/iofread.c:38
#3  0x00005555555559ae in read_binaryfile (par=..., 
    filename=0x7fffffffe127 "snap/m0.68_J18.00_g80.00_n1.00_T7.60_r1.00_v2.00/rho4.0_L4_N256_dt0.010_correlations_ICrand_dtsave0.05_t10.00.bin", x=0x7ffff7e37010, y=0x7ffff7b9d010, z=0x7ffff7b3a010, vx=0x7ffff7ad7010, vy=0x7ffff7a74010, 
    vz=0x7ffff779d010, wx=0x7ffff773a010, wy=0x7ffff76d7010, wz=0x7ffff7674010, t=0x55555556beb0)
    at spacetime_correlations.c:151
#4  0x000055555555602a in main (argc=2, argv=0x7fffffffdd28) at spacetime_correlations.c:226

Все массивы x,y,z,vx,vy,vz,wx,wy,wz определяются как:

    double *x = (double *)calloc(par.N * par.Nsnap, sizeof(double));

и мне кажется, что я никогда не превышаю их максимальную размерность, присваивая им значения, считанные из файла с помощью fread(&vz[lin_index] и т. д...).

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

ОБНОВЛЕНИЕ 1. Минимальный код для создания выходного файла с именем N100.bin.

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


typedef struct
{
    double x, y, z;    // position
    double vx, vy, vz; // velocity
    double wx, wy, wz; // acceleration
    int next_inbox;

} particle;


int update_binary_file(const char *name, particle *P, int N, double *time)
{

    FILE *file;
    file = fopen(name, "a+");

    if (!file)
    {
        return 1;
    }

    fwrite(time, sizeof(double), 1, file);
    fwrite(P, sizeof(particle), N, file);
    fclose(file);
    return 0;
}


int main(int argc, char *argv[])
{

    int N = 100;
    particle *P = (particle *)calloc(N, sizeof(particle));
    int Nsteps = 1000;

    for (int i = 0; i < N; i++)
    {
        P[i].x = 1;
        P[i].y = 1;
        P[i].z = 1;
        P[i].vx = 1;
        P[i].vy = 1;
        P[i].vz = 1;
        P[i].wx = 1;
        P[i].wy = 1;
        P[i].wz = 1;
        P[i].next_inbox = 1;
    }
    double time;

    for (int i = 0; i < Nsteps; i++)
    {
        time = i*0.1;
        update_binary_file("N100.bin", P, N, &time);
    }
    
    
}   

Минимальный код для чтения созданного файла N100.bin.

// gcc spacetime_correlations.c -o spacetime_correlations -lm -O3

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

#define linear_index(n, t) ((n) + (t) * par.N )

    typedef struct
{
    int N, Nsnap, L;
} parameters;

typedef struct
{
    double x, y, z;    // position
    double vx, vy, vz; // velocity
    double wx, wy, wz; // acceleration
    int next_inbox;

} particle;


void read_binaryfile(parameters par, char *filename, double *x, double *y, double *z, double *vx, double *vy, double *vz, double *wx, double *wy, double *wz, double *t)
{
    int dump;
    
    FILE *file;
    file = fopen(filename, "rb");
    if (!file)
    {
        printf("ERROR: invalid file %s\n", filename);
        return;
    }
    else
    {   
        for (int line = 0; line < par.Nsnap; line++)
        {
            if (fread(&t[line], 1, sizeof(double), file) != sizeof(double))
                break;
            printf("%f\n", t[line]);
            for(int n = 0; n < par.N; n++){
                int lin_index = linear_index(n, line);
                if (fread(&x[lin_index], 1, sizeof(double), file) != sizeof(double)){
                    printf("ERROR reading file!\n");
                    break;
                }
                if (fread(&y[lin_index], 1, sizeof(double), file) != sizeof(double))
                {
                    printf("ERROR reading file!\n");
                    break;
                }
                if (fread(&z[lin_index], 1, sizeof(double), file) != sizeof(double))
                {
                    printf("ERROR reading file!\n");
                    break;
                }
                if (fread(&vx[lin_index], 1, sizeof(double), file) != sizeof(double))
                {
                    printf("ERROR reading file!\n");
                    break;
                }
                if (fread(&vy[lin_index], 1, sizeof(double), file) != sizeof(double))
                {
                    printf("ERROR reading file!\n");
                    break;
                }
                if (fread(&vz[lin_index], 1, sizeof(double), file) != sizeof(double))
                {
                    printf("ERROR reading file!\n");
                    break;
                }
                if (fread(&wx[lin_index], 1, sizeof(double), file) != sizeof(double))
                {
                    printf("ERROR reading file!\n");
                    break;
                }
                if (fread(&wy[lin_index], 1, sizeof(double), file) != sizeof(double))
                {
                    printf("ERROR reading file!\n");
                    break;
                }
                if (fread(&wz[lin_index], 1, sizeof(double), file) != sizeof(double))
                {
                    printf("ERROR reading file!\n");
                    break;
                }
                if (fread(&dump, 1, sizeof(int), file) != sizeof(int))
                {
                    printf("ERROR reading file!\n");
                    break;
                }
                if (fread(&dump, 1, sizeof(int), file) != sizeof(int))
                {
                    printf("ERROR reading file!\n");
                    break;
                }
            }
 
        }
    }

    fclose(file);
}

int main(int argc, char **argv){

    // Provide filename from command line
    char *filename = argv[1], *dump;

    parameters par;

    double *time = (double *)calloc(par.Nsnap, sizeof(double));
    double *C_t = (double *)calloc(par.Nsnap, sizeof(double));
    double *Vx = (double *)calloc(par.Nsnap, sizeof(double));
    double *Vy = (double *)calloc(par.Nsnap, sizeof(double));
    double *Vz = (double *)calloc(par.Nsnap, sizeof(double));
    double *x = (double *)calloc(par.N * par.Nsnap, sizeof(double));
    double *y = (double *)calloc(par.N * par.Nsnap, sizeof(double));
    double *z = (double *)calloc(par.N * par.Nsnap, sizeof(double));
    double *vx = (double *)calloc(par.N * par.Nsnap, sizeof(double));
    double *vy = (double *)calloc(par.N * par.Nsnap, sizeof(double));
    double *vz = (double *)calloc(par.N * par.Nsnap, sizeof(double));
    double *wx = (double *)calloc(par.N * par.Nsnap, sizeof(double));
    double *wy = (double *)calloc(par.N * par.Nsnap, sizeof(double));
    double *wz = (double *)calloc(par.N * par.Nsnap, sizeof(double));
    double *delta_vx = (double *)calloc(par.N * par.Nsnap, sizeof(double));
    double *delta_vy = (double *)calloc(par.N * par.Nsnap, sizeof(double));
    double *delta_vz = (double *)calloc(par.N * par.Nsnap, sizeof(double));
 

    // Count number of "lines" (e.g. the number of particles arrays at different time)
    int count = 0;
    FILE *file;
    file = fopen(filename, "rb");
    while(fgetc(file) != EOF)
    {
        count++;
    }
    fclose(file);

    // Get number of particles from file name
    sscanf(filename,"N%d", &par.N);
    par.Nsnap = count/(sizeof(particle)*par.N+sizeof(double));

    printf("%d\n", par.N);

    read_binaryfile(par, filename, x, y, z, vx, vy, vz, wx, wy, wz, time);

    free(time);
    free(C_t);
    free(Vx);
    free(Vy);
    free(Vz);
    free(x);
    free(y);
    free(z);
    free(vx);
    free(vy);
    free(vz);
    free(wx);
    free(wy);
    free(wz);
    free(delta_vx);
    free(delta_vy);
    free(delta_vz);

    return 1;
}

Обратите внимание: если я изменю Nsteps в первом скрипте на меньшее значение, то при использовании второго скрипта у меня не будет ошибки сегментации.

Отредактируйте вопрос, чтобы предоставить минимально воспроизводимый пример.

Eric Postpischil 13.06.2024 17:08

Параметры все время инициализируются одинаково? Всегда ли par.N и par.Nsnap одинаковы при записи и чтении файла? Когда вы предоставляете MRE, запрошенный Эриком Постпишилом, пожалуйста, также включите некоторые тестовые данные, которые вы используете для создания файла.

Gerhardh 13.06.2024 17:18

да, пар.Н один и тот же и известен. par.Nsnap — это просто количество «строк» ​​двоичного файла. Как мне добавить файлы к вопросу?

TalJo 13.06.2024 17:22

Вы можете добавить пример кода, который использует update_binary_file для создания файла.

Gerhardh 13.06.2024 17:23

Как узнать, сколько «строк» ​​хранится в файле до его открытия? Почему вы используете структуру при записи файла, но отдельные значения для чтения? При написании структуры могут присутствовать некоторые байты заполнения, о которых нужно будет позаботиться при чтении отдельных значений.

Gerhardh 13.06.2024 17:29

@Gerhardh Думаю, именно поэтому в конце есть два вызова fread размера sizeof(int). Последний будет для заполнения. Но это все довольно непереносимо.

Ian Abbott 13.06.2024 17:40

@IanAbbott Ты прав. Это могло бы исправить ситуацию, но, как вы упомянули, портативность вышла из-под контроля...

Gerhardh 13.06.2024 17:49

Да, это действительно не очень умно. Было бы лучше читать как структуру (я собирался изменить ее на следующем этапе отладки). В любом случае, я не думаю, что это проблема. Про переносимость я всегда писал только для себя, поэтому мне никогда не приходилось об этом думать; Извини за это!

TalJo 13.06.2024 17:58

В «spacetime_correlations.c» main(), par не инициализируется перед использованием, что приводит к UB.

Ian Abbott 13.06.2024 18:55

Вы должны выделить эти буферы после заполнения par, чтобы par.N и par.Nsnap были допустимы в вычислениях для установки размера буферов. Я не знаю, есть ли в вашем реальном коде та же проблема, что и в этом минимально воспроизводимом примере.

Ian Abbott 13.06.2024 19:02

Разве ваш компилятор не выдал никаких предупреждений об использовании неинициализированной переменной par? Если нет, вам необходимо повысить уровень предупреждения. Для gcc используйте -Wall -Wextra -pedantic.

Gerhardh 13.06.2024 20:44

@Gerhardh Действительно, мой компилятор не жаловался... Спасибо за ценное предложение! Будет следовать :)

TalJo 13.06.2024 21:32
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
12
63
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Размеры буфера зависят от неинициализированной переменной, что приводит к неопределенному поведению.

    parameters par;

    double *time = (double *)calloc(par.Nsnap, sizeof(double));
    double *C_t = (double *)calloc(par.Nsnap, sizeof(double));
    double *Vx = (double *)calloc(par.Nsnap, sizeof(double));
    double *Vy = (double *)calloc(par.Nsnap, sizeof(double));
    double *Vz = (double *)calloc(par.Nsnap, sizeof(double));
    double *x = (double *)calloc(par.N * par.Nsnap, sizeof(double));
    double *y = (double *)calloc(par.N * par.Nsnap, sizeof(double));
    double *z = (double *)calloc(par.N * par.Nsnap, sizeof(double));
    double *vx = (double *)calloc(par.N * par.Nsnap, sizeof(double));
    double *vy = (double *)calloc(par.N * par.Nsnap, sizeof(double));
    double *vz = (double *)calloc(par.N * par.Nsnap, sizeof(double));
    double *wx = (double *)calloc(par.N * par.Nsnap, sizeof(double));
    double *wy = (double *)calloc(par.N * par.Nsnap, sizeof(double));
    double *wz = (double *)calloc(par.N * par.Nsnap, sizeof(double));
    double *delta_vx = (double *)calloc(par.N * par.Nsnap, sizeof(double));
    double *delta_vy = (double *)calloc(par.N * par.Nsnap, sizeof(double));
    double *delta_vz = (double *)calloc(par.N * par.Nsnap, sizeof(double));

Переместите эти выделения буфера в точку, где par.N и par.Nsnap действительны:

    // Get number of particles from file name
    sscanf(filename,"N%d", &par.N);
    par.Nsnap = count/(sizeof(particle)*par.N+sizeof(double));

    printf("%d\n", par.N);

    double *time = (double *)calloc(par.Nsnap, sizeof(double));
    double *C_t = (double *)calloc(par.Nsnap, sizeof(double));
    double *Vx = (double *)calloc(par.Nsnap, sizeof(double));
    double *Vy = (double *)calloc(par.Nsnap, sizeof(double));
    double *Vz = (double *)calloc(par.Nsnap, sizeof(double));
    double *x = (double *)calloc(par.N * par.Nsnap, sizeof(double));
    double *y = (double *)calloc(par.N * par.Nsnap, sizeof(double));
    double *z = (double *)calloc(par.N * par.Nsnap, sizeof(double));
    double *vx = (double *)calloc(par.N * par.Nsnap, sizeof(double));
    double *vy = (double *)calloc(par.N * par.Nsnap, sizeof(double));
    double *vz = (double *)calloc(par.N * par.Nsnap, sizeof(double));
    double *wx = (double *)calloc(par.N * par.Nsnap, sizeof(double));
    double *wy = (double *)calloc(par.N * par.Nsnap, sizeof(double));
    double *wz = (double *)calloc(par.N * par.Nsnap, sizeof(double));
    double *delta_vx = (double *)calloc(par.N * par.Nsnap, sizeof(double));
    double *delta_vy = (double *)calloc(par.N * par.Nsnap, sizeof(double));
    double *delta_vz = (double *)calloc(par.N * par.Nsnap, sizeof(double));

    read_binaryfile(par, filename, x, y, z, vx, vy, vz, wx, wy, wz, time);

О боже, такая глупая ошибка! Не могу поверить, что не заметил этого :( В любом случае спасибо, а также спасибо @Gerhardh, я введу более строгий уровень предупреждений!

TalJo 13.06.2024 21:33

Другие вопросы по теме

Утечка памяти Haskell, работающая с зонированным временем и добавляющая/вычитающая секунды
Утечка памяти с использованием статического члена unique_ptr
Утечка памяти, которую не устраняет GC в отношении .Net Entity Framework версии 8 (консольное приложение C# .Net8.02)
ASAN показывает утечку памяти через конфигурацию отладки CMAKE, но не показывает утечку памяти через конфигурацию выпуска CMAKE. Почему?
Каковы возможные объекты GDI, которые могут быть обнаружены, но не перечислены как известные типы объектов GDI?
Кадр сопрограммы автоматически уничтожается и освобождается (т.е. освобождается выделенный кадр?) после co_return?
Как исправить IntersectionObserver, вызывающий утечку памяти в моем веб-приложении OpenLayers?
Деструктор связанного списка Object Pascal оставляет один блок несвободным
Np.load() занимает слишком много памяти
C. Как освободить двойной указатель void, которому назначен массив динамических структур с помощью malloc