Fopen() в c: ошибка сегментации

Я пытаюсь обернуть функции библиотеки C malloc и бесплатно определить, есть ли утечка памяти в моем коде. Я расширяю функции malloc/free, добавляя к ним fprintf для записи в файл адреса malloc/free и размера.

Компиляция этого кода с помощью gcc или clang приводит к ошибке сегментации в строке fopen(). Вот команда:

gcc -o mainapp main.c -Wall -Wextra

Я поместил fopen внутри функции malloc и free, но также получил ту же проблему: ошибка сегментации (сброс ядра)

Не могу найти объяснение проблеме.

Вот мой полный код:

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#define __USE_GNU
#include <dlfcn.h>

#define TEST_MEM_LEAK 1 // a value of 1 means to join the memory leak detection, and a value of 0 means not to join

#if TEST_MEM_LEAK

typedef void *(*malloc_t)(size_t size);
malloc_t malloc_f = NULL;

typedef void (*free_t)(void *p);
free_t free_f = NULL;

int malloc_flag = 1;    // It is used to prevent repeated recursion and cannot exit because the printf function will call malloc for memory allocation
int free_flag = 1;
const char* logFileName = "/home/hammamiw/Documents/HeapMonitor/allocs.log";
FILE* fp = NULL;

void initCheck()
{
    fp = fopen("/home/hammamiw/Documents/HeapMonitor/allocs.log", "w");
}

void *malloc(size_t size)
{
    if(malloc_flag) { 
        initCheck();  
        malloc_flag = 0;  // Used to prevent printf from causing an error when calling malloc recursively
        void *p = malloc_f(size);
        fprintf(fp, "malloc, %lx, %lu\n", (uintptr_t)p, size);
        //printf("m\n");
        malloc_flag = 1;  // It is used to ensure that the initial value of flag flag is consistent when malloc in this file is called again
        return p;
    } 
    else {
        return malloc_f(size);  // Here, the malloc function in the system library obtained by dlsym is called
    }   
}

void free(void *p) 
{
    initCheck();
    if(free_flag) {
        //initCheck();  
        free_flag = 0;
        fprintf(fp, "F, %lx\n", (uintptr_t)p);
        //printf("f\n");
        free_f(p);
       free_flag = 1;
    } else {
        free_f(p);
    }
}
#endif

int main()
{
#if TEST_MEM_LEAK // the part from if to endif can be divided into function calls
    malloc_f = dlsym(RTLD_NEXT, "malloc");
    if(!malloc_f) {
        printf("load malloc failed: %s\n", dlerror());
        return 1;
    }
    free_f = dlsym(RTLD_NEXT, "free");
    if(!free_f) {
        printf("load free failed: %s\n", dlerror());
        return 1;
    }
#endif
    void *p1 = malloc(10);  //The malloc function in this article will be called first
    void *p2 = malloc(20);
    
    //Here, p2 is not released and there is a memory leak. Judge by checking whether the number of malloc and free times printed is the same
    free(p2);
    free(p1);
    return 0;
}

ПРИМЕЧАНИЕ: код работает хорошо, если я использую printf вместо fprintf -> печатает «f» и «m» при каждом вызове free и malloc.

Среда: Ubuntu 22.04, язык C, версия компилятора GCC 11.3.0

почему это помечено clang?

Marcus Müller 19.11.2022 11:55

что говорит твой отладчик?

Marcus Müller 19.11.2022 11:55
fopen() выделит память, возможно, вместе с malloc(). Это вызовет рекурсию с переполнением стека.
ensc 19.11.2022 11:59

@MarcusMüller Я удалил тег clang. Я оставил только c, malloc и linux. для отладки он останавливается на fopen и показывает «ошибку сегментации»

Wassim Hammami 19.11.2022 12:05

@ensc да, похоже, это причина проблемы. Что вы предлагаете в качестве решения

Wassim Hammami 19.11.2022 12:06

Одна вещь, с которой нужно быть осторожным - используя одиночные глобальные флаги, ваш код не является потокобезопасным. Если бы несколько потоков вызывали malloc() или free() одновременно, значения глобального флага могли бы быть неправильными в представлении из любого одного потока. Вы можете заменить fprintf() на write(), и вам не понадобятся флаги, но это усложнит сбор данных. Вам придется либо написать что-то вроде двоичных данных фиксированного размера и выполнить их постобработку, либо вам придется преобразовать данные в строки, не используя ничего, что вызывало бы malloc().

Andrew Henle 19.11.2022 13:24

Прежде чем изобретать велосипед, почитайте о valgrind или mtrace

Lorinczy Zsigmond 21.11.2022 12:29

Спасибо за вашу помощь. Проблема исправлена ​​(по предложению @ensc и Джона Цвинка)

Wassim Hammami 29.11.2022 15:02
Шаблоны Angular PrimeNg
Шаблоны Angular PrimeNg
Как привнести проверку типов в наши шаблоны Angular, использующие компоненты библиотеки PrimeNg, и настроить их отображение с помощью встроенной...
Создайте ползком, похожим на звездные войны, с помощью CSS и Javascript
Создайте ползком, похожим на звездные войны, с помощью CSS и Javascript
Если вы веб-разработчик (или хотите им стать), то вы наверняка гик и вам нравятся "Звездные войны". А как бы вы хотели, чтобы фоном для вашего...
Документирование API с помощью Swagger на Springboot
Документирование API с помощью Swagger на Springboot
В предыдущей статье мы уже узнали, как создать Rest API с помощью Springboot и MySql .
Начала с розового дизайна
Начала с розового дизайна
Pink Design - это система дизайна Appwrite с открытым исходным кодом для создания последовательных и многократно используемых пользовательских...
Шлюз в PHP
Шлюз в PHP
API-шлюз (AG) - это сервер, который действует как единая точка входа для набора микросервисов.
14 Задание: Типы данных и структуры данных Python для DevOps
14 Задание: Типы данных и структуры данных Python для DevOps
проверить тип данных используемой переменной, мы можем просто написать: your_variable=100
0
8
61
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Перед вызовом malloc_flag необходимо установить fopen(). Тогда вы защититесь от рекурсии не только через fprintf(), но и через fopen().

Да, установив 'malloc_flag' в 0 перед вызовом 'fopen()' в 'initCheck()', а затем вернувшись к 1.

Wassim Hammami 29.11.2022 15:00

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