63
메메메메메 (MEM) 메메메메메메메 메메메

메모리관리 (MEM)

  • Upload
    monty

  • View
    55

  • Download
    4

Embed Size (px)

DESCRIPTION

메모리관리 (MEM). 사이버보안학과 김현성. 제안. MEM00-C 동일한 추상화 레벨의 같은 모듈 안에서 메모리를 할당하고 해제하라 MEM01-C free() 후 즉시 포인터에 새로운 값을 저장하라 MEM02-C 메모리 할당 함수의 반환 값을 즉시 할당된 타입의 포인터로 변환시켜라 MEM03-C 재사용을 위해 반환된 재사용 가능한 리소스에 있는 중요한 정보를 클리어하라 MEM04-C 크기가 0 인 할당을 수행하지 마라 MEM05-C 큰 스택 할당을 피하라 - PowerPoint PPT Presentation

Citation preview

Page 1: 메모리관리 (MEM)

메모리관리(MEM)

사이버보안학과 김현성

Page 2: 메모리관리 (MEM)

2/63

제안 MEM00-C 동일한 추상화 레벨의 같은 모듈 안에서 메모리를 할당하고 해제하라 MEM01-C free() 후 즉시 포인터에 새로운 값을 저장하라 MEM02-C 메모리 할당 함수의 반환 값을 즉시 할당된 타입의 포인터로

변환시켜라 MEM03-C 재사용을 위해 반환된 재사용 가능한 리소스에 있는 중요한 정보를

클리어하라 MEM04-C 크기가 0 인 할당을 수행하지 마라 MEM05-C 큰 스택 할당을 피하라 MEM06-C 중요한 데이터가 디스크에 기록되지 않도록 보장하라 MEM07-C calloc() 의 인자가 곱해지는 경우 size_t 로 표현될 수 있게 하라 MEM08-C 동적으로 할당된 배열을 리사이즈하는 경우에만 realloc() 을

사용하라 MEM09-C 메모리 할당 루틴이 메모리를 초기화해줄 것이라 가정하지 마라 MEM10-C 포인터 검증 함수를 사용하라

Page 3: 메모리관리 (MEM)

규칙

MEM30-C 해제된 메모리에 접근하지 마라 MEM31-C 동적으로 할당된 메모리는 한 번만

해제하라 MEM32-C 메모리 할당 에러를 찾아 해결하라 MEM33-C 유연한 배열 원소에 정확한 문법을

사용하라 MEM34-C 동적으로 할당된 메모리만 해제하라 MEM35-C 객체에 충분한 메모리를 할당하라

3/63

Page 4: 메모리관리 (MEM)

4/63

제안 MEM00-C 동일한 추상화 레벨의 같은 모듈

안에서 메모리를 할당하고 해제하라 MEM01-C free() 후 즉시 포인터에 새로운 값을 저장하라 MEM02-C 메모리 할당 함수의 반환 값을 즉시 할당된 타입의 포인터로 변환시켜라 MEM03-C 재사용을 위해 반환된 재사용 가능한 리소스에 있는 중요한 정보를

클리어하라 MEM04-C 크기가 0 인 할당을 수행하지 마라 MEM05-C 큰 스택 할당을 피하라 MEM06-C 중요한 데이터가 디스크에 기록되지 않도록 보장하라 MEM07-C calloc() 의 인자가 곱해지는 경우 size_t 로 표현될 수 있게 하라 MEM08-C 동적으로 할당된 배열을 리사이즈하는 경우에만 realloc() 을 사용하라 MEM09-C 메모리 할당 루틴이 메모리를 초기화해줄 것이라 가정하지 마라 MEM10-C 포인터 검증 함수를 사용하라

Page 5: 메모리관리 (MEM)

메모리 할당 /해제 함수

void *malloc(size_t size); void *calloc(size_t nmemb, size_t

size); void *realloc(void *ptr, size_t size);

void free(void *ptr);

5/63

동일한 추상화 레벨의 같은 모듈 안에서 메모리를 할당하고 해제하라

Page 6: 메모리관리 (MEM)

MEM00-C 부적절한 코드 예enum {MIN_SIZE_ALLOWED = 32 };int verify_list(char *list, size_t size) {

if(size < MIN_SIZE_ALLOWED) {/* 에러 상태 처리 */free(list);return -1;}return 0;

}void process_list(size_t number) {

char *list = (char *)malloc(number);if(list == NULL) { /* 할당 에러 처리 */ }if(verify_list(list, number) == -1) {free(list);return;}/* 리스트 작업을 수행 */ free(list);

}

6/63

=> 같은 메모리를 중복 해제해 잠정적 악용가능한 취약성 존재

동일한 추상화 레벨의 같은 모듈 안에서 메모리를 할당하고 해제하라

free(list);

free(list);

free(list);

Page 7: 메모리관리 (MEM)

