640 likes | 865 Vues
메모리관리 (MEM). 사이버보안학과 김현성. 제안. MEM00-C 동일한 추상화 레벨의 같은 모듈 안에서 메모리를 할당하고 해제하라 MEM01-C free() 후 즉시 포인터에 새로운 값을 저장하라 MEM02-C 메모리 할당 함수의 반환 값을 즉시 할당된 타입의 포인터로 변환시켜라 MEM03-C 재사용을 위해 반환된 재사용 가능한 리소스에 있는 중요한 정보를 클리어하라 MEM04-C 크기가 0 인 할당을 수행하지 마라 MEM05-C 큰 스택 할당을 피하라
E N D
메모리관리(MEM) 사이버보안학과 김현성
제안 • 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 객체에 충분한 메모리를 할당하라
제안 • 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);
동일한추상화 레벨의 같은 모듈 안에서 메모리를 할당하고 해제하라 MEM00-C 부적절한 코드 예 free(list); 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); } 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); }
제안 • 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 포인터 검증 함수를 사용하라
free() 후즉시 포인터에 새로운 값을 저장하라 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); } value_1 value_2 => 메시지 타입 고려 1or 2처리 => 메시지 타입이 1과 2 모두 참일 경우 존재
free() 후즉시 포인터에 새로운 값을 저장하라 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; }
제안 • 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 부적절한코드 예 => p->i=0 p->d=0.0 #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; } => 메모리 오버런 발생 가능 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; }
제안 • 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 포인터 검증 함수를 사용하라
재사용을 위해 반환된 재사용 가능한 리소스에 있는 중요한 정보를 클리어하라 재사용 가능한 리소스 • 동적으로 할당된 메모리 • 정적으로 할당된 메모리 • 자동으로 할당된(스택) 메모리 • 메모리 캐시 • 디스크 • 디스크 개시
재사용을 위해 반환된 재사용 가능한 리소스에 있는 중요한 정보를 클리어하라 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; => new_secret 복사, 이용 후 삭제 strcpy(new_secret, secret); => new_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;
제안 • 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 포인터 검증 함수를 사용하라
크기가 0인 할당을 수행하지 마라 MEM04-C 부적절한코드 예 size_t size; /* 사용자입력 값으로 크기를 초기화 */ int*list = (int *)malloc(size); if (list == NULL) { /* 할당 에러 처리 */ } else { /* list 처리 작업 */ } => 0바이트 할당을 위한 malloc(0) 호출이 가능함. 호출 결과는 구현마다 다름
크기가 0인 할당을 수행하지 마라 MEM04-C 해결방법 size_t size; /* 사용자입력 값으로 크기를 초기화 */ if(size == 0) { /* 에러 처리 */ } int*list = (int *)malloc(size); if (list == NULL) { /* 할당 에러 처리 */ } else { /* list 처리 작업 */ }
제안 • 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 부적절한코드 예 intcopy_file(FILE *src, FILE *dst, size_t bufsize) { char buf[bufsize]; while(fgets(buf, bufsize, src)) { if(fputs(buf, dst) == EOF) { /* 에러처리 */ } } return0; } char buf[bufsize]; => src문자열을 buf에 bufsize만큼 복사 => bufsize가 공격자에 의해 제어된다면 DoS 공격 가능
큰 스택 할당을 피하라 MEM05-C 해결방법 intcopy_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); return0; }
제안 • 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; secret = (char *)malloc(size+1); free(secret); => 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) { /* 에러처리 */ } => setrlimit()를 통해 코어덤프의 크기를0으로 설정 가능
제안 • 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()의 인자가 곱해지는 경우 size_t로 표현될 수 있게 하라 calloc() • 지정된 크기만큼 메모리 공간 할당 • 할당할원소의 개수 • 원소의 크기 • 저장공간이 size_t로 표현될 수 없는 경우 요구한 크기보다 적은 크기의 메모리가 할당됨
calloc()의 인자가 곱해지는 경우 size_t로 표현될 수 있게 하라 MEM07-C 부적절한코드 예 size_t num_elements = /*필요한 원소 개수 */; long*buffer = (long *)calloc(num_elements, sizeof(long)); if(buffer == NULL) { /* 에러 상태 처리 */ } /* ... */ free(buffer); buffer = NULL; calloc(num_elements, sizeof(long)) => calloc()의 개수가 size_t로 표현될 수 없다면 버퍼 오버플로우 발생 가능 존재
calloc()의 인자가 곱해지는 경우 size_t로 표현될 수 있게 하라 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;
제안 • 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 포인터 검증 함수를 사용하라
동적으로 할당된 배열을 리사이즈하는 경우에만 realloc()을 사용하라 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)); =>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));
제안 • 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으로 초기화 됨
메모리 할당 루틴이 메모리를 초기화해줄 것이라 가정하지 마라 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; malloc(MAX_BUF_SIZE) => len이 널문자를 포함한 str의 전체 길이보다 작은경우 buf는 종료문자를포함하지 않을 수 있음 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;
제안 • 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);}
포인터 검증 함수를 사용하라 MEM10-C 부적절한코드 예 void incr(int *intptr) { if(intptr == NULL) { /* 에러처리 */ } *intptr++; } *intptr++ => 포인터가 NULL이 아닌 경우라도 유효 하지 않은 값일 수 있고, 이로 인해 메모리 손상 or 비정상 종료 유발 가능
포인터 검증 함수를 사용하라 MEM10-C 해결방법 #include <assert.h> void incr(int *intptr) { assert(valid(intptr)); *intptr++; }
제안 • 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 객체에 충분한 메모리를 할당하라
해제된 메모리에 접근하지 마라 MEM30-C 부적절한 코드 예 for (p = head; p != NULL; p = p->next) free(p); free(p); => head와 연계된 모든 메모리 해제 => p->next 처리 전에 p가 해제되어 p->next가 해제된 메모리를 접근함
해제된 메모리에 접근하지 마라 MEM30-C 해결방법 for (p = head; p != NULL; p = q) { q = p->next; free(p); } head = NULL;
규칙 • MEM30-C 해제된 메모리에 접근하지 마라 • MEM31-C 동적으로 할당된 메모리는 한 번만 해제하라 • MEM32-C 메모리 할당 에러를 찾아 해결하라 • MEM33-C 유연한 배열 원소에 정확한 문법을 사용하라 • MEM34-C 동적으로 할당된 메모리만 해제하라 • MEM35-C 객체에 충분한 메모리를 할당하라
동적으로 할당된 메모리는 한 번만 해제하라 MEM31-C 부적절한 코드 예 size_t num_elem = /* 초기값할당 */; interror_condition = 0; int *x = (int *)malloc(num_elem * sizeof(int)); if(x == NULL) { /* 할당에러 처리 */ } /* ... */ if(error_condition == 1) { /* 할당에러 처리 */ free(x); } /* ...*/ free(x); free(x); free(x); => error_condition이 1인경우 두번 메모리 해제
동적으로 할당된 메모리는 한 번만 해제하라 MEM31-C 해결방법 size_t num_elem = /* 초기값할당 */; interror_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;
규칙 • MEM30-C 해제된 메모리에 접근하지 마라 • MEM31-C 동적으로 할당된 메모리는 한 번만 해제하라 • MEM32-C 메모리 할당 에러를 찾아 해결하라 • MEM33-C 유연한 배열 원소에 정확한 문법을 사용하라 • MEM34-C 동적으로 할당된 메모리만 해제하라 • MEM35-C 객체에 충분한 메모리를 할당하라
메모리 할당 에러를 찾아 해결하라 메모리할당 함수 출력 값