diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index d90a7a94..74dff429 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -50,5 +50,6 @@ jobs: - run: cargo fmt --all -- --check - run: cargo clippy --all -- -D warnings - - run: cargo clippy --target wasm32-unknown-unknown -- -D warnings + # test_utils requires tokio rt-multi-thread, which does not compile on wasm + - run: cargo clippy --workspace --exclude test_utils --target wasm32-unknown-unknown -- -D warnings - run: cargo test --all diff --git a/Cargo.lock b/Cargo.lock index 8fa03237..5d8ef91a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -346,7 +346,6 @@ dependencies = [ "test_utils", "tokio", "tracing", - "tracing-attributes", "url", "zip", ] @@ -690,26 +689,14 @@ dependencies = [ [[package]] name = "tracing" -version = "0.1.41" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" dependencies = [ "pin-project-lite", - "tracing-attributes", "tracing-core", ] -[[package]] -name = "tracing-attributes" -version = "0.1.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "tracing-core" version = "0.1.36" @@ -733,9 +720,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.20" +version = "0.3.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2054a14f5307d601f88daf0553e1cbf472acc4f2c51afab632431cdcd72124d5" +checksum = "cb7f578e5945fb242538965c2d0b04418d38ec25c79d160cd279bf0731c8d319" dependencies = [ "matchers", "nu-ansi-term", diff --git a/Cargo.toml b/Cargo.toml index 5b8be404..4bb49eb1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,7 @@ dyn-hash = { version = "^1.0", default-features = false } hashbrown = { version = "^0.17", features = ["default-hasher"], default-features = false } nom = { version = "^8.0", default-features = false, features = ["alloc"] } parking_lot = { version = "^0.12", default-features = false } -tracing = { version = "^0.1", default-features = false, features = ["attributes"] } +tracing = { version = "^0.1", default-features = false } tokio = { version = "^1.52", features = ["macros"] } diff --git a/REPORT.md b/REPORT.md index b9d26e9b..9c2b77fa 100644 --- a/REPORT.md +++ b/REPORT.md @@ -1,5 +1,19 @@ # REPORT +## [2026-07-22] tracing-attributes 상한 핀 제거 (rustjava-tracing-attributes-pin-removal) +- 무엇을: 워크스페이스 유일의 `#[tracing::instrument]`(thread.rs, "java thread" span)를 + `tracing::info_span!` + `Instrument` 수동 span 으로 대체하고, `java_runtime` 의 + `tracing-attributes <0.1.29` 직접 의존 핀과 workspace `tracing` 의 `attributes` 피처를 제거. + Cargo.lock 은 tracing 계열만 국소 갱신(tracing 0.1.41→0.1.44, subscriber 0.3.20→0.3.23, + tracing-attributes 그래프에서 소멸). wasm32 clippy CI 의 누락 커버리지도 교정 + (`--workspace --exclude test_utils` — test_utils 는 tokio rt-multi-thread 라 wasm 불가). +- 왜: 한 줄의 attribute macro 가 no_std 빌드를 깨는 탓(tokio-rs/tracing#3388)에 tracing 계열 + 전체가 동결됐고 dependabot PR 이 해석 불가로 계속 죽었음. +- 사용자 영향: tracing 계열 업데이트 재개 가능(보안 패치 포함). span 출력("java thread{id=N}" + 이름·필드·레벨·타깃)은 실행 대조로 동일함을 확인 — 관측 회귀 0. +- 후속 추천: ① dependabot 재시도 유도(다음 주기에 자동), ② javac 21 익명 내부 클래스 파싱 + 실패(Malformed) 원인 조사 별건, ③ wasm32 에서 test_utils 대체 테스트 전략 검토. + ## [2026-07-22] 클래스파일 파싱 실패 → ClassFormatError 전파 (rustjava-classfile-parse-error-propagation) - 무엇을: `ClassInfo::parse` 를 `Option` → `Result<_, ParseError>` 로 바꿔 실패 원인(절단/매직 불일치/미지원 상수풀 태그 N/기타 손상)을 담고, `from_classfile` 의 `unwrap()`/`assert_eq!` 를 diff --git a/STATE.md b/STATE.md index b3bcba31..528b972d 100644 --- a/STATE.md +++ b/STATE.md @@ -6,14 +6,14 @@ ## 완료 - [rustjava-runtime-time-todo-impl] RuntimeImpl 시간 API `todo!()` 3건 제거(now/sleep/yield) + test_utils `r#yield` 구현 + tokio `time` 피처 추가 + 회귀 잠금 픽스처(`test_data/TimeApi`). - ★게이트③ 진행: PR #2 approve 핀 `3afb6cc` 확인 → main(549b9eb) 충돌 해소(STATE/REPORT - superset, docs-only) 후 스쿼시 머지(2026-07-23). + ★게이트③ 완료: PR #2 스쿼시 머지 → main `13ab950`(2026-07-23), 브랜치 정리 완료. - [rustjava-classfile-parse-error-propagation] 클래스파일 파싱 실패를 패닉 대신 `java.lang.ClassFormatError` 로 전파(절단/매직 불일치/미지원 상수풀 태그 구분). ★게이트③ 완료: PR #3 스쿼시 머지 → main `549b9eb`(2026-07-23), 브랜치 정리 완료. - [rustjava-tracing-attributes-pin-removal] `#[tracing::instrument]` 1건을 수동 span 으로 대체, `tracing-attributes` 상한 핀 제거(tracing 0.1.41→0.1.44 언프리즈), wasm32 clippy CI 커버리지 - 교정. 브랜치 `tracing-attributes-pin-removal`, PR 게이트② 대기. + 교정. ★게이트③ 완료: PR #4 approve 핀 `0a19f38` 확인 → main 충돌 해소(docs-only) 후 + 스쿼시 머지(2026-07-23), 브랜치 정리 완료. - [rustjava-unsupported-charset-exception] 미지원 charset `unimplemented!()` 패닉 3지점을 `java.io.UnsupportedEncodingException`(신설) throw 로 전환, String↔InputStreamReader 지원 charset 을 공용 `charset::Charset` 으로 일치(ISO-8859-1/US-ASCII 가 Reader 에서도 동작). @@ -22,10 +22,9 @@ `unsupported-charset-exception`, PR #5 게이트② 대기. ## 다음 -- 잔여 PR 게이트② approve 후 머지: tracing-attributes-pin-removal, #5(unsupported-charset). - 브랜치 정리(`gh pr merge --delete-branch` → `git branch -D` → `git fetch --prune`) -- ★잔여 PR 도 STATE.md/REPORT.md add/add·수정 충돌 예상 — 선행 머지 후 후행 브랜치에 - `git merge main` 하고 최신(superset) 내용 채택으로 해소. +- 잔여 PR: #5(unsupported-charset) 게이트② approve 후 머지, 브랜치 정리 + (`gh pr merge --delete-branch` → `git branch -D` → `git fetch --prune`) +- ★#5 착지 전 후행 브랜치에 `git merge main` + superset 채택으로 STATE/REPORT 충돌 해소. - ★PR 발권 시 `--repo Jun025/RustJava` 명시(2026-07-22 upstream 오발행 사고 재발 방지). - (범위 밖 잔여) `jvm_rust/src/interpreter.rs:629` `todo!()` (invokedynamic) — 별건 티켓 필요 - (신규 발견) javac 21 산출 익명 내부 클래스(.class)가 "Malformed class file" 로 파싱 실패 — diff --git a/java_runtime/Cargo.toml b/java_runtime/Cargo.toml index f003fbd7..a50d3027 100644 --- a/java_runtime/Cargo.toml +++ b/java_runtime/Cargo.toml @@ -14,7 +14,6 @@ tracing = { workspace = true } chrono = { version = "^0.4", default-features = false } encoding_rs = { version = "^0.8", features = ["alloc"], default-features = false } -tracing-attributes = { version = "<0.1.29" } # Pin this to avoid compile error with no-std https://github.com/tokio-rs/tracing/issues/3388 url = { version = "^2.5", default-features = false } zip = { version = "^8.6", features = ["deflate"], default-features = false } diff --git a/java_runtime/src/classes/java/lang/thread.rs b/java_runtime/src/classes/java/lang/thread.rs index d40447d0..bde4cde5 100644 --- a/java_runtime/src/classes/java/lang/thread.rs +++ b/java_runtime/src/classes/java/lang/thread.rs @@ -4,6 +4,7 @@ use core::time::Duration; use java_class_proto::{JavaFieldProto, JavaMethodProto}; use java_constants::MethodAccessFlags; use jvm::{ClassInstanceRef, Jvm, Result, runtime::JavaLangString}; +use tracing::Instrument; use crate::{RuntimeClassProto, RuntimeContext, SpawnCallback, classes::java::lang::Runnable}; @@ -87,50 +88,57 @@ impl Thread { #[async_trait::async_trait] impl SpawnCallback for ThreadStartProxy { - #[tracing::instrument(name = "java thread", fields(id = self.thread_id), skip_all)] async fn call(&self) -> Result<()> { - tracing::trace!("Thread start"); - - self.jvm.attach_thread()?; - - let result: Result<()> = self.jvm.invoke_virtual(&self.this, "run", "()V", []).await; - - if let Err(jvm::JavaError::JavaException(x)) = result { - let string_writer = self.jvm.new_class("java/io/StringWriter", "()V", ()).await.unwrap(); - let print_writer = self - .jvm - .new_class("java/io/PrintWriter", "(Ljava/io/Writer;)V", (string_writer.clone(),)) - .await - .unwrap(); - - let _: () = self - .jvm - .invoke_virtual(&x, "printStackTrace", "(Ljava/io/PrintWriter;)V", (print_writer,)) - .await - .unwrap(); - - let trace = self - .jvm - .invoke_virtual(&string_writer, "toString", "()Ljava/lang/String;", []) - .await - .unwrap(); - - tracing::error!( - "Uncaught exception in thread {}:\n{}", - self.thread_id, - JavaLangString::to_rust_string(&self.jvm, &trace).await.unwrap() - ); - } else { - result?; + // manual span instead of #[tracing::instrument]: tracing-attributes breaks no_std + // builds (tokio-rs/tracing#3388), and this was the only use in the workspace + let span = tracing::info_span!("java thread", id = self.thread_id); + + async { + tracing::trace!("Thread start"); + + self.jvm.attach_thread()?; + + let result: Result<()> = self.jvm.invoke_virtual(&self.this, "run", "()V", []).await; + + if let Err(jvm::JavaError::JavaException(x)) = result { + let string_writer = self.jvm.new_class("java/io/StringWriter", "()V", ()).await.unwrap(); + let print_writer = self + .jvm + .new_class("java/io/PrintWriter", "(Ljava/io/Writer;)V", (string_writer.clone(),)) + .await + .unwrap(); + + let _: () = self + .jvm + .invoke_virtual(&x, "printStackTrace", "(Ljava/io/PrintWriter;)V", (print_writer,)) + .await + .unwrap(); + + let trace = self + .jvm + .invoke_virtual(&string_writer, "toString", "()Ljava/lang/String;", []) + .await + .unwrap(); + + tracing::error!( + "Uncaught exception in thread {}:\n{}", + self.thread_id, + JavaLangString::to_rust_string(&self.jvm, &trace).await.unwrap() + ); + } else { + result?; + } + + self.jvm.detach_thread()?; + + let mut this = self.this.clone(); + self.jvm.put_field(&mut this, "alive", "Z", false).await.unwrap(); + self.jvm.object_notify(&self.this, usize::MAX); + + Ok(()) } - - self.jvm.detach_thread()?; - - let mut this = self.this.clone(); - self.jvm.put_field(&mut this, "alive", "Z", false).await.unwrap(); - self.jvm.object_notify(&self.this, usize::MAX); - - Ok(()) + .instrument(span) + .await } }