MEM00-C 해결방법enum {MIN_SIZE_ALLOWED = 32 };int verify_list(char *list, size_t size) {

if(size < MIN_SIZE_ALLOWED) {/* 에러 상태 처리 */return -1;}return 0;

}void process_list(size_t number) {

char *list = (char *)malloc(number);if(list == NULL) { /* 할당 에러 처리 */}if(verify_list(list, number) == -1) {free(list);return;}/* 리스트 작업을 수행 */ free(list);

}

7/63

동일한 추상화 레벨의 같은 모듈 안에서 메모리를 할당하고 해제하라

Page 8: 메모리관리 (MEM)

8/63

제안 MEM00-C 동일한 추상화 레벨의 같은 모듈 안에서 메모리를 할당하고 해제하라

MEM01-C free() 후 즉시 포인터에 새로운 값을 저장하라

MEM02-C 메모리 할당 함수의 반환 값을 즉시 할당된 타입의 포인터로 변환시켜라 MEM03-C 재사용을 위해 반환된 재사용 가능한 리소스에 있는 중요한 정보를

클리어하라 MEM04-C 크기가 0 인 할당을 수행하지 마라 MEM05-C 큰 스택 할당을 피하라 MEM06-C 중요한 데이터가 디스크에 기록되지 않도록 보장하라 MEM07-C calloc() 의 인자가 곱해지는 경우 size_t 로 표현될 수 있게 하라 MEM08-C 동적으로 할당된 배열을 리사이즈하는 경우에만 realloc() 을 사용하라 MEM09-C 메모리 할당 루틴이 메모리를 초기화해줄 것이라 가정하지 마라 MEM10-C 포인터 검증 함수를 사용하라

Page 9: 메모리관리 (MEM)

MEM01-C 부적절한 코드 예char *message;int message_type;/* message와 message_type을 초기화 */if(message_type == value_1) {

/* 메시지 타입 1 처리 */free(message);

}/* ... */if(message_type == value_2) {

/* 메시지 타입 2 처리 */free(message);

}

9/63

free() 후 즉시 포인터에 새로운 값을 저장하라

=> 메시지 타입이 1 과 2 모두 참일 경우 존재=> 메시지 타입 고려 1or 2 처리

value_1

value_2

Page 10: 메모리관리 (MEM)

MEM01-C 해결방법char *message;int message_type;/* message 와 message_type 을 초기화 */if(message_type == value_1) {

/* 메시지 타입 1 처리 */free(message);message = NULL;

}/* ... */if(message_type == value_2) {

/* 메시지 타입 2 처리 */free(message);message = NULL;

}

10/63

free() 후 즉시 포인터에 새로운 값을 저장하라

Page 11: 메모리관리 (MEM)

11/63

제안 MEM00-C 동일한 추상화 레벨의 같은 모듈 안에서 메모리를 할당하고 해제하라 MEM01-C free() 후 즉시 포인터에 새로운 값을 저장하라

MEM02-C 메모리 할당 함수의 반환 값을 즉시 할당된 타입의 포인터로 변환시켜라

MEM03-C 재사용을 위해 반환된 재사용 가능한 리소스에 있는 중요한 정보를 클리어하라

MEM04-C 크기가 0 인 할당을 수행하지 마라 MEM05-C 큰 스택 할당을 피하라 MEM06-C 중요한 데이터가 디스크에 기록되지 않도록 보장하라 MEM07-C calloc() 의 인자가 곱해지는 경우 size_t 로 표현될 수 있게 하라 MEM08-C 동적으로 할당된 배열을 리사이즈하는 경우에만 realloc() 을 사용하라 MEM09-C 메모리 할당 루틴이 메모리를 초기화해줄 것이라 가정하지 마라 MEM10-C 포인터 검증 함수를 사용하라

Page 12: 메모리관리 (MEM)

MEM02-C 부적절한 코드 예#include <stdlib.h>typedef struct gadget gadget;struct gadget {

int i;double d;

};typedef struct widget widget;struct widget {

char c[10];int i;double d;

};widget *p;/* ... */p = malloc(sizeof(gadget));If(p != NULL) {

p->i = 0;p->d = 0.0;

}

12/63

메모리 할당 함수의 반환 값을 즉시 할당된 타입의 포인터로 변환시켜라

=> 메모리 오버런 발생 가능

=> p->i=0 p->d=0.0

malloc(sizeof(gadget));

p->i = 0;p->d = 0.0;

Page 13: 메모리관리 (MEM)

MEM02-C 해결방법#include <stdlib.h>typedef struct gadget gadget;struct gadget {

int i;double d;

};typedef struct widget widget;struct widget {

char c[10];int i;double d;

};widget *p;/* ... */p = (widget *)malloc(sizeof(widget));If(p != NULL) {

p->i = 0;p->d = 0.0;

}

13/63

메모리 할당 함수의 반환 값을 즉시 할당된 타입의 포인터로 변환시켜라

Page 14: 메모리관리 (MEM)

14/63

제안 MEM00-C 동일한 추상화 레벨의 같은 모듈 안에서 메모리를 할당하고 해제하라 MEM01-C free() 후 즉시 포인터에 새로운 값을 저장하라 MEM02-C 메모리 할당 함수의 반환 값을 즉시 할당된 타입의 포인터로 변환시켜라

