블로그

R8 컴파일러 버그 수정 완료, 신고 4일 만에 릴리스 브랜치까지 반영됨

로또 1등보다 낮은 확률로 만난 키보드 앙의 R8 VerifyError가 수정되어 9.3·9.4·9.5 브랜치에 반영됨. 수정 빌드로 Android 10과 16에서 직접 확인함.

신고했던 R8 컴파일러 버그가 수정됐습니다. 신고 당시의 상황은 이전 글에 적었습니다. 이슈를 올린 지 4일 만이고, 수정은 R8 main 브랜치뿐 아니라 9.3, 9.4, 9.5 릴리스 브랜치에도 반영됐습니다. 이슈 573664753의 상태도 Fixed로 바뀌었습니다.

신고부터 수정까지

이슈는 P1로 분류됐고, 진행은 다음과 같았습니다.

10월 15일 15시 21분 신고, 약 2시간 뒤(17시 37분): R8 메인테이너가 담당자로 지정되어 덤프를 비공개로 보내 달라고 요청함

10월 16일 0시 39분(신고 약 9시간 뒤): 덤프 없이 문제를 재현하는 테스트 커밋이 이슈에 연결됨. 그래서 덤프는 보내지 않음

10월 19일 18시 8분(재현 커밋 3일 17시간 뒤): 수정 커밋이 연결되고 이슈가 Fixed로 바뀜. 같은 날 직접 검증한 결과를 이슈에 남김

10월 19일 21시 41분: 수정이 9.5, 9.4, 9.3 브랜치로 옮겨졌다는 알림이 올라옴

원인과 수정

문제는 레지스터 할당기가 겹치는 long 레지스터 쌍을 옮기는 순서였습니다. 한 쌍(v6:v7)을 읽기 전에 다른 값(v5:v6)이 하위 절반인 v6를 먼저 덮어써서 ART 검증기가 클래스를 거부했습니다. 수정 커밋의 제목은 다음과 같습니다.

Fix registor allocator clobbering live wide register pair

제목 그대로 살아 있는 wide 레지스터 쌍을 덮어쓰는 문제를 고친 커밋입니다. 바뀐 파일은 레지스터 이동을 순서대로 처리하는 RegisterMove.java와 RegisterMoveScheduler.java이고, 테스트 두 개가 함께 들어갔습니다. 커밋은 5de2ece, 리뷰는 r8-review 141000에서 볼 수 있습니다.

직접 확인한 결과

수정이 나오면 검증해서 알려 주겠다고 했던 대로, CI 프리빌트(5de2ece, raw/main)로 직접 확인했습니다. 처음 신고에 사용한 컴파일러 입력 덤프를 이 빌드로 다시 컴파일하자 androidx.compose.material3.TextKt의 문제 구간에서 덮어쓰는 move-wide가 사라졌고, 같은 메서드 시그니처는 그대로 남아 있었습니다.

이어서 우회 keep 규칙 없이 앱을 다시 빌드해 두 기기에서 확인했습니다.

Android 10 (API 29): cmd package compile -m verify로 전체 검증을 돌려 거부되는 클래스가 없었고 앱이 정상 실행됨

Android 16 (API 36): 시작하자마자 VerifyError로 종료되던 증상이 사라졌고 키보드 입력도 정상 동작함

릴리스 브랜치 반영

AGP 9.4와 9.5가 수정을 받을 수 있는지 물었고, 수정이 세 브랜치로 옮겨졌습니다.

9.5 브랜치: 버전 9.5.27 커밋과 함께 수정이 들어갔고, 이후 재현 테스트 파일의 컴파일 실패를 고치는 커밋과 버전 9.5.28 커밋이 추가됨(R8 본체가 아니라 테스트 파일 문제)

9.4 브랜치: 수정과 버전 9.4.33 커밋이 들어감

9.3 브랜치: 수정과 버전 9.3.34 커밋이 들어감

다만 브랜치에 커밋이 들어간 것이고, 이 R8이 들어간 AGP가 언제 배포되는지는 아직 알 수 없습니다.

우회 규칙은 아직 유지

수정된 R8이 포함된 AGP가 나오기 전까지는 신고 때 적어 둔 우회 규칙을 계속 사용합니다.

-keepclasseswithmembers class androidx.** { @androidx.compose.runtime.Composable <methods>; }
-keepclassmembers class androidx.** { @androidx.compose.runtime.Composable <methods>; }

참고

수정된 R8이 들어간 AGP가 나오면 이 규칙을 빼고, Android 10 기기에서 앱 전체 검증으로 거부되는 클래스가 없는지 한 번 더 확인할 예정입니다.