[Java] 정수 오버플로우(Integer overflow)

🌈 M1naWorld ·2022년 11월 13일
2

자바를 잡아! 👻

목록 보기
14/19
post-thumbnail

정수 오버플로우(Integer overflow)

산술 연살을 할 때 주의할 점은 표현 가능한 산출 타입인지 확인해야 한다. 산출 타입으로 표현할 수 없는 값인 경우 오버플로우가 발생하여 쓰레기 값이 반환된다. 쉽게 말해, 정수형 오버플로우는 정수 값이 증가하면서 허용된 가장 큰 값보다 커져 실제 저장되는 값이 의도치 않게 아주 작은 수 이거나 음수가 되는 것이다. 특히 반복문 제어, 메모리 할당, 메모리 복사 등을 위한 조건으로 사용자가 제공하는 입력값을 사용하고 그 과정에서 정수형 오버플로우가 발생하는 경우 보안상 문제를 유발 할 수 있다.

// 정수 오버플로우 예시

public class OverflowEx{

	public static void main(String[] args){
    
    	int x = 50000;
        int y = 50000;
        
        int z = x * y;
        System.out.println(z); // -1794967296
    }
}

변수 x, y, z 모두 int 타입이다. 컴파일 에러도 없지만 변수 z에 예상한 값이 저장되지 않았다. 그 이유는 int 타입 범위를 초과하였기 때문인데, 올바른 값을 얻기 위해서는 변수가 long 타입이어야 한다.

정수형 오버플로우는 컴파일러가 오버플로우를 무시하기 때문에 잘못된 값이 저장될 뿐, 문제가 발생하여도 발생했는지 발견할 수 없기 때문에 매우 위험하다. 만약 정수형 오버플로우가 발생하더라도 프로그램은 수행 결과가 올바른지 알 수 없지만 정해진 연산을 처리할 것이다. 이러한 잘못된 결과는 프로그램의 오작동을 발생할 수 있으며, 보안에 취약한 부분을 내포하게 된다.
(*언더 플로우란, 오버플로우의 반대 개념으로 최소 범위보다 작은 수를 발생시키는 경우 발생하는 현상으로 언더플로우의 문제 또한 오버플로우와 같다.)


❗️ 오버플로우를 고려한 안전한 코딩기법

  • 언어・플랫폼별 정수 타입의 범위를 확인하여 사용한다.
  • 정수형 변수를 연산에 사용하는 경우 결과 값의 범위를 체크하는 모듈을 사용한다.
  • 외부입력값을 동적 메모리 할당에 사용하는 경우, 변수값이 적절한 범위 내에 존재하는지 값인지 확인한다.

위의 3가지를 고려하여 코드를 짠다면 오버플로우를 방지할 수 있다.

- 허용범위 확인
각 타입별 허용 범위는 각 타입별 클래스의 MIN_VALUE(최소값), MAX_VALUE(최대값) 메소드를 통해 타입의 범위를 확인할 수 있다.

System.out.println("char: " + (int)Character.MIN_VALUE + " ~ " + (int)Character.MAX_VALUE);
System.out.println("byte: " + Byte.MIN_VALUE + " ~ " + (int)Byte.MAX_VALUE);
System.out.println("short: " + Short.MIN_VALUE + " ~ " + Short.MAX_VALUE);
System.out.println("int: " + Integer.MIN_VALUE + " ~ " + Integer.MAX_VALUE);
System.out.println("long: " + Long.MIN_VALUE + " ~ " + Long.MAX_VALUE);
System.out.println("float: " + Float.MIN_VALUE + " ~ " + Float.MAX_VALUE);
System.out.println("double: " + Double.MIN_VALUE + " ~ " + Double.MAX_VALUE);

// 결과값 
char: 0 ~ 65535
byte: -128 ~ 127
short: -32768 ~ 32767
int: -2147483648 ~ 2147483647
long: -9223372036854775808 ~ 9223372036854775807
float: 1.4E-45 ~ 3.4028235E38
double: 4.9E-324 ~ 1.7976931348623157E308

- BigInteger 클래스 활용
Java에서는 이런 정수 타입의 저장 한계를 극복하기 위해 BigInteger 클래스를 제공하고 있다. BigInteger 클래스는 정수를 문자열 형태로 저장하기 때문에 메모리가 부족하지 않은 이상 무한한 숫자를 저장할 수 있다.

  • BigInteger 선언 및 생성
BigInteger bigInteger1 = new BigInteger("1234");
BigInteger bigInteger2 = BigInteger.valueOf("1234");
  • BigInteger 연산
BigInteger bigInteger1 = new BigInteger("123");
BigInteger bigInteger2 = new BigInteger("234");

// 더하기
System.out.println(bigInteger1.add(bigInteger2));
// 빼기
System.out.println(bigInteger1.subtract(bigInteger2));
// 곱하기
System.out.println(bigInteger1.multiply(bigInteger2));
// 나누기
System.out.println(bigInteger1.divide(bigInteger2));
// 나머지
System.out.println(bigInteger1.remainder(bigInteger2));
  • 타입 변환
int intNum = bigInteger.intValue(); // int 타입으로 변환
long longNum = bigInteger.longValue(); // long 타입으로 변환
float floatNum = bigInteger.floatValue(); // float 타입으로 변환
double doubleNum = bigInteger.doubleValue(); // double 타입으로 변환
String stringValue = bigInteger.toString(); // 문자열 타입으로 변환
  • 비교 연산
BigInteger bigInteger1 = new BigInteger("7777");
BigInteger bigInteger2 = new BigInteger("8888");
		
// 같으면 0, 입력한 인자가 더 크면 -1, 입력한 인자가 더 작으면 +1
int compare = bigInteger2.compareTo(bigInteger2);
System.out.println(compare);

- 예외 처리: Math 클래스 정적 메소드 활용
더 큰 값을 허용하지 않거나 오버플로가 발생하는 것을 원하지 않을 경우 예외를 던지고 싶은 경우,
Java8부터 정확한 산술 연산을 위해 Math클래스의 정적 메소드를 사용할 수 있음.
정적 메서드 Math.addExact()등은 작업 결과 오버플로우 또는 언더플로우가 발생하면 예외가 발생한다.

  • 예외를 발생시키는 메소드 종류 : 'Exact'가 포함된 메소드
// 인수값으로 int형 혹은 long형 값이 들어 올 수 있음

addExact(x, y) // x + y 
subtractExactTest(x, y) // x - y
Math.multiplyExactTest(x, y) // x * y
Math.incrementExact(a) // a++
Math.decrementExact(a) // a--
Math.negateExact(a) // -a
Math.toIntExact(x) // long 타입을 int로 변경
  • 사용 예제
int x = Integer.MAX_VALUE;
int y= 1;
System.out.println(Math.addExact(x, y)); //Exception in thread "main" java.lang.ArithmeticException: integer overflow 에러 발생

long x = Integer.MAX_VALUE;
long y= 1;
System.out.println(Math.addExact(x, y)); // 2147483648


Ref.
해답을 찾기위해...
Effective Data Engineering
Developer TABLE/Java
터프남 - Java Math 클래스 정적 메소드

profile
개발자로 사는 내 삶은 즐거워 👾

0개의 댓글