안경잡이개발자

728x90
반응형

Q. 10칸이 들어갈 수 있는 char 배열을 만든 뒤에, 그 안에 정확히 10개의 문자를 넣었어요. 그런데 오류가 발생했어요. 왜 그런거죠? 캐릭터 배열은 원래 1자 적게 입력을 받아야 하나요?

 

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>

int main(void) {
	char a[10];
	scanf("%s", &a);
	printf("%s", a);
	system("pause");
	return 0;
}

 

A. 위 소스코드를 실행하면 실제로, 프로그램이 실행이 되긴 하는 것을 알 수 있습니다. 하지만 메모리를 벗어났기 때문에 런타임 오류가 발생할 수 있습니다.

 

 

이러한 결과가 나오는 이유는 우리가 scanf() 함수에 의해서 "0123456789"라는 문자열을 입력하면, 실제로는 문자열 뒤에 널(Null) 값이 붙어서 11자가 입력되는 것입니다. 그렇기 때문에 10자라는 캐릭터 배열의 범위를 벗어나서 오류가 발생하는 것입니다.

 

사실 char 배열로 10칸을 만들어도 정확히 10칸까지의 데이터를 넣을 수 있습니다. 하지만 이건 개발자가 억지로 10칸의 데이터를 넣는 것에 가깝습니다. 왜냐하면 printf("%s", 변수); 형태는 null을 만날 때까지 출력합니다. 따라서 null 값을 넣지 않게 되면, null 값을 만날 때까지 쓰레기 값이 왕창 출력될 수 있습니다.

 

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>

int main(void) {
	char a[10] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
	printf("%s", a);
	system("pause");
	return 0;
}

 

위 소스코드를 실행해 보시면, 0부터 9까지 가득 채워 정확히 10자 만큼의 char 배열을 초기화했기 때문에 null 값이 배열에 들어가지 못합니다. 그래서 0부터 9까지의 문자 뿐만 아니라 쓰레기 값까지 한꺼번에 출력될 확률이 높습니다. 

 

 

이러한 결과는 컴퓨터 시스템에 따라서 다를 수 있습니다. 우연히 그 뒤 메모리가 null로 채워져 있을 수 있다면, 정확히 0부터 9까지만 출력이 될 수도 있습니다. 맞습니다. 기본적으로 우리의 컴퓨터 시스템은 문자열을 초기화 하거나, 입력을 받을 때 자동으로 null 값을 뒤쪽에 채워넣게 됩니다.

 

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>

int main(void) {
	char a[] = "0123456789";
	printf("크기: %d\n", sizeof(a));
	system("pause");
	return 0;
}

 

위 소스코드를 실행해 보시면 a의 배열의 크기는 실제로 10 바이트가 아닌, 11 바이트인 것을 알 수 있습니다. 다시 말해서 1칸 이상의 여유 공간이 없도록 입력을 받는 경우에는 캐릭터 배열을 초기화할 때는 런타임 에러가 발생할 수 있는 것입니다.

 

 

이러한 상황에서는 우리의 컴퓨터 메모리 상에 문제가 발생하여, 오류가 발생할 수 있습니다. 하지만 특정 시스템에서는 그러한 문제가 발생한 상태에서 강제 종료가 되지는 않고 그대로 실행이 될 수 있습니다. 이러한 형태는 위험합니다. 프로그램을 실행하는 공격자가 임의로 악용할 수 있기 때문이죠.

 

그래서 gets_s()와 같이 메모리 오버플로우 공격을 방어할 수 있는 함수를 이용해야 합니다. 이러한 함수는 메모리 오류를 바로 체크해주기 때문에, 메모리 오버플로우가 발생한 위치에서 오류 메시지를 띄우게 됩니다. 그래서 버퍼 오버플로우 공격 등을 방어할 수 있습니다.

728x90
반응형