OPEN HYPER STEP
← 목록으로 (화이트햇 보안)
SECURITY · 90 / 96
security
CHAPTER 90 / 96
읽기 약 2
FUNCTION

malloc과 free: 동적 메모리


핵심 개념

malloc/calloc/realloc/free — 메모리 누수, dangling 포인터, double free + valgrind 탐지.

본문

4가지 동적 메모리 함수

C📋 코드 (9줄)
#include <stdlib.h>

// 할당
void *malloc(size_t size);              // 초기화 안 된 메모리
void *calloc(size_t n, size_t size);    // 0으로 초기화
void *realloc(void *ptr, size_t size);  // 크기 변경

// 해제
void  free(void *ptr);

malloc 기본

C📋 코드 (22줄)
#include <stdio.h>
#include <stdlib.h>

int main(void) {
    int *arr = malloc(10 * sizeof(int));
    if (arr == NULL) {
        fprintf(stderr, "할당 실패\n");
        return 1;
    }

    // 초기화 안 됨 — 쓰레기 값
    printf("초기값: %d\n", arr[0]);

    for (int i = 0; i < 10; i++) {
        arr[i] = i;
    }

    free(arr);
    arr = NULL;  // dangling 방지

    return 0;
}

calloc — 0 초기화

C📋 코드 (16줄)
#include <stdio.h>
#include <stdlib.h>

int main(void) {
    int *arr = calloc(10, sizeof(int));
    if (arr == NULL) return 1;

    // 모두 0
    for (int i = 0; i < 10; i++) {
        printf("%d ", arr[i]);  // 0 0 0 0 0 0 0 0 0 0
    }
    printf("\n");

    free(arr);
    return 0;
}

realloc — 크기 변경

C📋 코드 (22줄)
#include <stdio.h>
#include <stdlib.h>

int main(void) {
    int *arr = malloc(5 * sizeof(int));
    for (int i = 0; i < 5; i++) arr[i] = i;

    // 10개로 확장
    int *new_arr = realloc(arr, 10 * sizeof(int));
    if (new_arr == NULL) {
        free(arr);  // 원본 해제 후 종료
        return 1;
    }
    arr = new_arr;  // ⚠️ realloc 실패 시 원본 그대로 유효

    // 기존 값 보존됨, 새 영역은 초기화 안 됨
    for (int i = 0; i < 5; i++) printf("%d ", arr[i]);
    // 0 1 2 3 4

    free(arr);
    return 0;
}

메모리 누수

C📋 코드 (15줄)
#include <stdio.h>
#include <stdlib.h>

void leak(void) {
    int *p = malloc(1000 * sizeof(int));
    // ⚠️ free 누락 — 함수 종료 시 메모리 누수
}

int main(void) {
    for (int i = 0; i < 1000000; i++) {
        leak();
    }
    // 4GB 누수
    return 0;
}

valgrind로 누수 탐지

BASH📋 코드 (15줄)
# 컴파일
gcc -g -O0 leak.c -o leak

# valgrind 실행
valgrind --leak-check=full ./leak

# 출력 예시:
# ==12345== HEAP SUMMARY:
# ==12345==     in use at exit: 4,000,000,000 bytes in 1,000,000 blocks
# ==12345==   total heap usage: 1,000,000 allocs, 0 frees, 4,000,000,000 bytes allocated
# ==12345==
# ==12345== 4,000,000,000 bytes in 1,000,000 blocks are definitely lost
# ==12345==    at 0x...: malloc
# ==12345==    by 0x...: leak (leak.c:5)
# ==12345==    by 0x...: main (leak.c:12)

Dangling 포인터

C📋 코드 (19줄)
#include <stdio.h>
#include <stdlib.h>

int main(void) {
    int *p = malloc(sizeof(int));
    *p = 42;
    free(p);

    // ❌ 위험 — p는 더 이상 유효하지 않음 (dangling)
    // *p = 100;     // Use-After-Free
    // printf("%d\n", *p);  // 정의되지 않은 동작

    p = NULL;  // ✅ 명시적 무효화

    if (p != NULL) {
        // 실행 안 됨
    }
    return 0;
}

Double free

C📋 코드 (16줄)
#include <stdlib.h>

int main(void) {
    int *p = malloc(sizeof(int));
    free(p);
    free(p);  // ❌ 두 번 해제 — 힙 손상, glibc는 중단시킴
    // 출력: free(): double free detected in tcache 2
    // Aborted (core dumped)

    // ✅ 안전
    int *q = malloc(sizeof(int));
    free(q);
    q = NULL;  // 다시 free 호출되어도 free(NULL)은 안전
    free(q);   // OK
    return 0;
}

메모리 안전 패턴

C📋 코드 (32줄)
#include <stdio.h>
#include <stdlib.h>

// 패턴 1 — 단일 진입/종료 + cleanup
int do_work(void) {
    int *a = NULL, *b = NULL;
    int rc = -1;

    a = malloc(100);
    if (!a) goto cleanup;

    b = malloc(200);
    if (!b) goto cleanup;

    // 작업...
    rc = 0;

cleanup:
    free(a);
    free(b);
    return rc;
}

// 패턴 2 — 매크로로 free + NULL
#define SAFE_FREE(p) do { free(p); (p) = NULL; } while (0)

int main(void) {
    int *p = malloc(100);
    SAFE_FREE(p);
    SAFE_FREE(p);  // OK — free(NULL)
    return 0;
}

valgrind + gcc sanitizer

BASH📋 코드 (11줄)
# valgrind (모든 OS, 별도 도구)
valgrind --leak-check=full --track-origins=yes ./prog

# AddressSanitizer (gcc/clang 내장, 빠름)
gcc -fsanitize=address -g prog.c -o prog
./prog
# 누수·UAF·OOB 모두 탐지 + 정확한 위치 + 백트레이스

# MemorySanitizer (clang)
clang -fsanitize=memory -g prog.c -o prog
# 초기화 안 된 메모리 사용 탐지

다음 챕터

CH.7 "버퍼 오버플로우" — 메모리 안전의 가장 유명한 취약점.


AI 프롬프트
🤖 AI에게 잘 물어보는 법 — 모델·전략별 프롬프트
Claude

무료: Sonnet 4.6 / Pro $20/mo: Opus 4.6

내 C 코드의 모든 malloc/free 짝을
분석해서 누수·UAF·double free
위험 위치를 보고해줘.
ChatGPT

무료: GPT-5.5 / Plus $20/mo: GPT-5.5 Pro

리눅스 커널과 일반 애플리케이션의
메모리 관리 차이 + RAII 패턴 비교를 알려줘.
Gemini

무료: 2.5 Flash / Pro $19.99/mo: 3.1 Pro

내 C 프로젝트에 valgrind/ASan을
적용하는 가이드와 자동화 스크립트를
만들어줘.
Grok

무료: Grok 4.1 / SuperGrok $30/mo

2026년 한국 임베디드 시스템에서
메모리 누수 사고 통계와 방어 트렌드를
솔직히 알려줘.

⭐ 이것만 기억하세요
malloc과 free: 동적 메모리 이 3가지만 확실히 잡으세요
1.malloc/free는 짝 — 누락 시 누수, 두 번 호출 시 double free
2.안전 패턴: free 후 NULL 설정 + valgrind/ASan으로 자동 탐지
3.다음 챕터 CH.7에서 버퍼 오버플로우 — 메모리 안전의 대표 취약점


공유하기
진행도 90 / 96