C언어 버그
목차
C언어의 위험한 코드를 정리한 문서입니다.
메모리누수, 널 문자열 비교
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
int p_equal_flag = 0;
char *p = (char *)malloc(20);
p = "hello\0world\0";
if (strcmp(p, "hello\0wall") == 0) {
p_equal_flag = 1;
}
printf("p : %s\n", p);
printf("p_equal_flag : %d\n", p_equal_flag);
free(p);
return 0;
}
버그
- char *p malloc 진행한 뒤 p에 대입연산자 (=) 로 문자열을 입력.
-
memcpy(p, "hello\0world\0", 20);
써줘야 함
-
- strcmp로 문자열을 비교.
- 널문자가 포함된 비교를 진행하기에 for문으로 하나하나 비교하거나
memcmp
를 써야 함. -
strncmp
또한 길이를 지정한다 하더라도 중간에 널 문자를 만나면 비교를 멈추기 때문에 사용하면 안됨.
- 널문자가 포함된 비교를 진행하기에 for문으로 하나하나 비교하거나
널검사 안한 포인터 사용
1
2
3
4
5
6
7
8
#include <string.h>
int get_maxlen(char *str1, char *str2) {
if (strlen(str1) > strlen(str2))
return strlen(str1);
else
return strlen(str2);
}
버그
- 널검사 없이
strlen
함수를 사용함.-
str1
또는str2
변수가 null 이면strlen
함수에서 segmentation fault 발생. - 포인터를 참조할 때에는 항상 널검사 진행.
- 널검사를 하지않는 위험한 함수임을 주석 또는 doxygen을 통해 사전에 정의. - 외부에서 null 검사가 완료된 검증된 포인터만 사용할 수 있도록 함
-
- 버그는 아니지만 속도상의 문제
-
strlen
함수가 총 3번 동작함. 2번 동작하게끔 줄일 수 있음
-
free 후 널 초기화 미진행
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <stdlib.h>
struct test_t {
int a;
int b;
};
void initialize_test(struct test_t *p) {
if (p == NULL) return ;
p->a = 0;
p->b = 0;
}
void free_test(struct test_t *p) {
if (p == NULL) return ;
free(p);
}
void func() {
struct test_t *p = (struct test *)malloc(sizeof(struct test));
initialize_test(p);
// code
free_test(p);
initialize_test(p);
}
버그
-
free
후 NULL 초기화를 하지 않아 이후initialize_test
함수의if (p == NULL)
구문에서 비정상 포인터를 걸러내지 못함.-
#define nullfree(p) if (p) { free(p); p = NULL; }
처럼 매크로를 free를 재정의해서 사용하면 좋음.
-
댕글링 포인터를 만드는 행위
변수, 구조체, 할당 시 초기화
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
void func()
{
// code
}
int main()
{
func();
const int ptr1_size = 32000;
char *ptr1 = malloc(ptr1_size);
memset(ptr1, 0, ptr1_size);
memcpy(ptr1, "asdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdf", 60);
printf("ptr1 addr : %x\n", ptr1);
printf("ptr1 : %s\n", ptr1);
free(ptr1);
char *ptr2 = malloc(8192);
memcpy(ptr2, "qwerqwer", 8);
printf("ptr2 addr : %x\n", ptr2);
printf("ptr2 : %s\n", ptr2);
free(ptr2);
return 0;
}
ptr1
, ptr2
변수 동적할당 시 memset
함수 등으로 메모리 초기화를 진행하지 않음.
코드 컴파일 후 실행 결과
1
2
3
4
ptr1 addr : 81da1920
ptr1 : asdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdf
ptr2 addr : 81da1920
ptr2 : qwerqwerasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdf
ptr2
변수 출력 시 ptr1
초기화하지 못한 ptr1의 뒷 문자가 출력됨.
만약 ptr1에 민감한 정보가 들어있다면 보안상의 문제가 발생할 수 있음.
따라서 알 수 있는 결과 : 변수 선언 시 꼭 초기화를 진행하자.
This post is licensed under CC BY 4.0 by the author.