증상
samples/hwp3-sample16.hwp (2.9 MB, 64쪽 RFP 문서, 한국수자원공사 2004.11) 를 rhwp-studio 에서 열면 다음 panic 발생:
panicked at library/alloc/src/raw_vec/mod.rs:28:5: capacity overflow
[main] 파일 로드 실패: RuntimeError: unreachable
한컴오피스에서는 정상 오픈됨.
환경별 차이
| 환경 |
결과 |
| rhwp-studio (WASM, 32-bit) |
Rust panic: RawVec capacity overflow → wasm unreachable trap |
네이티브 CLI (rhwp dump, 64-bit) |
Graceful Err: HWP 파싱 실패 - 유효하지 않은 파일: HWP 3.0 오류: 입출력 오류가 발생했습니다: failed to fill whole buffer |
| 다른 HWP3 샘플 (sample14 등) |
정상 |
같은 코드가 32-bit/64-bit 메모리 가용성에 따라 panic / Err 로 갈림.
근본 원인 (probe binary 로 추적)
1차: 거대 length 할당
src/parser/hwp3/records.rs:413 — Hwp3AdditionalInfoBlock::read:
let length = reader.read_u32::<LittleEndian>()?;
let mut data = vec![0u8; length as usize]; // ← panic 지점
probe 실측: decompressed body offset 15131 위치에서
id u32 = 0x00000002
length u32 = 0xDC000000 = 3,690,987,520 (~3.69 GB)
32-bit WASM 메모리 한계 초과 → RawVec capacity overflow.
2차 (상위): 파라그래프 리스트 조기 종료
- decompressed body 크기: 16,199,028 바이트 (16.2 MB, 64쪽 분량)
- HWP3 파서 인식 paragraph 수: 1개 (
cc=5, lc=1 — 표지 picture 포함)
- 나머지 16.18 MB 가 통째로
additional_info_blocks 영역으로 잘못 진입
- 첫 picture(
ch=11) 처리 후 cursor alignment 가 misalign 되어, 정상 paragraph 헤더 자리에 발견된 00 00 00 ... 패턴이 char_count=0 end marker 로 오인됨
의심 코드: HWP3 picture(ch=11) 처리
src/parser/hwp3/mod.rs:929-933:
let n_ext_from_buf = (&info_buf[0..4]).read_u32::<LittleEndian>().unwrap_or(0);
let n_ext = n_ext_from_buf;
let mut ext_buf = vec![0u8; n_ext as usize];
if let Err(_) = body_cursor.read_exact(&mut ext_buf) { break; }
- sample16 실측:
info_buf[0..4] = 00 00 00 00 → n_ext = 0 (이 위치 자체는 sample16 에서 무해)
- 그러나
ext_buf 는 pic_type == 3 (drawing object) 일 때만 실제 사용됨에도 무조건 할당+read 함
- 이후 mod.rs:978 의
caption_paras = parse_paragraph_list(...) 재귀 호출의 byte alignment 가 정확하지 않을 가능성 (sample16 의 표지 picture 가 한컴 편집기에서 정상 표시되는 것으로 보아 file 자체는 valid HWP3)
probe 추적 detail
body_data.len() = 16199028
font_faces (7 lang) 정상 파싱: 끝 pos = 2694
nstyles = 51, 정상 파싱: 끝 pos = 14834
paragraph list start = 14834
para[0] @ 14834: cc=5, lc=1, end_pos = 15088
end marker @ 15088 (cc=0) ← 조기 종료
after paragraphs pos = 15131 (43 bytes end marker 소비)
additional_info_block[0] @ 15131:
id = 2
length = 0xDC000000 = 3690987520 ← garbage, panic 유발
bytes: [02 00 00 00] [00 00 00 dc] 0a f5 03 00 00 00 00 01 00 12 ff 94 fe ...
재현 방법
cargo run --release --bin rhwp -- dump samples/hwp3-sample16.hwp
# → "HWP 파싱 실패 - 유효하지 않은 파일: HWP 3.0 오류: 입출력 오류가 발생했습니다: failed to fill whole buffer"
# 또는 rhwp-studio 에서 samples/hwp3-sample16.hwp 파일 열기
# → "파일 로드 실패: RuntimeError: unreachable"
samples/hwp3-sample16.hwp 는 작업지시자가 추가한 새 샘플 (현재 미커밋). samples/hwp3-sample16-hwp5.hwp / samples/hwp3-sample16-hwp5.hwpx 는 동일 문서의 한컴 HWP5/HWPX 변환본이며 비교용.
수정 방향 (제안)
- 방어적 할당 가드 (즉시 효과):
Hwp3AdditionalInfoBlock::read 와 mod.rs:932 (picture ext_buf) 에서 length/n_ext 가 남은 stream 크기보다 크면 Err 반환. ch=29 (mod.rs:1119) 에는 이미 < 1000000 검증 존재 — 동일 패턴 적용.
- WASM panic hook 강화:
console_error_panic_hook 등록 (이미 panic 시 stack 일부 노출되므로 부분적으로 동작 중인 것으로 보임), Vec::try_with_capacity 또는 try_reserve 사용으로 panic → Err 변환.
- 상위 원인 해결: HWP3 picture(ch=11) 처리에서 ext_buf 읽기를
pic_type == 3 일 때만 수행하도록 변경. 그리고 첫 paragraph 의 byte consumption 검증 (실제 sample16 body 가 어디까지 사용되어야 정합한지 spec 재확인).
관련 파일
증상
samples/hwp3-sample16.hwp(2.9 MB, 64쪽 RFP 문서, 한국수자원공사 2004.11) 를 rhwp-studio 에서 열면 다음 panic 발생:한컴오피스에서는 정상 오픈됨.
환경별 차이
RawVec capacity overflow→ wasmunreachabletraprhwp dump, 64-bit)HWP 파싱 실패 - 유효하지 않은 파일: HWP 3.0 오류: 입출력 오류가 발생했습니다: failed to fill whole buffer같은 코드가 32-bit/64-bit 메모리 가용성에 따라 panic / Err 로 갈림.
근본 원인 (probe binary 로 추적)
1차: 거대 length 할당
src/parser/hwp3/records.rs:413 —
Hwp3AdditionalInfoBlock::read:probe 실측: decompressed body offset 15131 위치에서
id u32 = 0x00000002length u32 = 0xDC000000= 3,690,987,520 (~3.69 GB)32-bit WASM 메모리 한계 초과 →
RawVeccapacity overflow.2차 (상위): 파라그래프 리스트 조기 종료
cc=5, lc=1— 표지 picture 포함)additional_info_blocks영역으로 잘못 진입ch=11) 처리 후 cursor alignment 가 misalign 되어, 정상 paragraph 헤더 자리에 발견된00 00 00 ...패턴이char_count=0end marker 로 오인됨의심 코드: HWP3 picture(ch=11) 처리
src/parser/hwp3/mod.rs:929-933:
info_buf[0..4] = 00 00 00 00 → n_ext = 0(이 위치 자체는 sample16 에서 무해)ext_buf는pic_type == 3(drawing object) 일 때만 실제 사용됨에도 무조건 할당+read 함caption_paras = parse_paragraph_list(...)재귀 호출의 byte alignment 가 정확하지 않을 가능성 (sample16 의 표지 picture 가 한컴 편집기에서 정상 표시되는 것으로 보아 file 자체는 valid HWP3)probe 추적 detail
재현 방법
samples/hwp3-sample16.hwp는 작업지시자가 추가한 새 샘플 (현재 미커밋).samples/hwp3-sample16-hwp5.hwp/samples/hwp3-sample16-hwp5.hwpx는 동일 문서의 한컴 HWP5/HWPX 변환본이며 비교용.수정 방향 (제안)
Hwp3AdditionalInfoBlock::read와mod.rs:932(picture ext_buf) 에서length/n_ext가 남은 stream 크기보다 크면 Err 반환.ch=29(mod.rs:1119) 에는 이미< 1000000검증 존재 — 동일 패턴 적용.console_error_panic_hook등록 (이미 panic 시 stack 일부 노출되므로 부분적으로 동작 중인 것으로 보임),Vec::try_with_capacity또는try_reserve사용으로 panic → Err 변환.pic_type == 3일 때만 수행하도록 변경. 그리고 첫 paragraph 의 byte consumption 검증 (실제 sample16 body 가 어디까지 사용되어야 정합한지 spec 재확인).관련 파일
Hwp3AdditionalInfoBlock::readparse_hwp3