MEM03-C 재사용을 위해 반환된 재사용 가능한 리소스에 있는 중요한 정보를 클리어하라

MEM04-C 크기가 0 인 할당을 수행하지 마라 MEM05-C 큰 스택 할당을 피하라 MEM06-C 중요한 데이터가 디스크에 기록되지 않도록 보장하라 MEM07-C calloc() 의 인자가 곱해지는 경우 size_t 로 표현될 수 있게 하라 MEM08-C 동적으로 할당된 배열을 리사이즈하는 경우에만 realloc() 을 사용하라 MEM09-C 메모리 할당 루틴이 메모리를 초기화해줄 것이라 가정하지 마라 MEM10-C 포인터 검증 함수를 사용하라

Page 15: 메모리관리 (MEM)

재사용 가능한 리소스

동적으로 할당된 메모리 정적으로 할당된 메모리 자동으로 할당된 ( 스택 ) 메모리 메모리 캐시 디스크 디스크 캐시

15/63

재사용을 위해 반환된 재사용 가능한 리소스에 있는 중요한 정보를 클리어하라

Page 16: 메모리관리 (MEM)

MEM03-C 부적절한 코드 예

char *secret;/* secret 초기화 */char *new_secret;size_t size = strlen(secret);if(size == SIZE_MAX) { /* 에러 처리 */ }new_secret = (char *)malloc(size+1);if(!new_secret) { /* 에러 처리 */ }strcpy(new_secret, secret);/* new_secret 처리 ... */free(new_secret);new_secret = NULL;

16/63

재사용을 위해 반환된 재사용 가능한 리소스에 있는 중요한 정보를 클리어하라

=> new_secret 재활용당시 메모리 내용이공격에 활용가능

=> new_secret 복사 ,이용 후 삭제

strcpy(new_secret, secret);

free(new_secret);

Page 17: 메모리관리 (MEM)

MEM03-C 해결방법

char *secret;/* secret 초기화 */char *new_secret;size_t size = strlen(secret);if(size == SIZE_MAX) { /* 에러 처리 */ }new_secret = (char *)calloc(size+1, sizeof(char));if(!new_secret) { /* 에러 처리 */ }strcpy(new_secret, secret);/* new_secret 처리 ... */memset((volatile char *)new_secret, ‘\0’, size);free(new_secret);new_secret = NULL;

17/63

재사용을 위해 반환된 재사용 가능한 리소스에 있는 중요한 정보를 클리어하라

Page 18: 메모리관리 (MEM)

18/63

제안 MEM00-C 동일한 추상화 레벨의 같은 모듈 안에서 메모리를 할당하고 해제하라 MEM01-C free() 후 즉시 포인터에 새로운 값을 저장하라 MEM02-C 메모리 할당 함수의 반환 값을 즉시 할당된 타입의 포인터로 변환시켜라 MEM03-C 재사용을 위해 반환된 재사용 가능한 리소스에 있는 중요한 정보를

클리어하라

MEM04-C 크기가 0 인 할당을 수행하지 마라 MEM05-C 큰 스택 할당을 피하라 MEM06-C 중요한 데이터가 디스크에 기록되지 않도록 보장하라 MEM07-C calloc() 의 인자가 곱해지는 경우 size_t 로 표현될 수 있게 하라 MEM08-C 동적으로 할당된 배열을 리사이즈하는 경우에만 realloc() 을 사용하라 MEM09-C 메모리 할당 루틴이 메모리를 초기화해줄 것이라 가정하지 마라 MEM10-C 포인터 검증 함수를 사용하라

Page 19: 메모리관리 (MEM)

MEM04-C 부적절한 코드 예

size_t size;/* 사용자 입력 값으로 크기를 초기화 */int *list = (int *)malloc(size);if (list == NULL) { /* 할당 에러 처리 */ }else { /* list 처리 작업 */ }

19/63=> 0 바이트 할당을 위한 malloc(0) 호출이가능함 . 호출 결과는 구현마다 다름

크기가 0 인 할당을 수행하지 마라

Page 20: 메모리관리 (MEM)

MEM04-C 해결방법

size_t size;/* 사용자 입력 값으로 크기를 초기화 */if(size == 0) { /* 에러 처리 */ }int *list = (int *)malloc(size);if (list == NULL) { /* 할당 에러 처리 */ }else { /* list 처리 작업 */ }

20/63

크기가 0 인 할당을 수행하지 마라

Page 21: 메모리관리 (MEM)

21/63

제안 MEM00-C 동일한 추상화 레벨의 같은 모듈 안에서 메모리를 할당하고 해제하라 MEM01-C free() 후 즉시 포인터에 새로운 값을 저장하라 MEM02-C 메 모 리 할 당 함 수 의 반 환 값 을 즉 시 할 당 된 타 입 의 포 인 터 로

변환시켜라 MEM03-C 재사용을 위해 반환된 재사용 가능한 리소스에 있는 중요한 정보를

클리어하라 MEM04-C 크기가 0 인 할당을 수행하지 마라

