[JAVA] TOCTOU : Time of Check to Time of Use

2025. 7. 28. 20:41Languages/JAVA

 

🦜 업무 또는 공부하다 마주친 문제에 대해서, 구글링을 해보며 공부한 내용입니다.

 

 

📝 TOCTOU : Time of Check to Time of Use

 

싱글 스레드가 아닌 멀티 스레드 환경에서, 하나의 리소스를 가지고 여러 스레드가 경쟁하는 상황이 발생할 수 있습니다. 만약 이런 경우는, Reentrant Lock, Synchronized 와 같이 비관적 락의 관점에서 접근하거나 Atomic 처럼 낙관적 락의 관점에서 어떻게 자원을 점유할지 고민할 수 있습니다. 그런데 이런 기법은 애플리케이션의 수준에서의 접근입니다.

 

만약 자원에 접근할 때, OS 수준까지 내려가면 어떻게 될까요? 이 때 발생할 수 있는 대표적인 문제 중 하나가 TOCTOU입니다.

 

String path = "(파일 경로)";
File myFile = new File(path);
if(myFile.exist()) {
	if(file.delete()) {
    //중략
    }
}

 

1) 파일이 경로에 있는지 확인하고, 2) 있는 경우 파일을 삭제하고 싶다면, 위와 같이 코드를 작성할 수 있습니다. 그런데 가끔 이럴 때 TOCTOU 문제가 발생하게 됩니다. 

 

TOCTOU란 무엇일까요? 위키피디아에서는 다음과 같이 소개하고 있습니다.

 

In software developmenttime-of-check to time-of-use (TOCTOUTOCTTOU or TOC/TOU) is

a class of software bugs caused by a race condition 

involving the checking of the state of a part of a system (such as a security credential)

and the use of the results of that check.

- 위키피디아(https://en.wikipedia.org/wiki/Time-of-check_to_time-of-use)

 

경쟁 조건(Race Condition)에서 발생할 수 있는 SW 버그로서, 1) check 하고 2) use 하는 시간 사이에 리소스의 상태가 바뀌면 발생할 수 있는 문제가 TOCTOU입니다.

 

예를 들어 파일을 생성하는 모듈과 파일을 다운로드하는 모듈이 나뉘어 있다고 생각해봅시다. 파일을 다운로드 받을 때 파일이 있는지 체크했는데, 이후 파일을 다운로드하려고 행동하니 파일이 없거나 다른 파일일 수 있습니다. 파일 생성하는 모듈에서 파일을 바꾸거나 새롭게 생성한 것이겠지요!

 

따라서 TOCTOU 문제를 회피하거나 문제가 발생하는 상황을 줄여보고 싶다면, 코드를 다음과 같이 작성할 수 있습니다.

String path = "(파일 경로)";
Path myPath = Paths.get(path);
if(Files.deleteIfExist(myPath)) {
	//중략
}

 

파일이 있다면 삭제하는 로직을 하나로 합치는 겁니다. 예를 들어, deleteIfExist()는 내부적으로 원자적 시스템 호출을 사용한다고 합니다. 

 

이렇게 코드를 작성해서, 최대한 TOCTOU를 막아보면 좋을 것 같습니다.

 

References

1. Time-of-check to time-of-use

'Languages > JAVA' 카테고리의 다른 글

[JAVA] 값 복사 vs 참조 복사  (0) 2025.02.25
[JAVA] Time  (1) 2025.02.20
[JAVA] Stream++  (1) 2024.10.05
[JAVA] Optional  (2) 2024.09.08
[JAVA] max()  (0) 2024.04.04