From 4e20c12c3adff723374f5184ce4f548c6b7cf873 Mon Sep 17 00:00:00 2001 From: jun0 Date: Thu, 1 Oct 2026 10:04:08 +0900 Subject: [PATCH] =?UTF-8?q?[rustjava-zipfile-close-not-registered]=20feat(?= =?UTF-8?q?zip):=20ZipFile.close()=20=EB=93=B1=EC=9E=AC=20=E2=80=94=20?= =?UTF-8?q?=EB=AA=85=EC=8B=9C=20close=20=EC=99=80=20try-with-resources=20?= =?UTF-8?q?=EB=A5=BC=20ZipClose=20=ED=94=BD=EC=8A=A4=EC=B2=98=EB=A1=9C=20?= =?UTF-8?q?=EC=9E=A0=EA=B8=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 --- docs/worklog/2026-10-01-zipfile-close.json | 20 ++++++++++++++++++ docs/worklog/2026-10-01-zipfile-close.md | 12 +++++++++++ .../src/classes/java/util/zip/zip_file.rs | 10 +++++++++ test-data/ZipClose.class | Bin 0 -> 1255 bytes test-data/ZipClose.txt | 3 +++ test-data/class-file-versions.txt | 1 + test-data/src/ZipClose.java | 17 +++++++++++++++ test-data/src/ZipGuards.java | 2 +- 8 files changed, 64 insertions(+), 1 deletion(-) create mode 100644 docs/worklog/2026-10-01-zipfile-close.json create mode 100644 docs/worklog/2026-10-01-zipfile-close.md create mode 100644 test-data/ZipClose.class create mode 100644 test-data/ZipClose.txt create mode 100644 test-data/src/ZipClose.java diff --git a/docs/worklog/2026-10-01-zipfile-close.json b/docs/worklog/2026-10-01-zipfile-close.json new file mode 100644 index 00000000..c5a37b27 --- /dev/null +++ b/docs/worklog/2026-10-01-zipfile-close.json @@ -0,0 +1,20 @@ +{ + "schema": 1, + "date": "2026-10-01", + "title": "ZipFile.close() 등재", + "taskId": "rustjava-zipfile-close-not-registered", + "summary": "ZipFile.close()V 를 no-op 으로 등재하고 ZipClose 픽스처로 명시 close 와 try-with-resources 를 잠갔다. 착지한 카드 3건을 근거 커밋과 함께 닫았다.", + "proposals": [], + "adoptedProposals": [ + "2026-09-12-zip-getinputstream-guard-lock#p0", + "2026-08-27-upstream-sync-s3#p1", + "2026-09-17-lambda-capture-order-and-host-abort#p0", + "2026-09-16-cp-tags-15-18-parse#p1" + ], + "declinedProposals": [], + "closedBy": { + "2026-08-27-upstream-sync-s3#p1": "f19acf77 (#67)", + "2026-09-17-lambda-capture-order-and-host-abort#p0": "f19acf77 (#67)", + "2026-09-16-cp-tags-15-18-parse#p1": "dc035936 (#44)" + } +} diff --git a/docs/worklog/2026-10-01-zipfile-close.md b/docs/worklog/2026-10-01-zipfile-close.md new file mode 100644 index 00000000..c14a1e88 --- /dev/null +++ b/docs/worklog/2026-10-01-zipfile-close.md @@ -0,0 +1,12 @@ +## [2026-10-01] ZipFile.close() 등재 (rustjava-zipfile-close-not-registered) + +- 무엇을: `java/util/zip/ZipFile.close()V` 를 no-op 으로 등재했다. 픽스처 `ZipClose` 가 명시 `close()` 와 try-with-resources 를 둘 다 잠근다. +- 왜: `ZipFile` 을 닫는 평범한 게스트가 `NoSuchMethodError: java/util/zip/ZipFile.close:()V` 로 죽었다(픽스처로 재현). + javac 는 try-with-resources 를 자원의 정적 타입에 대한 `invokevirtual ZipFile.close` 로 컴파일하므로(javap 확인) `Closeable` 인터페이스 없이 이 한 메서드로 두 경로가 다 산다. +- 사용자 영향: zip/jar 을 읽고 닫는 게스트가 정상 종료한다. no-op 인 이유는 `` 이 아카이브 전체를 `zipData` 로 복사해 해제할 핸들이 없어서다. 그래서 close 뒤 읽기도 계속 되며, JDK 처럼 `IllegalStateException` 을 던지지는 않는다. + +양방향: 수정 전 `cargo test --test test_class` → `Test ZipClose failed … NoSuchMethodError: java/util/zip/ZipFile.close:()V` · 수정 후 ok. + +카드 정리: `2026-09-12-zip-getinputstream-guard-lock#p0` 채택(이 회차). 이미 착지한 것을 재측해 닫았다: +- `2026-08-27-upstream-sync-s3#p1` · `2026-09-17-lambda-capture-order-and-host-abort#p0` → PR #67 `f19acf77`(거부 사유가 `ClassFormatError` 메시지까지 간다) +- `2026-09-16-cp-tags-15-18-parse#p1` → PR #44 `dc035936`(ldc 15/16/17 이 「파손」이 아니라 「미지원」으로 보고됨 · javac 는 그 ldc 를 내지 않음을 실측) diff --git a/rustjava-runtime/src/classes/java/util/zip/zip_file.rs b/rustjava-runtime/src/classes/java/util/zip/zip_file.rs index f89c54f8..cd1ad7dc 100644 --- a/rustjava-runtime/src/classes/java/util/zip/zip_file.rs +++ b/rustjava-runtime/src/classes/java/util/zip/zip_file.rs @@ -44,6 +44,7 @@ impl ZipFile { MethodAccessFlags::PUBLIC, ), JavaMethodProto::new("entries", "()Ljava/util/Enumeration;", Self::entries, MethodAccessFlags::PUBLIC), + JavaMethodProto::new("close", "()V", Self::close, MethodAccessFlags::PUBLIC), ], fields: vec![JavaFieldProto::new("zipData", "[B", FieldAccessFlags::PRIVATE)], access_flags: ClassAccessFlags::PUBLIC, @@ -133,6 +134,15 @@ impl ZipFile { Ok(entries.into()) } + // No-op: copies the whole archive into `zipData` and every read reparses that array, + // so there is no file handle to release. Reads after close() keep working rather than + // throwing IllegalStateException as the JDK does. + async fn close(_: &Jvm, _: &mut RuntimeContext, this: ClassInstanceRef) -> Result<()> { + tracing::debug!("java.util.zip.ZipFile::close({this:?})"); + + Ok(()) + } + async fn get_input_stream( jvm: &Jvm, _: &mut RuntimeContext, diff --git a/test-data/ZipClose.class b/test-data/ZipClose.class new file mode 100644 index 0000000000000000000000000000000000000000..d7fd12f41a79494170f5526d21d8694adb0cb3f2 GIT binary patch literal 1255 zcmZ`(SyK~15dJ1vm}FUw1j3;pQ4|v(!~+iqULdHLfK{QW0(@{ureGo2-AX1L{vn?6 zAyi3~zWLxk@#6vX4vvsQgc(9LL@j8|+F>A~2sh*kPFV!e zg>H@>12=H%^DZv4k}1v5A=m+37~ayU%<2qc2D9WsP!=M$2GVXHfiE8+xEyXe zMDroq(!*7>e?w=uw~AXAjTtf=VPN?X_ril!#74p+RgC@u*Y=_Lt9Vq!6LKSE`#vJ` zC$ecmOY~?}q!K?>+*brRAQq!o#3~K*Grk~4(&up