Skip to content

fix: 라운드35 전수 감사 — 입력의 크기·깊이, 결함 16건 - #59

Merged
centwon merged 1 commit into
mainfrom
audit/round35-full
Sep 30, 2026
Merged

centwon merged 1 commit into
mainfrom
audit/round35-full

Conversation

@centwon

@centwon centwon commented Sep 30, 2026

Copy link
Copy Markdown
Owner

요약

라운드35 전수 감사. src 약 19,500줄을 모델 → 포매터 → 컨트롤 순으로 읽었다. 결함 16건을 찾았고, 모두 빨강 먼저 → 수정 → 개별 반증을 거쳤다. 대부분은 이전 라운드가 재지 않은 축, 즉 붙여넣거나 여는 입력이 얼마나 크고 깊을 수 있는가에서 나왔다.

프로세스 종료 (catch 불가)

입력 이전 이후
<div> 2,000겹 (11 KB HTML) 붙여넣기 스택 오버플로로 종료 0.4 s
<div>/<span> 20,000겹 종료 3.3 s (HtmlAgilityPack 파싱이 2.9 s)
중첩 표 400단 (RTF \itap, HTML) 렌더 중 종료 32단(RTF)·42단(HTML)으로 잘리고 글자는 보존
행 없는 인라인 표 (JSON) + → 키 처리기 밖으로 예외 빈 격자는 문서에서 제외

수정: DOM 128단 아래는 글자로 접는다(비재귀). HtmlAgilityPack의 id 색인은 끈다(그 서브트리 제거가 재귀였다). RTF 중첩은 32단까지만 읽는다.

데이터 소실

  • 인라인 표 셀로 끝나는 선택을 삭제하면 그 줄 전체가 지워졌다(표 뒤 글자와 표 자체까지). 드래그나 Shift+→로 재현된다. TextRange.CoveredSpan으로 삭제·복사 텍스트·서식 적용이 같은 규칙을 쓴다.
  • 호스트가 Document에 새 문서를 대입한 뒤 Ctrl+Z를 누르면 옛 파일이 돌아왔다. 이제 새 문서는 새 기록으로 시작한다. undo/redo 자체의 문서 교체는 기록을 유지한다.
  • 인라인 표가 글자와 섞인 한 문단을 붙여넣으면 표가 사라졌다.

보안

  • JSON/.flow 파일에 적힌 그림 MIME이 내보낸 HTML(클립보드 HTML 포함)의 <img src="data:…">에 그대로 들어가 onerror= 속성이 주입됐다. 읽을 때와 쓸 때 모두 검증한다.

메모리·시간

  • 픽셀 폭탄: 1.5 MB PNG(40000²)를 디코드하는 데 1.6 GB가 들었다(real Skia). DecodeToWidth는 더 나빠서 20000²에 2 GB였다. 이제 1억 픽셀 초과는 디코드하지 않는다.
  • 가져오는 표는 1,000열 / 25만 셀로 제한한다(JSON·RTF·HTML 공통). RTF IndexOf의 O(n²)는 사전으로 바꿨다.
  • .flow: 문서가 참조하는 그림 항목만 읽는다(63 KB 파일이 64 MB를 풀던 문제). 항목당 256 MB 상한.
  • 그 밖: HTML 한 행의 셀이 1,000개를 넘으면 예외 · ListLevel -1이면 HTML 내보내기 예외(복사도 실패) · InsertTable(-1, n) 예외 · 문단 안 <script>/<style> 소스가 본문으로 들어옴.

⚠ 확인이 필요한 결정

  • 그림 디코드 상한 1억 픽셀: 넘는 그림은 붙여넣기에서 거절되고, 이미 문서에 있는 것은 바이트만 보존하고 그리지 않는다. 200 MP 폰 사진이 여기에 걸린다.
  • 표 가져오기 1,000열 / 25만 셀, HTML DOM 128단, RTF 표 중첩 32단, .flow 그림 항목 256 MB.

