설명
int 곱셈을 먼저 수행한 뒤 결과를 long으로 변환하면, 곱셈 단계에서 이미 오버플로우한 값이 그대로 확장됩니다. 또한 타입 폭 이상의 시프트는 언어의 시프트 거리 처리 규칙 때문에 개발자가 의도한 값과 다른 결과를 만들 수 있습니다. 이는 계산 정확성 문제이며, 보안 영향은 잘못된 결과가 크기 제한이나 접근 판단 등에 사용되는지에 따라 달라집니다.
잠재적 영향
- 크기, 개수, 인덱스 계산 결과가 잘못될 수 있습니다.
- 비트 마스크와 플래그가 의도와 다르게 계산될 수 있습니다.
- 잘못된 중간 결과가 이후 로직에 전파되어 예측하기 어려운 동작을 만들 수 있습니다.
해결 방법
- 곱셈 전에 피연산자 중 하나를
long으로 변환합니다. - 오버플로우를 오류로 처리해야 한다면
Math.multiplyExact를 사용합니다. - 시프트 거리가 대상 타입의 비트 폭보다 작은지 확인합니다.
- 더 넓은 결과가 필요하다면 시프트 전에 값을 적절한 타입으로 변환합니다.
예시
곱셈 결과 확장
변경 전
java
public long calculateSize(int itemCount, int itemSize) {
return (long) (itemCount * itemSize);
}
변경 후
java
public long calculateSize(int itemCount, int itemSize) {
return (long) itemCount * itemSize;
}
설명:
- 변경 전: 캐스팅 전에
int곱셈이 수행되므로 중간 결과가 이미 오버플로우할 수 있습니다. - 변경 후: 피연산자를 먼저
long으로 변환하여 곱셈 전체를long범위에서 수행합니다.
시프트 연산
변경 전
java
public int buildMask(int flags) {
return flags << 32;
}
변경 후
java
public long buildMask(int flags) {
return ((long) flags) << 32;
}
설명:
- 변경 전: Java의
int시프트 거리는 하위 5비트만 사용하므로32만큼의 시프트가 개발자의 기대와 다르게 처리됩니다. - 변경 후: 값을
long으로 먼저 변환하여 64비트 계산으로 수행합니다.