Aug 26 2008

순수 자바를 이용하여 JVM을 죽게 하는 프로그램을 어떻게 짤까?

분류: Lang.Java 태그: ,, , , Heart @ 1:36 오전

Trackback : http://dev.heartsavior.net/archives/182/trackback/

순수 자바를 이용하여 JVM을 죽게 하는 프로그램을 어떻게 짜죠?

‘사랑하지 않으면 떠나라’ 의 한 챕터에서 제시하는, 자바 고급 프로그래머에 대한 면접 내용이다.

처음에 이 문제를 접했을 때 잠깐 착각을 해서 ‘순수 자바를 이용하여’ 라는 부분을 염두에 두지 못했다.

이 전제가 없으면 가장 편하게 생각할 수 있는 방법은 JNI 이다. JNI에서 C/C++ 라이브러리를 호출하고, 라이브러리 내부에서 런타임 에러로 crash 상태를 만들면(잘못된 메모리 참조 같은 쉬운 방법을 이용하자) JVM 도 crash 가 발생하게 된다. 견고한 JVM 을 피해서 돌아가는 답안이라고 할 수 있다. 그만큼 JNI 라이브러리를 작성할 때는 심혈을 기울여야 한다는 뜻이기도 하다.

하지만, ‘순수 자바를 이용하여’ 라는 전제가 붙는 것을 확인하고는 답을 낼 수 없었다. 자바 코드 내에서 발생하는 오류는 모두 Exception 이나 Error 로 잡힌다고 생각했던 것도 있고, JVM 내부는 공부해 본 적이 없기 때문이기도 했다.

그러다 오늘, 프로그래밍 갤러리에서 DriverManager Vulnerability 라는 글이 올라왔고, 약간의 논쟁 후에 immutable 속성인 String 클래스의 private field 를 수정하는 아이디어가 나타났다.
reflection을 몰라서 가능할 것이라고는 전혀 생각하지 못했다.
근데… reflection을 통해서 String 클래스의 private field 를 변경하는 글이 올라왔다. (첫번째 글 / 두번째 글)
이것 자체로도 나에게는 상당히 신기한 일이었다.
C/C++ 언어를 주로 다뤘던지라, 캡슐화는 견고함을 보장한다라고 생각을 하고 있었는데, reflection 으로 private field의 access 권한을 획득해버렸다.

근데, 첫번째 글의 결과를 보니… JVM이 죽었다!?

글에 적힌 crash 로그를 살펴보니 jre 1.5 버전이다.
같은 코드를 eclipse 에서 구현하여 해당 프로젝트의 JDK와 JRE를 1.5로 맞추었다.

String abc = "abc";
String def = "abc";
Field declaredField = String.class.getDeclaredField("value");
declaredField.setAccessible(true);
char[] abcArray = (char[]) declaredField.get(abc);
 
abcArray[0] = 'd';
 
System.out.println(def);

해당 코드를 호출했다. 역시, JVM이 crash되었다.

#
# An unexpected error has been detected by HotSpot Virtual Machine:
#
#  EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0×00aea4fc, pid=1764, tid=1672
#
# Java VM: Java HotSpot(TM) Client VM (1.5.0_16-b02 mixed mode, sharing)
# Problematic frame:
# j  net.heartsavior.dev.JVMDeath.crashJVMUsingStringObject()V+24
#
# An error report file with more information is saved as hs_err_pid1764.log
#
# If you would like to submit a bug report, please visit:
#   http://java.sun.com/webapps/bugreport/crash.jsp
#

뭐… 그래서 결론은 JVM 이 죽는 코드를 ‘구현했다’ 가 아닌 ‘발견했다’ 이고, 그나마 위의 코드는 1.6에서는 통하지 않는다…;;
위의 코드를 1.6에서 돌리면 정상적으로(라고 해야될라나) ‘def’ 가 출력된다.
( 이게 1.5만의 버그인지, 1.5 이하 공통 버그였다가 1.6에서 수정된 것인지는 잘 모르겠다. 귀찮다;; )

ps. 잘 생각해 보면 1.6도 JVM 이 죽지 않는다 뿐이지, String 클래스가 immutable 에서 해방될 수 있다…
즉, ” ‘뻘짓을 하지 않고 정식 루트로 접근할 경우’ String 클래스는 immutable 이다 ” 라고 할 수 있겠다. -_-;;