MEM05-C 큰 스택 할당을 피하라 MEM06-C 중요한 데이터가 디스크에 기록되지 않도록 보장하라 MEM07-C calloc() 의 인자가 곱해지는 경우 size_t 로 표현될 수 있게 하라 MEM08-C 동적으로 할당된 배열을 리사이즈하는 경우에만 realloc() 을 사용하라 MEM09-C 메모리 할당 루틴이 메모리를 초기화해줄 것이라 가정하지 마라 MEM10-C 포인터 검증 함수를 사용하라

Page 22: 메모리관리 (MEM)

MEM05-C 부적절한 코드 예

int copy_file(FILE *src, FILE *dst, size_t bufsize) {char buf[bufsize];while(fgets(buf, bufsize, src)) {

if(fputs(buf, dst) == EOF) {/* 에러 처리 */

}}return 0;

}

22/63

=> bufsize 가 공격자에 의해 제어된다면DoS 공격 가능

=> src 문자열을 buf 에 bufsize 만큼 복사

큰 스택 할당을 피하라

char buf[bufsize];

Page 23: 메모리관리 (MEM)

MEM05-C 해결방법

int copy_file(FILE *src, FILE *dst, size_t bufsize) {if(bufsize == 0) { /* 에러처리 */ }char *buf=(char *)malloc(bufsize);if(!buf) { return -1; }while(fgets(buf, bufsize, src)) {if(fputs(buf, dst) == EOF) {/* 에러 처리 */}}free(buf);return 0;

}

23/63

큰 스택 할당을 피하라

Page 24: 메모리관리 (MEM)

24/63

제안 MEM00-C 동일한 추상화 레벨의 같은 모듈 안에서 메모리를 할당하고 해제하라 MEM01-C free() 후 즉시 포인터에 새로운 값을 저장하라 MEM02-C 메모리 할당 함수의 반환 값을 즉시 할당된 타입의 포인터로 변환시켜라 MEM03-C 재사용을 위해 반환된 재사용 가능한 리소스에 있는 중요한 정보를

클리어하라 MEM04-C 크기가 0 인 할당을 수행하지 마라 MEM05-C 큰 스택 할당을 피하라

MEM06-C 중 요 한 데 이 터 가 디 스 크 에 기록되지 않도록 보장하라

MEM07-C calloc() 의 인자가 곱해지는 경우 size_t 로 표현될 수 있게 하라 MEM08-C 동적으로 할당된 배열을 리사이즈하는 경우에만 realloc() 을 사용하라 MEM09-C 메모리 할당 루틴이 메모리를 초기화해줄 것이라 가정하지 마라 MEM10-C 포인터 검증 함수를 사용하라

Page 25: 메모리관리 (MEM)

MEM06-C 부적절한 코드 예

char *secret;secret = (char *)malloc(size+1);if(!secret) { /* 에러 처리 */ }/* secret 을 사용한 작업 수행 */free(secret);secret = NULL;

25/63

중요한 데이터가 디스크에 기록되지 않도록 보장하라

=> free() 호출전 프로그램 종료시 secret에 저장된 정보는 코어 덤프에 기록됨

secret = (char *)malloc(size+1);

free(secret);

Page 26: 메모리관리 (MEM)

MEM06-C 해결방법#include <ssys/resource.h>/* ... */struct rlimit limit;char *secret;limit.rlim_cur = 0;limit.rlim_max = 0;if(setrlimit(RLIMIT_CORE, &limit) ! = 0) {

/* 에러 처리 */}/* 중요 데이터를 생성하거나 수집 */if(fgets(secret, sizeof(secret), stdin) == EOF) {

/* 에러 처리 */}

26/63

중요한 데이터가 디스크에 기록되지 않도록 보장하라

=> setrlimit() 를 통해 코어덤프의 크기를0 으로 설정 가능

Page 27: 메모리관리 (MEM)

27/63

제안 MEM00-C 동일한 추상화 레벨의 같은 모듈 안에서 메모리를 할당하고 해제하라 MEM01-C free() 후 즉시 포인터에 새로운 값을 저장하라 MEM02-C 메모리 할당 함수의 반환 값을 즉시 할당된 타입의 포인터로 변환시켜라 MEM03-C 재사용을 위해 반환된 재사용 가능한 리소스에 있는 중요한 정보를

클리어하라 MEM04-C 크기가 0 인 할당을 수행하지 마라 MEM05-C 큰 스택 할당을 피하라 MEM06-C 중요한 데이터가 디스크에 기록되지 않도록 보장하라

MEM07-C calloc() 의 인자가 곱해지는 경우 size_t 로 표현될 수 있게 하라

MEM08-C 동적으로 할당된 배열을 리사이즈하는 경우에만 realloc() 을 사용하라 MEM09-C 메모리 할당 루틴이 메모리를 초기화해줄 것이라 가정하지 마라 MEM10-C 포인터 검증 함수를 사용하라

Page 28: 메모리관리 (MEM)

calloc()

28/63

calloc() 의 인자가 곱해지는 경우 size_t 로 표현될 수 있게 하라