검증

  • 빌드 경고 0 · unit 1287 + render 55 그린 · 퍼즈 500시드 1회 그린
  • Round35AuditTests 31건. 수정마다 되돌려 해당 테스트가 빨개지는지 확인했다. 깊이 관련 반증은 테스트 호스트를 죽이므로 별도 프로세스에서 시간 제한을 두고 돌렸다. 한 겹은 반증에서 초록으로 남아(id 색인은 20,000겹에서만 넘친다) 그 깊이의 사례를 추가했다.
  • 실측으로 기각한 후보: file:///%5C%5Chost UNC 우회(\\\host는 SMB를 타지 않음, 0 ms), 링크 셸 실행(http(s)만 연다).

포트(WinUIRichEditor)는 포매터가 같은 코드라 같은 결함이 있을 것으로 보지만, 아직 측정하지 않았다.

🤖 Generated with Claude Code

src 전체(약 19,500줄)를 모델 -> 포매터 -> 컨트롤 순으로 읽었다. 대부분 이전 라운드가
재지 않은 축: 붙여넣거나 여는 문서가 얼마나 크고 깊을 수 있는가.

프로세스 종료(catch 불가):
- HTML <div> 2,000겹(11 KB) -> WalkBlocks 스택 오버플로. DOM 128단 아래는 글자로 접기(비재귀),
  HtmlAgilityPack id 색인 끔(그 서브트리 제거가 재귀)
- 중첩 표 400단 -> 렌더 스택 오버플로, RTF \itap 무제한. RTF 중첩 32단
- 행 없는 인라인 표(JSON) -> 화살표에서 키 처리기 밖으로 예외. 빈 격자는 문서에서 뺌

데이터 소실:
- 인라인 표 셀로 끝나는 선택 삭제가 그 줄 전체(표 포함)를 지움 (TextRange.CoveredSpan)
- 호스트의 Document 대입 뒤 Ctrl+Z가 옛 파일을 되살림 -> 새 문서 = 새 기록
- 인라인 표 섞인 한 문단 붙여넣기가 표를 버림

보안: 파일의 그림 MIME이 내보낸/클립보드 HTML <img src>에 그대로 -> 속성 주입

메모리·시간: 픽셀 폭탄(1.5 MB -> 1.6 GB, real Skia) 1억 픽셀 상한 · 가져오는 표 1,000열/25만 셀 ·
.flow 미참조 항목 안 읽음(항목당 256 MB) · RTF IndexOf O(n^2) · HTML 넓은 행 예외 ·
ListLevel 범위(-1이면 HTML 내보내기 예외) · InsertTable 음수 · 문단 안 script/style

테스트: Round35AuditTests(31). 수정마다 개별 반증 — 깊이 반증은 별도 프로세스(호스트가 죽음).
unit 1287 + render 55, 퍼즈 500시드 그린.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@centwon
centwon merged commit 072b9fe into main Sep 30, 2026
4 checks passed
@centwon
centwon deleted the audit/round35-full branch September 30, 2026 21:44
centwon added a commit that referenced this pull request Sep 30, 2026
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
centwon added a commit that referenced this pull request Sep 30, 2026
* docs: 로드맵 — 라운드35 머지(#59), 상한값 사용자 확정

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix: 라운드35 후속 — 남겨 둔 4건 확정·수정

- JPEG 채움 바이트(FF FF)·길이 없는 마커를 세그먼트 길이로 읽어 프레임 헤더를 건너뜀
  -> 크기 (0,0) -> 1억 픽셀 상한 우회. 채움 바이트와 길이 없는 마커를 건너뜀
- RTF 세로 병합 2만 개(1.4 MB)에 29.6 s 멈춤: MergeCells가 매번 격자 전체 스캔.
  1x1 칸만인 범위는 기존 병합에 걸칠 수 없으므로 스캔 생략 -> 0.38 s (500x500 상한 끝 2.7 s)
- 앵커 셀이 중첩 표로 시작하면 병합한 글자가 그 표 안으로(TableCell.Para가 내려감)
- RTF 글꼴명의 ';'가 글꼴 표 항목을 끊음 -> 이름에서 뺌
- 기각: 구분선 Indent의 JSON 누락(메뉴로 못 바꾸고 렌더링도 안 씀)

반증: 수정마다 되돌려 빨강, 빠른 경로의 전제(병합 옆 1x1 범위·병합에 닿는 범위의 확장)도 반증.
unit 1293 + render 55, 퍼즈 500시드 그린.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
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