일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 | 27 | 28 | 29 | 30 | 31 |
- bagofwords
- DNS해킹
- stopword
- DNS개념
- pynput
- CodeTranslation
- MITM
- lemmatization
- NLP
- AI
- 모두의 깃&깃허브
- 비트시프트
- 15679
- Private AI
- C
- 동형암호
- bettercap
- kali
- pos tagging
- 노말틱
- youtubeNormaltic
- 해킹입문
- 해킹 용어
- MachineCode
- Normaltic
- CProgramming
- NLTK
- HEaaN
- c언어
- 딥러닝
- Today
- Total
일단 테크블로그😊
[CS 기초] DataType과 Overflow를 알아보자! 본문
0. Data Type의 존재 의의
프로그래밍 언어에서는 '데이터 타입(Data type, 자료형)'이라는 개념이 존재한다. 변수에 저장된 데이터를 다양한 타입 (integer, boolean, character, floating-point number... 등)으로 분류하여, 해당 데이터의 종류와 형식을 정의하고 처리하는 것이다. 그렇다면 왜 굳이 분류를 하는 것일까? 많은 이유가 존재하겠지만, 대표적으로 효율성과 안정성을 꼽을 수 있겠다.
1byte의 공간만 필요한 변수에 굳이 100bytes의 공간을 할당해 준다면, 그만큼 컴퓨터 리소스의 가용 공간이 줄어들어 효율이 떨어지게 됨은 물론, 프로그램이 복잡해질수록 예기치 않은 오류를 발생시킬 위험도 증가하게 될 것이다.
#include <stdio.h>
int main(void){
printf("Size of char : %zu bytes\n",sizeof(char)); // Size of char : 1 bytes
printf("Size of Short : %zu bytes\n",sizeof(short)); // Size of Short : 2 bytes
printf("Size of int : %zu bytes\n",sizeof(int)); // Size of int : 4 bytes
printf("Size of long : %zu bytes\n",sizeof(long)); // Size of long : 8 bytes
printf("Size of long long : %zu bytes\n",sizeof(long long)); // Size of long long : 8 bytes
printf("Size of float : %zu bytes\n",sizeof(float)); // Size of float : 4 bytes
printf("Size of double : %zu bytes\n",sizeof(double)); // Size of double : 8 bytes
printf("Size of long double : %zu bytes\n",sizeof(long double)); // Size of long double : 16 bytes
printf("Size of pointer : %zu bytes\n",sizeof(void*)); // Size of pointer : 8 bytes
return 0;
}
c언어로 알아보는 데이터 타입의 종류와 크기 (%zu는 sizeof 연산자의 결과를 받기 위한 서식 지정자입니다)
-그렇다면 Data type의 정의가 무조건 옳은가?
물론, 모든 기술이 약점을 가지듯 데이터 타입 또한 취약점을 가질 수밖에 없다. 그중 대표적인 약점이 바로 오버플로우이다. 오버플로우는 데이터 타입이 나타낼 수 있는 최댓값을 초과하려고 할 때 발생한다. 예를 들어, 1byte의 unsigned char (부호 없는 정수, 0~255) 데이터 타입에서 255를 초과하는 값인 256을 저장하려고 하면, 오버플로우가 발생하고 결과 값이 0부터 다시 시작하게 된다. 이는 명백한 데이터 손실이며 프로그램에 치명적인 오류를 가져다줄 수 있다. 그러나 이러한 오류에도 불구하고 Data type의 명시적 활용은 컴퓨터의 동작에 매우 효율적이고 필수적이므로, 개발자들은 데이터타입을 채택하여 효율적인 프로그래밍을 하면서도 오버플로우가 발생하지 않도록 다양한 조치들을 취하고 있다.
1. 오버플로우 구현
간단한 C 프로그램을 통해 오버플로우를 구현하고 확인해 보자. 우선 limits.h 라는 헤더 파일을 참조할 것이다. 이 헤더 파일은 시스템에서 사용 가능한 데이터 타입의 범위와 특성에 관한 정보를 제공해 준다. char 데이터 타입의 최댓값을 헤더 파일의 정보를 통해 확인해 보고, 오버플로우를 발생시킨 뒤, gdb 디버거로 이를 살펴보자.
#include <stdio.h>
#include <limits.h>
int main(void){
char value = CHAR_MAX;
printf("%d\n",value); //127
value += 1;
printf("%d\n", value); //-128
return 0;
}
각 줄을 실행해보며 overflow 전 후의 value 변수의 값을 2진수로 확인한다. value 값의 변화는 다음과 같다.
Overflow 전 = 0111 1111 (127)
Overflow 후 = 1000 0000 (-128)
이진수로만 따졌을 때는 단순히 1이 더해졌으니 연산 자체는 틀리지 않았지만, 결괏값은 Char형의 데이터 타입 범위를 넘어서게 된다. 그러면서 가장 앞의 1이 부호 비트로써 작용하게 되며, 2의 보수 표현에 의해 가장 작은 음수인 -128이라는 결과가 되는 것이다.
2. 언더플로우 구현
언더플로우의 경우도 살펴보면 다음과 같다. (Underflow라는 표현에 대해 정확성 논란이 있지만, 편의상 '표현할 수 있는 가장 작은 수보다 작은 수를 저장할 때'를 지칭하고자 한다.) 이번에는 value 변수에 가장 작은 수인 CHAR_MIN 값을 대입해 본다.
#include <stdio.h>
#include <limits.h>
int main(void){
char value = CHAR_MIN;
printf("%d\n",value); //-128
value += 1;
printf("%d\n", value); //127
return 0;
}
`
Underflow 전 = 1000 0000 (-128)
Underflow 후 = 0111 1111 (127)
정 반대의 결과가 나타나는 것을 알 수 있다. 마찬가지로 2진수 연산은 올바르지만, 부호비트의 변화와 함께 데이터가 완전히 바뀌어버렸다.
간단한 예제를 통하여 오버플로우를 구현해 보며 오버플로우에 대한 기본적 이해를 높여보았다. 실제로 컴퓨터가 막 발전을 시작하던 과거에, 오버플로우는 심각한 exploit으로써 다수의 이용자들을 위협하였다. 현재는 다양한 컴퓨터 보안 기술과 개발자들의 노력으로 많은 측면에서 오버플로우의 위험성이 완화되었지만, 여전히 주의해야 할 중요한 문제임에는 틀림없다.
소중한 의견, 피드백 감사합니다😊
'Study > Computer Science' 카테고리의 다른 글
[2진수,비트연산] 비트연산으로 비트를 끄고 켜보자! (0) | 2023.09.15 |
---|