지정된 크기만큼 메모리 공간 할당– 할당할 원소의 개수– 원소의 크기

저장공간이 size_t 로 표현될 수 없는 경우 요구한 크기보다 적은 크기의 메모리가 할당됨

Page 29: 메모리관리 (MEM)

MEM07-C 부적절한 코드 예

size_t num_elements = /* 필요한 원소 개수 */;long *buffer = (long *)calloc(num_elements, sizeof(long));if(buffer == NULL) {

/* 에러 상태 처리 */}/* ... */free(buffer);buffer = NULL;

29/63

=> calloc() 의 개수가 size_t 로 표현될 수 없다면 버퍼 오버플로우 발생 가능 존재

calloc() 의 인자가 곱해지는 경우 size_t 로 표현될 수 있게 하라

calloc(num_elements, sizeof(long))

Page 30: 메모리관리 (MEM)

MEM07-C 해결방법

long *buffer;size_t num_elements = /* 필요한 원소 개수 */;if(num_elements > SIZE_MAX/sizeof(long)) {

/* 에러 상태 처리 */}buffer = (long *)calloc(num_elements, sizeof(long));if(buffer == NULL) {

/* 에러 상태 처리 */}/* ... */free(buffer);buffer = NULL;

30/63

calloc() 의 인자가 곱해지는 경우 size_t 로 표현될 수 있게 하라

Page 31: 메모리관리 (MEM)

31/63

제안 MEM00-C 동일한 추상화 레벨의 같은 모듈 안에서 메모리를 할당하고 해제하라 MEM01-C free() 후 즉시 포인터에 새로운 값을 저장하라 MEM02-C 메모리 할당 함수의 반환 값을 즉시 할당된 타입의 포인터로 변환시켜라 MEM03-C 재사용을 위해 반환된 재사용 가능한 리소스에 있는 중요한 정보를

클리어하라 MEM04-C 크기가 0 인 할당을 수행하지 마라 MEM05-C 큰 스택 할당을 피하라 MEM06-C 중요한 데이터가 디스크에 기록되지 않도록 보장하라 MEM07-C calloc() 의 인자가 곱해지는 경우 size_t 로 표현될 수 있게 하라

MEM08-C 동 적 으 로 할 당 된 배 열 을 리사이즈하는 경우에만 realloc() 을 사용하라

MEM09-C 메모리 할당 루틴이 메모리를 초기화해줄 것이라 가정하지 마라 MEM10-C 포인터 검증 함수를 사용하라

Page 32: 메모리관리 (MEM)

MEM08-C 부적절한 코드 예#include <stdlib.h>typedef struct gadget gadget;struct gadget {

int i;double e;char *p;

}typedef struct widget widget;struct widget {

char *q;int j;double e;

};gadget *gp;widget *wp;/* ... */wp = (widget *)realloc(gp, sizeof(widget));

32/63

=>widget 형을 gadget 형처럼 초기화 하고 있음

realloc(gp, sizeof(widget))

동적으로 할당된 배열을 리사이즈하는 경우에만 realloc() 을 사용하라

Page 33: 메모리관리 (MEM)

MEM08-C 해결방법#include <stdlib.h>typedef struct widget widget;struct widget {

char *q;int j;double e;

};widget *wp;widget *wq;/* ... */wp = (widget *)malloc(10*sizeof(widget)); /* ... */wq = (widget *)realloc(wp, 20*sizeof(widget));/* ... */wp = (widget *)realloc(wq, 15*sizeof(widget));

33/63

동적으로 할당된 배열을 리사이즈하는 경우에만 realloc() 을 사용하라

Page 34: 메모리관리 (MEM)

34/63

제안 MEM00-C 동일한 추상화 레벨의 같은 모듈 안에서 메모리를 할당하고 해제하라 MEM01-C free() 후 즉시 포인터에 새로운 값을 저장하라 MEM02-C 메모리 할당 함수의 반환 값을 즉시 할당된 타입의 포인터로 변환시켜라 MEM03-C 재사용을 위해 반환된 재사용 가능한 리소스에 있는 중요한 정보를

클리어하라 MEM04-C 크기가 0 인 할당을 수행하지 마라 MEM05-C 큰 스택 할당을 피하라 MEM06-C 중요한 데이터가 디스크에 기록되지 않도록 보장하라 MEM07-C calloc() 의 인자가 곱해지는 경우 size_t 로 표현될 수 있게 하라 MEM08-C 동적으로 할당된 배열을 리사이즈하는 경우에만 realloc() 을 사용하라

MEM09-C 메 모 리 할 당 루 틴 이 메 모 리 를 초기화해줄 것이라 가정하지 마라

MEM10-C 포인터 검증 함수를 사용하라

Page 35: 메모리관리 (MEM)

메모리 할당 함수

malloc() 은 값이 정해지지 않은 객체에 대한 공간 할당

realloc() 은 동적으로 할당된 메모리 블록의 크기 변경

calloc() 은 메모리의 모든 비트가 0으로 초기화 됨

35/63

메모리 할당 루틴이 메모리를 초기화해줄 것이라 가정하지 마라

