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
메모리관리(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 포인터 검증 함수를 사용하라
규칙
MEM30-C 해제된 메모리에 접근하지 마라 MEM31-C 동적으로 할당된 메모리는 한 번만
해제하라 MEM32-C 메모리 할당 에러를 찾아 해결하라 MEM33-C 유연한 배열 원소에 정확한 문법을
사용하라 MEM34-C 동적으로 할당된 메모리만 해제하라 MEM35-C 객체에 충분한 메모리를 할당하라
3/63
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 포인터 검증 함수를 사용하라
메모리 할당 /해제 함수
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
동일한 추상화 레벨의 같은 모듈 안에서 메모리를 할당하고 해제하라
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);
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
동일한 추상화 레벨의 같은 모듈 안에서 메모리를 할당하고 해제하라
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 포인터 검증 함수를 사용하라
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
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() 후 즉시 포인터에 새로운 값을 저장하라
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 포인터 검증 함수를 사용하라
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;
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
메모리 할당 함수의 반환 값을 즉시 할당된 타입의 포인터로 변환시켜라
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 포인터 검증 함수를 사용하라
재사용 가능한 리소스
동적으로 할당된 메모리 정적으로 할당된 메모리 자동으로 할당된 ( 스택 ) 메모리 메모리 캐시 디스크 디스크 캐시
15/63
재사용을 위해 반환된 재사용 가능한 리소스에 있는 중요한 정보를 클리어하라
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);
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
재사용을 위해 반환된 재사용 가능한 리소스에 있는 중요한 정보를 클리어하라
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 포인터 검증 함수를 사용하라
MEM04-C 부적절한 코드 예
size_t size;/* 사용자 입력 값으로 크기를 초기화 */int *list = (int *)malloc(size);if (list == NULL) { /* 할당 에러 처리 */ }else { /* list 처리 작업 */ }
19/63=> 0 바이트 할당을 위한 malloc(0) 호출이가능함 . 호출 결과는 구현마다 다름
크기가 0 인 할당을 수행하지 마라
MEM04-C 해결방법
size_t size;/* 사용자 입력 값으로 크기를 초기화 */if(size == 0) { /* 에러 처리 */ }int *list = (int *)malloc(size);if (list == NULL) { /* 할당 에러 처리 */ }else { /* list 처리 작업 */ }
20/63
크기가 0 인 할당을 수행하지 마라
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 포인터 검증 함수를 사용하라
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];
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
큰 스택 할당을 피하라
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 포인터 검증 함수를 사용하라
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);
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 으로 설정 가능
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 포인터 검증 함수를 사용하라
calloc()
28/63
calloc() 의 인자가 곱해지는 경우 size_t 로 표현될 수 있게 하라
지정된 크기만큼 메모리 공간 할당– 할당할 원소의 개수– 원소의 크기
저장공간이 size_t 로 표현될 수 없는 경우 요구한 크기보다 적은 크기의 메모리가 할당됨
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))
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 로 표현될 수 있게 하라
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 포인터 검증 함수를 사용하라
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() 을 사용하라
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() 을 사용하라
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 포인터 검증 함수를 사용하라
메모리 할당 함수
malloc() 은 값이 정해지지 않은 객체에 대한 공간 할당
realloc() 은 동적으로 할당된 메모리 블록의 크기 변경
calloc() 은 메모리의 모든 비트가 0으로 초기화 됨
35/63
메모리 할당 루틴이 메모리를 초기화해줄 것이라 가정하지 마라
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)
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
메모리 할당 루틴이 메모리를 초기화해줄 것이라 가정하지 마라
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 포인터 검증 함수를 사용하라
포인터 유효성 체크
NULL 제외한 모든 포인터 유효int invalid(void *ptr) {
return (ptr != NULL);}
39/63
포인터 검증 함수를 사용하라
MEM10-C 부적절한 코드 예
void incr(int *intptr) {if(intptr == NULL) {
/* 에러 처리 */}*intptr++;
}
40/63
포인터 검증 함수를 사용하라
=> 포인터가 NULL 이 아닌 경우라도 유효하지 않은 값일 수 있고 , 이로 인해 메모리 손상 or 비정상 종료 유발 가능
*intptr++
MEM10-C 해결방법
#include <assert.h>void incr(int *intptr) {
assert(valid(intptr));*intptr++;
}
41/63
포인터 검증 함수를 사용하라
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 포인터 검증 함수를 사용하라
규칙
MEM30-C 해제된 메모리에 접근하지 마라 MEM31-C 동적으로 할당된 메모리는 한 번만
해제하라 MEM32-C 메모리 할당 에러를 찾아 해결하라 MEM33-C 유연한 배열 원소에 정확한 문법을
사용하라 MEM34-C 동적으로 할당된 메모리만 해제하라 MEM35-C 객체에 충분한 메모리를 할당하라
43/63
MEM30-C 부적절한 코드 예
for (p = head; p != NULL; p = p->next)
free(p);
44/63
=> head 와 연계된 모든 메모리 해제
해제된 메모리에 접근하지 마라
=> p->next 처리 전에 p 가 해제되어 p->next 가 해제된 메모리를 접근함
free(p);
MEM30-C 해결방법
for (p = head; p != NULL; p = q) {q = p->next;free(p);
}head = NULL;
45/63
해제된 메모리에 접근하지 마라
규칙
MEM30-C 해제된 메모리에 접근하지 마라 MEM31-C 동적으로 할당된 메모리는 한
번만 해제하라 MEM32-C 메모리 할당 에러를 찾아 해결하라 MEM33-C 유연한 배열 원소에 정확한 문법을
사용하라 MEM34-C 동적으로 할당된 메모리만 해제하라 MEM35-C 객체에 충분한 메모리를 할당하라
46/63
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);
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
동적으로 할당된 메모리는 한 번만 해제하라
규칙
MEM30-C 해제된 메모리에 접근하지 마라 MEM31-C 동적으로 할당된 메모리는 한 번만
해제하라 MEM32-C 메모리 할당 에러를 찾아
해결하라 MEM33-C 유연한 배열 원소에 정확한 문법을
사용하라 MEM34-C 동적으로 할당된 메모리만 해제하라 MEM35-C 객체에 충분한 메모리를 할당하라
49/63
메모리 할당 함수 출력 값
함수 성공시 반환 값
에러시 반환 값
malloc() 할당된 공간에 대한 포인터
널 포인터
calloc() 할당된 공간에 대한 포인터
널 포인터
realloc() 새로운 객체에 대한 포인터
널 포인터
50/63
메모리 할당 에러를 찾아 해결하라
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)
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
메모리 할당 에러를 찾아 해결하라
규칙
MEM30-C 해제된 메모리에 접근하지 마라 MEM31-C 동적으로 할당된 메모리는 한 번만
해제하라 MEM32-C 메모리 할당 에러를 찾아 해결하라 MEM33-C 유연한 배열 원소에 정확한
문법을 사용하라 MEM34-C 동적으로 할당된 메모리만 해제하라 MEM35-C 객체에 충분한 메모리를 할당하라
53/63
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]
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] 선언처럼 처리
data[] 제한 불완전한 배열 타입은 ‘반드시‘ 구조체의
마지막 원소여야 함 불완전한 배열 타입을 원소로 갖는 구조체의
배열은 있을 수 없음 유연한 배열 멤버를 포함하는 구조체를 다른
구조체의 멤버로 사용할 때 가운데에 배치할 수 없음
sizeof 연산자는 유연한 배열에 적용할 수 없음
56/63
유연한 배열 원소에 정확한 문법을 사용하라
규칙
MEM30-C 해제된 메모리에 접근하지 마라 MEM31-C 동적으로 할당된 메모리는 한 번만
해제하라 MEM32-C 메모리 할당 에러를 찾아 해결하라 MEM33-C 유연한 배열 원소에 정확한 문법을
사용하라 MEM34-C 동적으로 할당된 메모리만
해제하라 MEM35-C 객체에 충분한 메모리를 할당하라
57/63
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]”
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
동적으로 할당된 메모리만 해제하라
규칙
MEM30-C 해제된 메모리에 접근하지 마라 MEM31-C 동적으로 할당된 메모리는 한 번만
해제하라 MEM32-C 메모리 할당 에러를 찾아 해결하라 MEM33-C 유연한 배열 원소에 정확한 문법을
사용하라 MEM34-C 동적으로 할당된 메모리만 해제하라 MEM35-C 객체에 충분한 메모리를
할당하라
60/63
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
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
객체에 충분한 메모리를 할당하라
규칙
MEM30-C 해제된 메모리에 접근하지 마라 MEM31-C 동적으로 할당된 메모리는 한 번만
해제하라 MEM32-C 메모리 할당 에러를 찾아 해결하라 MEM33-C 유연한 배열 원소에 정확한 문법을
사용하라 MEM34-C 동적으로 할당된 메모리만 해제하라 MEM35-C 객체에 충분한 메모리를 할당하라
63/63