Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
21 changes: 4 additions & 17 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"] }

Expand Down
14 changes: 14 additions & 0 deletions REPORT.md
Original file line number Diff line number Diff line change
@@ -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!` 를
Expand Down
13 changes: 6 additions & 7 deletions STATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 에서도 동작).
Expand All @@ -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" 로 파싱 실패 —
Expand Down
1 change: 0 additions & 1 deletion java_runtime/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }

Expand Down
92 changes: 50 additions & 42 deletions java_runtime/src/classes/java/lang/thread.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};

Expand Down Expand Up @@ -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
}
}

Expand Down
Loading