Page 36: 메모리관리 (MEM)

MEM09-C 부적절한 코드 예enum { MAX_BUF_SIZE = 256 };char *str = /* 사용자 입력 데이터 */;size_t len = strlen(str);if(len >= MAX_BUF_SIZE -1) {

/* 너무 긴 문자열 에러 처리 */}char *buf = (char *)malloc(MAX_BUF_SIZE);if(buf == NULL) {

/* 할당 에러 처리 */}strncpy(buf, str, len);/* buf 처리 */free(buf);buf = NULL;

36/63

메모리 할당 루틴이 메모리를 초기화해줄 것이라 가정하지 마라

=> len 이 널문자를 포함한 str 의 전체 길이보다 작은경우 buf 는 종료문자를 포함하지 않을 수 있음

malloc(MAX_BUF_SIZE)

strncpy(buf, str, len)

Page 37: 메모리관리 (MEM)

MEM09-C 해결방법enum { MAX_BUF_SIZE = 256 };char *str = /* 사용자 입력 데이터 */;size_t len = strlen(str);if(len >= MAX_BUF_SIZE -1) {

/* 너무 긴 문자열 에러 처리 */}char *buf = (char *)malloc(MAX_BUF_SIZE);if(buf == NULL) {

/* 할당 에러 처리 */}strncpy(buf, str, len);/* 문자열 NULL 종료 */buf[len] = ‘\0’;/* buf 처리 */free(buf);buf = NULL;

37/63

메모리 할당 루틴이 메모리를 초기화해줄 것이라 가정하지 마라

Page 38: 메모리관리 (MEM)

38/63

제안 MEM00-C 동일한 추상화 레벨의 같은 모듈 안에서 메모리를 할당하고 해제하라 MEM01-C free() 후 즉시 포인터에 새로운 값을 저장하라 MEM02-C 메 모 리 할 당 함 수 의 반 환 값 을 즉 시 할 당 된 타 입 의 포 인 터 로

변환시켜라 MEM03-C 재사용을 위해 반환된 재사용 가능한 리소스에 있는 중요한 정보를

클리어하라 MEM04-C 크기가 0 인 할당을 수행하지 마라 MEM05-C 큰 스택 할당을 피하라 MEM06-C 중요한 데이터가 디스크에 기록되지 않도록 보장하라 MEM07-C calloc() 의 인자가 곱해지는 경우 size_t 로 표현될 수 있게 하라 MEM08-C 동적으로 할당된 배열을 리사이즈하는 경우에만 realloc() 을 사용하라 MEM09-C 메모리 할당 루틴이 메모리를 초기화해줄 것이라 가정하지 마라

MEM10-C 포인터 검증 함수를 사용하라

Page 39: 메모리관리 (MEM)

포인터 유효성 체크

NULL 제외한 모든 포인터 유효int invalid(void *ptr) {

return (ptr != NULL);}

39/63

포인터 검증 함수를 사용하라

Page 40: 메모리관리 (MEM)

MEM10-C 부적절한 코드 예

void incr(int *intptr) {if(intptr == NULL) {

/* 에러 처리 */}*intptr++;

}

40/63

포인터 검증 함수를 사용하라

=> 포인터가 NULL 이 아닌 경우라도 유효하지 않은 값일 수 있고 , 이로 인해 메모리 손상 or 비정상 종료 유발 가능

*intptr++

Page 41: 메모리관리 (MEM)

MEM10-C 해결방법

#include <assert.h>void incr(int *intptr) {

assert(valid(intptr));*intptr++;

}

41/63

포인터 검증 함수를 사용하라

Page 42: 메모리관리 (MEM)

42/63

제안 MEM00-C 동일한 추상화 레벨의 같은 모듈 안에서 메모리를 할당하고 해제하라 MEM01-C free() 후 즉시 포인터에 새로운 값을 저장하라 MEM02-C 메모리 할당 함수의 반환 값을 즉시 할당된 타입의 포인터로

변환시켜라 MEM03-C 재사용을 위해 반환된 재사용 가능한 리소스에 있는 중요한 정보를

클리어하라 MEM04-C 크기가 0 인 할당을 수행하지 마라 MEM05-C 큰 스택 할당을 피하라 MEM06-C 중요한 데이터가 디스크에 기록되지 않도록 보장하라 MEM07-C calloc() 의 인자가 곱해지는 경우 size_t 로 표현될 수 있게 하라 MEM08-C 동적으로 할당된 배열을 리사이즈하는 경우에만 realloc() 을

사용하라 MEM09-C 메모리 할당 루틴이 메모리를 초기화해줄 것이라 가정하지 마라 MEM10-C 포인터 검증 함수를 사용하라

Page 43: 메모리관리 (MEM)

규칙

MEM30-C 해제된 메모리에 접근하지 마라 MEM31-C 동적으로 할당된 메모리는 한 번만

해제하라 MEM32-C 메모리 할당 에러를 찾아 해결하라 MEM33-C 유연한 배열 원소에 정확한 문법을

사용하라 MEM34-C 동적으로 할당된 메모리만 해제하라 MEM35-C 객체에 충분한 메모리를 할당하라

