Skip to content

[rustjava-error-path-string-array-hiding-overflows-stack-p1] docs(jvm): cap 은 이 재귀를 «끝낸다» — 지난 회차 원인 기재를 반증한다 - #88

Merged
Jun025 merged 2 commits into
mainfrom
feat/rustjava-string-array-overflow-investigation
Sep 20, 2026
Merged

Jun025 merged 2 commits into
mainfrom
feat/rustjava-string-array-overflow-investigation

Conversation

@Jun025

@Jun025 Jun025 commented Sep 20, 2026

Copy link
Copy Markdown
Owner

채택 제안 2026-09-20-error-path-class-closure#p1 — ★조사 회차(「고쳐라」가 아니라 「알아내라」). ★제품 코드 0줄 · 고친 것은 스윕 헤더의 거짓 문장 하나다.

재현 — 했다

origin/main 97707f26 · cap 20 · 기본 스택 ⇒ thread 'probe' has overflowed its stack / fatal runtime error: stack overflow, aborting · rc 134.

★★결론 — 지난 회차가 적은 «원인»이 틀렸다

종전 문안: 「its recursion does not come back through the loader, so the cap cannot end it」

반증됐다. 매 턴 로더로 돌아오고, cap 이 끝낸다 — 살아남은 전 실행에서 asked = cap + 1, 즉 ★**[C 가 보이는 바로 그 모양이다. 넘치는 이유는 모양이 아니라 ★턴당 비용**이다.

두 손잡이가 «따로» 임계를 움직인다 — 이 한 실험이 「무한」과 「유한하지만 깊다」를 가른다(무한이면 둘 다 안 움직인다):

손잡이 고정 결과
cap 스택 2 MiB 18 생존(asked=19) ↔ ★19 오버플로
스택 cap 20 2 MiB 오버플로 ↔ ★4 MiB 생존(asked=21) · 8/32/128 MiB 도 생존

순환 — 추측이 아니라 백트레이스(계측은 되돌렸다 · 추적 0)

fill_in_stack_trace
 └ instantiate_array("Ljava/lang/String;")
    └ resolve_class → resolve_class_internal → load_class      ← 로더가 None(숨김)
       └ exception("java/lang/NoClassDefFoundError", …)
          └ new_class → invoke_special ×4
             (NoClassDefFoundError → LinkageError → Error → Throwable.<init>)
             └ init_with_message → invoke_virtual "fillInStackTrace"
                └ fill_in_stack_trace                           ← 같은 자리, 다음 턴

한 턴 ≈ 57 프레임. [CJavaLangString::from_rust_string 안에서 도는 훨씬 짧은 경로라 같은 2 MiB 에 20턴이 들어간다. ⇒ ★[Ljava/lang/String;「배열이라서」가 아니라 「오류 경로의 더 깊은 곳에서 필요해서」 비싸다.

「이 타입이 특별한가」 — 대조로 답했다 (cap 20)

숨긴 이름 결과
[C 재귀 · asked=21 · 생존
[Ljava/lang/String; 재귀 · 2 MiB 오버플로 / 4 MiB asked=21
[B Option::unwrap() 패닉 — ★bootstrap_classes 소속이라 형제 #p0 의 결함(이 회차 아님)
[I · [Ljava/lang/Object; · [Ljava/lang/StackTraceElement; · java/lang/Integer · java/lang/StringBuilder asked=0 · 구성 성공(묻지도 않는다)

cap 20 의 출처

jvm/tests/test_error_path_class_sweep.rsconst GIVE_UP_AFTER: u32 = 20test_utils::test_jvm_hidingHidesOneClass.give_up_after. ★테스트 전용 상수 — ★제품에는 상한이 없다.

무엇을 바꿨나 · 무엇을 안 바꿨나

  • 바꾼 것: 스윕 헤더의 거짓 문단 → 측정된 내용으로 교체.
  • 안 바꾼 것: 배열 제외 유지. 그 근거는 원래부터 「로더가 합성하므로 어떤 클래스 집합도 배열을 빠뜨릴 수 없다」였고 ★이번 측정과 무관하게 유효하다.
  • 개악 양방향 = 해당 없음(동작 무변경). 이 회차를 참으로 만드는 것은 위 측정표다.

대가 · 남긴 것

새 잠금 0. 순환은 ★제품에 바닥이 없는 채로 남는다 — 오늘 닿을 수 없을 뿐이다(클래스 집합 축은 Jvm::new 의 폐포 walk 가 닫았고, 배열은 합성된다). ⇒ 후속 카드 1건: 「Jvm::exception 에 바닥을 주라」(M · 형제 #p0 가 부딪친 JavaError 단일 변종 문제와 같이 결정해야 한다).

검증

DoD 9명령 rc 0. 호스트 부하: 빌드 1회(3m26s · 정본 체크아웃의 워밍된 target 재사용 — 콜드 빌드 ~11분을 피했다) · 프로브 실행 31회(전부 1초 미만).

worklog 쌍 = docs/worklog/2026-09-20-string-array-hiding-overflows-stack.{md,json} · adoptedProposals2026-09-20-error-path-class-closure#p1 축자 기록.

PR #87(형제 #p0)과 같은 파일(jvm/tests/test_error_path_class_sweep.rs)을 만진다 — 다른 문단이라 합집합이지만 착지 순서에 따라 손 해소가 필요할 수 있다.

🤖 Generated with Claude Code

jun0 and others added 2 commits September 20, 2026 20:55
…): cap 은 이 재귀를 «끝낸다» — 지난 회차 원인 기재를 반증한다

채택 제안 2026-09-20-error-path-class-closure#p1 (조사 회차 · 제품 코드 0줄).

재현했다: cap 20 · 기본 스택 → `stack overflow, aborting` rc 134.

그러나 원인 기재가 틀렸다. 「its recursion does not come back through the
loader, so the cap cannot end it」는 거짓이다 — 매 턴 로더로 돌아오고, 살아남은
모든 실행에서 `asked = cap + 1` 이다(= `[C` 가 보이는 그 모양).

두 손잡이가 따로 임계를 움직이므로 「유한하지만 깊다」로 확정된다(무한이면
둘 다 안 움직인다): cap 은 스택 2 MiB 고정에서 18 생존 ↔ 19 오버플로,
스택은 cap 20 고정에서 2 MiB 오버플로 ↔ 4 MiB 생존(asked=21).

순환은 백트레이스로 보였다(계측은 되돌렸다): fillInStackTrace →
instantiate_array("Ljava/lang/String;") → resolve_class → load_class(None) →
exception → new_class → invoke_special ×4 (NoClassDefFoundError → LinkageError
→ Error → Throwable.<init>) → init_with_message → invoke_virtual →
fillInStackTrace. 한 턴 ≈ 57 프레임이고, `[C` 는 from_rust_string 안에서 도는
짧은 경로라 같은 스택에 20턴이 들어간다. 차이는 모양이 아니라 턴당 비용이다.

대조(cap 20): `[C` 만 같이 돌고, `[I`·`[Ljava/lang/Object;`·
`[Ljava/lang/StackTraceElement;`·java/lang/Integer·java/lang/StringBuilder 는
asked=0 이다 ⇒ 「배열이면 난다」가 아니라 「오류 경로가 실제로 필요로 하는 두
배열」이다. (`[B` 는 bootstrap_classes 소속이라 형제 #p0 의 결함이다.)

배열 제외는 유지한다 — 그 이유(로더가 합성하므로 어떤 클래스 집합도 배열을
빠뜨릴 수 없다)는 이번 측정과 무관하게 유효하다.

개악 양방향: 해당 없음(동작을 바꾸지 않았다).
DoD 9명령 rc 0.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…igin/main — 승인된 원장 2파일 합집합

충돌은 REPORT.md·STATE.md 2건뿐(검수 예측 그대로)이고 둘 다 머리 append 다.
양쪽을 모두 남겼다 — 두 방향 모두 «병합본에 없는 줄 0» 으로 확인했다(#87 의
name-the-missing-bootstrap-class-p0 항목 · 이 회차의 string-array-hiding 항목).
jvm/tests/test_error_path_class_sweep.rs 는 자동 해소(충돌 0).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@Jun025
Jun025 merged commit 8c74bba into main Sep 20, 2026
13 checks passed
@Jun025
Jun025 deleted the feat/rustjava-string-array-overflow-investigation branch September 20, 2026 14:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant