C 프로그램에서 메모리 누수를 감지하는 간단한 프로그램
때때로 우리는 메모리 누수를 남기는 프로그램을 작성하는데, 그 결과 일정 시간이 지나면 프로그램이 충돌하고 메모리 누수가 어디에 남아 있는지 찾기가 매우 어렵습니다.
따라서 이러한 문제를 디버깅하기 위해 프로그램에서 메모리 누수를 감지하는 간단한 프로그램을 작성할 수 있습니다.
여기서 아이디어는 모든 할당을 추적하고 프로그램 실행 중에 해제되었는지 여부를 확인하는 것입니다.
프로그램 실행 중 메모리 할당 정보를 저장하기 위한 기본 데이터 구조부터 시작하겠습니다.
데이터 구조 코드
// We assume max 1000 allocations will take place
#define MAX_ALLOCATIONS 1000
/*
Data Structure to keep track of memory allocations
address -> Memory address allocated
size -> Size allocated
line -> Line number where allocation is done
*/
typedef struct {
size_t address;
size_t size;
uint32_t line;
} Mem;
/*
mem -> store all the allocation in array
total_allocated_size -> Keep track total memory allocated
total_free_size -> Keep track total memory freed
*/
struct {
Mem mem[MAX_ALLOCATIONS];
size_t total_allocated_size;
size_t total_free_size;
} data;
이제 데이터 구조에서 메모리 할당을 찾고, 삽입하고, 지우는 몇 가지 도우미 함수를 만들 것입니다.
도우미 함수 코드
/**
* Find a memory by its address
*
* @return: Pointer to memory
*/
Mem *find_by_address(size_t address) {
for (uint32_t i=0; i<MAX_ALLOCATIONS; i++) {
if (data.mem[i].address == address)
return &data.mem[i]; // as soon as find return
}
// otherwise return null
return NULL;
}
/**
* insert memory allocated with size
*/
void insert(size_t address, size_t size, uint32_t line) {
// check for null
if (address == 0) {
WARN("Memory allocation failed", line);
return;
}
Mem *mem = find_by_address(0);
// if the return value is null we need to increase the MAX_ALLOCATIONS value
if (mem == NULL) {
WARN("Max allocations reached", line);
return;
}
// save all the allocation info
mem->address = address;
mem->size = size;
mem->line = line;
data.total_allocated_size += size;
}
/**
* Remove the memory allocation
*
* @return: -1 on failure else 0
*/
int erase(size_t address, uint32_t line) {
if (address == 0) {
WARN("Tried to free a null ptr", line);
return -1;
}
Mem *mem = find_by_address(address);
// if the address is not found we assume it is already deleted
if (mem == NULL) {
WARN("Double free detected", line);
return -1;
}
// set address to null and update info
mem->address = 0;
data.total_free_size += mem->size;
return 0;
}
프로그램이 끝나면 메모리 누수에 대한 자세한 보고서를 인쇄합니다.
암호
void print_report() {
printf("\nLeak Summary\n");
printf("Total Memory allocated %lu bytes\n", data.total_allocated_size);
printf("Total Memory freed %lu bytes\n", data.total_free_size);
printf("Memory Leaked %lu bytes\n\n",
data.total_allocated_size - data.total_free_size);
if (data.total_free_size != data.total_allocated_size) {
printf("Detailed Report\n");
for (int i=0; i<MAX_ALLOCATIONS; i++) {
if (data.mem[i].address != 0) {
printf("Memory leak at line %d: (%lu bytes)\n",
data.mem[i].line,
data.mem[i].size);
}
}
}
}
이제 기본 할당자가 가로채는 함수를 만들어 메모리 할당 동안 삽입하고 사용 가능한 동안 지우십시오.
사용자 지정 할당자 함수
// Create allocator functions
void *_malloc(size_t size, uint32_t line) {
void *ptr = malloc(size);
// insert to memory data
insert((size_t)ptr, size, line);
return ptr;
}
void _free(void *ptr, uint32_t line) {
// erase memory data
if (erase((size_t)ptr, line) == 0)
free(ptr);
}
여기서 우리는 가로챈 함수로
malloc
및 free
와 같은 기본 할당자 함수를 재정의합니다.기본 할당자 함수 재정의
// redefine allocator functions
#define malloc(size) _malloc(size, __LINE__)
#define free(ptr) _free(ptr, __LINE__)
그게 다야!
완전한 코드
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#define MAX_ALLOCATIONS 100
#define WARN(msg, line) (printf("Warning %d: %s\n", line, msg))
/*
Data Structure to keep track of memory allocations
*/
typedef struct {
size_t address;
size_t size;
uint32_t line;
} Mem;
struct {
Mem mem[MAX_ALLOCATIONS];
size_t total_allocated_size;
size_t total_free_size;
} data;
/**
* Find a memory by its address
*
* @return: Pointer to memory
*/
Mem *find_by_address(size_t address) {
for (uint32_t i=0; i<MAX_ALLOCATIONS; i++) {
if (data.mem[i].address == address)
return &data.mem[i]; // as soon as find return
}
// otherwise return null
return NULL;
}
/**
* insert memory allocated with size
*/
void insert(size_t address, size_t size, uint32_t line) {
// check for null
if (address == 0) {
WARN("Memory allocation failed", line);
return;
}
Mem *mem = find_by_address(0);
// if the return value is null we need to increase the MAX_ALLOCATIONS value
if (mem == NULL) {
WARN("Max allocations reached", line);
return;
}
// save all the allocation info
mem->address = address;
mem->size = size;
mem->line = line;
data.total_allocated_size += size;
}
/**
* Remove the memory allocation
*
* @return: -1 on failure else 0
*/
int erase(size_t address, uint32_t line) {
if (address == 0) {
WARN("Tried to free a null ptr", line);
return -1;
}
Mem *mem = find_by_address(address);
// if the address is not found we assume it is already deleted
if (mem == NULL) {
WARN("Double free detected", line);
return -1;
}
// set address to null and update info
mem->address = 0;
data.total_free_size += mem->size;
return 0;
}
void print_report() {
printf("\nLeak Summary\n");
printf("Total Memory allocated %lu bytes\n", data.total_allocated_size);
printf("Total Memory freed %lu bytes\n", data.total_free_size);
printf("Memory Leaked %lu bytes\n\n",
data.total_allocated_size - data.total_free_size);
if (data.total_free_size != data.total_allocated_size) {
printf("Detailed Report\n");
for (int i=0; i<MAX_ALLOCATIONS; i++) {
if (data.mem[i].address != 0) {
printf("Memory leak at line %d: (%lu bytes)\n",
data.mem[i].line,
data.mem[i].size);
}
}
}
}
// Override allocation functions
void *_malloc(size_t size, uint32_t line) {
void *ptr = malloc(size);
// insert to memory data
insert((size_t)ptr, size, line);
return ptr;
}
void _free(void *ptr, uint32_t line) {
// erase memory data
if (erase((size_t)ptr, line) == 0)
free(ptr);
}
// redefine allocator functions
#define malloc(size) _malloc(size, __LINE__)
#define free(ptr) _free(ptr, __LINE__)
int main() {
int *n1 = malloc(sizeof(int));
free(n1);
int *n2 = NULL;
free(n2);
int *n3 = malloc(sizeof(int));
free(n3);
free(n3);
int *n4 = malloc(sizeof(int));
print_report();
return 0;
}
산출
naman@namantam1:~/programs$ gcc main.c && ./a.out
Warning 143: Tried to free a null ptr
Warning 147: Double free detected
Leak Summary
Total Memory allocated 12 bytes
Total Memory freed 8 bytes
Memory Leaked 4 bytes
Detailed Report
Memory leak at line 149: (4 bytes)
위의 출력에서 모든 메모리 누수를 double-free로 감지한 것이 분명합니다.
Note: This program will not be able to keep track of memory allocation done by inbuild or any third-party library. So if we free memory allocated in library call, It will show double free, We can simply ignore them.
❤️이 글을 읽어주셔서 정말 감사합니다. 저는 새로운 것을 배우는 열정적인 공대생이므로 실수를 발견하거나 제안할 사항이 있으면 댓글로 알려주세요.
또한 이 게시물이 어떤 식으로든 도움이 된다면 공유하고 엄지손가락을 치켜세우는 것을 고려하십시오.
Reference
이 문제에 관하여(C 프로그램에서 메모리 누수를 감지하는 간단한 프로그램), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/namantam1/a-simple-program-to-detect-memory-leak-in-our-c-program-5c5i텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)