43/63

Page 44: 메모리관리 (MEM)

MEM30-C 부적절한 코드 예

for (p = head; p != NULL; p = p->next)

free(p);

44/63

=> head 와 연계된 모든 메모리 해제

해제된 메모리에 접근하지 마라

=> p->next 처리 전에 p 가 해제되어 p->next 가 해제된 메모리를 접근함

free(p);

Page 45: 메모리관리 (MEM)

MEM30-C 해결방법

for (p = head; p != NULL; p = q) {q = p->next;free(p);

}head = NULL;

45/63

해제된 메모리에 접근하지 마라

Page 46: 메모리관리 (MEM)

규칙

MEM30-C 해제된 메모리에 접근하지 마라 MEM31-C 동적으로 할당된 메모리는 한

번만 해제하라 MEM32-C 메모리 할당 에러를 찾아 해결하라 MEM33-C 유연한 배열 원소에 정확한 문법을

사용하라 MEM34-C 동적으로 할당된 메모리만 해제하라 MEM35-C 객체에 충분한 메모리를 할당하라

46/63

Page 47: 메모리관리 (MEM)

MEM31-C 부적절한 코드 예size_t num_elem = /* 초기값 할당 */;int error_condition = 0;int *x = (int *)malloc(num_elem * sizeof(int));if(x == NULL) {

/* 할당 에러 처리 */}/* ... */if(error_condition == 1) {

/* 할당 에러 처리 */free(x);

}/* ... */free(x);

47/63

동적으로 할당된 메모리는 한 번만 해제하라

=> error_condition 이 1 인경우 두번 메모리 해제

free(x);

free(x);

Page 48: 메모리관리 (MEM)

MEM31-C 해결방법size_t num_elem = /* 초기값 할당 */;int error_condition = 0;if(num_elem > SIZE_MAX/sizeof(int)) { /* 오버플로우 처리 */ }int *x = (int *)malloc(num_elem * sizeof(int));if(x == NULL) {

/* 할당 에러 처리 */}/* ... */if(error_condition == 1) {

/* 에러 상태 처리 */}/* ... */free(x);x = NULL;

48/63

동적으로 할당된 메모리는 한 번만 해제하라

Page 49: 메모리관리 (MEM)

규칙

MEM30-C 해제된 메모리에 접근하지 마라 MEM31-C 동적으로 할당된 메모리는 한 번만

해제하라 MEM32-C 메모리 할당 에러를 찾아

해결하라 MEM33-C 유연한 배열 원소에 정확한 문법을

사용하라 MEM34-C 동적으로 할당된 메모리만 해제하라 MEM35-C 객체에 충분한 메모리를 할당하라

49/63

Page 50: 메모리관리 (MEM)

메모리 할당 함수 출력 값

함수 성공시 반환 값

에러시 반환 값

malloc() 할당된 공간에 대한 포인터

널 포인터

calloc() 할당된 공간에 대한 포인터

널 포인터

realloc() 새로운 객체에 대한 포인터

널 포인터

50/63

메모리 할당 에러를 찾아 해결하라

Page 51: 메모리관리 (MEM)

MEM32-C 부적절한 코드 예

char *input_string = /* 신뢰할 수 없는 데이터로부터 초기화 */size_t size = strlen(input_string) + 1;char *str = (char *)malloc(size);strcpy(str, input_string);/* ... */free(str);str = NULL;

51/63

메모리 할당 에러를 찾아 해결하라

=> 메모리 할당 에러 상태 체크 필요

malloc(size)

Page 52: 메모리관리 (MEM)

MEM32-C 해결방법char *input_string = /* 신뢰할 수 없는 데이터로부터 초기화 */size_t size = strlen(input_string) + 1;char *str = (char *)malloc(size);if(str == NULL) { /* 할당 에러 처리 */ }else {

strcpy(str, input_string);/* ... */free(str);str = NULL;

}

52/63

메모리 할당 에러를 찾아 해결하라

Page 53: 메모리관리 (MEM)

규칙

MEM30-C 해제된 메모리에 접근하지 마라 MEM31-C 동적으로 할당된 메모리는 한 번만

해제하라 MEM32-C 메모리 할당 에러를 찾아 해결하라 MEM33-C 유연한 배열 원소에 정확한

문법을 사용하라 MEM34-C 동적으로 할당된 메모리만 해제하라 MEM35-C 객체에 충분한 메모리를 할당하라

53/63

Page 54: 메모리관리 (MEM)

MEM33-C 부적절한 코드 예struct flexArrayStruct {

int num;int data[1];

};/* ... */size_t array_size;size_t i;/* array_size 초기화 */struct flexArrayStruct *structP = (struct flexArrayStruct *) malloc(sizeof(struct flexArrayStruct) +

sizeof(int) * (array_size -1));if (structP == NULL) { /* malloc 실패 시 처리 */ }structP->num = 0;for(i = 0; i < array_size; i++) {

structP->data[i] = 1;}

54/63

유연한 배열 원소에 정확한 문법을 사용하라

=> structP->data 는 크기 1 인 배열

structP->data[i]

Page 55: 메모리관리 (MEM)

MEM33-C 해결방법struct flexArrayStruct {

int num;int data[];

};/* ... */size_t array_size;size_t i;/* array_size 초기화 */struct flexArrayStruct *structP = (struct flexArrayStruct *) malloc(sizeof(struct flexArrayStruct) +

sizeof(int) * (array_size -1));if (structP == NULL) { /* malloc 실패 시 처리 */ }structP->num = 0;for(i = 0; i < array_size; i++) {

structP->data[i] = 1;}

55/63

유연한 배열 원소에 정확한 문법을 사용하라

=> data[array_size] 선언처럼 처리

Page 56: 메모리관리 (MEM)

data[] 제한 불완전한 배열 타입은 ‘반드시‘ 구조체의

마지막 원소여야 함 불완전한 배열 타입을 원소로 갖는 구조체의

배열은 있을 수 없음 유연한 배열 멤버를 포함하는 구조체를 다른

구조체의 멤버로 사용할 때 가운데에 배치할 수 없음

sizeof 연산자는 유연한 배열에 적용할 수 없음

56/63

유연한 배열 원소에 정확한 문법을 사용하라

Page 57: 메모리관리 (MEM)

규칙

MEM30-C 해제된 메모리에 접근하지 마라 MEM31-C 동적으로 할당된 메모리는 한 번만

해제하라 MEM32-C 메모리 할당 에러를 찾아 해결하라 MEM33-C 유연한 배열 원소에 정확한 문법을

사용하라 MEM34-C 동적으로 할당된 메모리만

해제하라 MEM35-C 객체에 충분한 메모리를 할당하라

57/63

Page 58: 메모리관리 (MEM)

MEM34-C 부적절한 코드 예enum { MAX_ALLOCATION = 1000 };int main(int argc, const char *agrv[]) {

char *str = NULL;size_t len;if(argc == 2) {len = strlen(argv[1]) + 1;if(len > MAX_ALLOCATION) { /* 에러 처리 */ }str = (char *)malloc(len);if(str == NULL) { /* 할당 에러 처리 */ }strcpy(str, argv[1]);}else {str = “usage: $>a.exe [string]”;printf(“%s\n”, str);}/* ... */free(str);return 0;

}

58/63=> else 시 str 에 문자리터럴이 정의되어 있어 오류

free(str)

동적으로 할당된 메모리만 해제하라

str = “usage: $>a.exe [string]”

Page 59: 메모리관리 (MEM)

MEM34-C 해결방법enum { MAX_ALLOCATION = 1000 };int main(int argc, const char *agrv[]) {

char *str = NULL;size_t len;if(argc == 2) {len = strlen(argv[1]) + 1;if(len > MAX_ALLOCATION) { /* 에러 처리 */ }str = (char *)malloc(len);if(str == NULL) { /* 할당 에러 처리 */ }strcpy(str, argv[1]);}else {printf(“%s\n”, “usage: $>a.exe [string]”);return -1;}/* ... */free(str);return 0;

}

59/63

동적으로 할당된 메모리만 해제하라

Page 60: 메모리관리 (MEM)

규칙

MEM30-C 해제된 메모리에 접근하지 마라 MEM31-C 동적으로 할당된 메모리는 한 번만

해제하라 MEM32-C 메모리 할당 에러를 찾아 해결하라 MEM33-C 유연한 배열 원소에 정확한 문법을

사용하라 MEM34-C 동적으로 할당된 메모리만 해제하라 MEM35-C 객체에 충분한 메모리를

할당하라

60/63

Page 61: 메모리관리 (MEM)

MEM35-C 부적절한 코드 예enum { BLOCKSIZE = 16 };/* ... */void *alloc_blocks(size_t num_blocks) {

if (num_blocks == 0) {return NULL;}unsigned long long alloc = num_blocks *

BLOCKSIZE;return (alloc < UINT_MAX) ? malloc(num_blocks * BLOCKSIZE): NULL;

}

61/63

객체에 충분한 메모리를 할당하라

=> 곱셈의 결과 오버플로우 발생 가능

num_blocks * BLOCKSIZE

Page 62: 메모리관리 (MEM)

MEM35-C 해결방법

enum { BLOCKSIZE = 16 };/* ... */void *alloc_blocks(size_t num_blocks) { if (num_blocks == 0

|| num_blocks > SIZE_MAX / BLOCKSIZE) {

return NULL;}return malloc(num_blocks * BLOCKSIZE);

}

62/63

객체에 충분한 메모리를 할당하라

Page 63: 메모리관리 (MEM)

규칙

MEM30-C 해제된 메모리에 접근하지 마라 MEM31-C 동적으로 할당된 메모리는 한 번만

해제하라 MEM32-C 메모리 할당 에러를 찾아 해결하라 MEM33-C 유연한 배열 원소에 정확한 문법을

사용하라 MEM34-C 동적으로 할당된 메모리만 해제하라 MEM35-C 객체에 충분한 메모리를 할당하라

63/63