diff --git a/docs/HISTORY.md b/docs/HISTORY.md index b8f29f4..711858c 100644 --- a/docs/HISTORY.md +++ b/docs/HISTORY.md @@ -40,6 +40,7 @@ --- +### 9-70. 체크드 정수 산술 슬라이스 (2026-09-26, E2) — **`!` 본문의 오버플로가 `-3`이 됐다** → [본문](history/9-70.md) ### 9-69. §7을 열두 도메인으로 돌렸다 (2026-09-26, E2) — **가장 강한 근거는 체크드 산술이고, 그것은 설계 결정 하나에 걸려 있다** → [본문](history/9-69.md) ### 9-68. 상수 선언 슬라이스 (2026-09-26, E2) — **조용한 오독이 거부가 됐다** → [본문](history/9-68.md) ### 9-67. 잔여 작업과 상태 머신 예제 (2026-09-26, E2) — **상태 번호는 헤더와 지문 밖에 있었다** → [본문](history/9-67.md) diff --git a/docs/STATUS.md b/docs/STATUS.md index 17e87fb..73f6435 100644 --- a/docs/STATUS.md +++ b/docs/STATUS.md @@ -186,6 +186,8 @@ 본다. 상태 머신의 벽은 모듈 안이 아니라 거기 있었다(§9-67.2). - **조용한 오답은 기능에 귀속하기 전에 대조한다** — 그 기능이 있어도 같은 실수가 똑같이 쉬우면 근거가 아니다. 판정은 가드를 넣은 신중한 판이 아니라 가장 직접적인 형태로 한다. 이 둘이 1라운드 후보 다섯을 내렸다(§9-69.1). +- **심기의 결과는 `--no-fail-fast`로 읽는다.** `cargo test`는 첫 실패 바이너리에서 멈춰, 그 뒤 바이너리의 테스트는 + 돌지 않은 채 *"하나만 잡았다"* 처럼 보인다(§9-70.5). ### 7-1. 검증 절차 감사 (2026-09-03) — 왜 검증이 반복해서 헛돌았나 → [본문](history/status-7.md) ### 7-3. 한 세션을 실측으로 복기했다 (2026-09-11) — **네 가지가 반복해서 값을 잃었다** → [본문](history/status-7.md) @@ -225,25 +227,26 @@ > ## ▶ 여기서 시작한다 > -> ### 2026-09-26 기준 (3) — **§7을 열두 도메인으로 돌렸다: 가장 강한 근거는 체크드 산술이고, 설계 결정 하나에 걸려 있다 (§9-69)** +> ### 2026-09-26 기준 (4) — **체크드 정수 산술 슬라이스가 닫혔다: `!` 본문의 오버플로가 `-3`이 됐다 (§9-70)** > -> 72규칙을 한 기준과 귀속 대조로 쟀고, 1위 후보(체크드 정수 산술)를 버리는 브랜치에서 구현해 626행으로 다시 쟀다 — -> 조용한 오답 161행 중 84(A)~101(A+`as`)이 status가 되고, 기존 테스트의 동작은 하나도 바뀌지 않는다. 그 과정의 -> 결함들은 PR 셋으로 고쳤다(#329 · #330 · #331). +> §9-69가 잰 1위 후보를 슬라이스로 닫았다(#333 SPEC · #334 구현). `!` 본문의 i32 `+ - *`·단항 `-`·`MIN / -1`과 +> NaN·범위 밖 `f64 as i32`가 `ML_ST_OVERFLOW`(`-3`)를 내고, 실제 C 호스트가 그것을 받는다. 구현으로 다시 잰 +> 626행은 실험의 표와 같다(조용한 오답 161행 중 101이 status). 같은 날 Q17은 (A)로 열어 두고 위험을 +> `HOST_ABI.md`에 적었다(#335). > > **▶ 다음 세션 — 여기서 시작한다.** 순서대로: > -> 1. **체크드 정수 산술 — 구현 중.** DP-O1~O9 전부 사용자 확인(2026-09-26). `docs/slices/SPEC-checked-arithmetic.md` -> §6의 작업 1(codegen·바인딩·오라클 값·문서)이 들어갔고, **작업 2가 남았다** — 실제 C 호스트가 `-3`을 받는 수용 D, -> §9-69의 161행 재측정, 크기 변화, 그리고 슬라이스 닫기. +> 1. **다음 슬라이스 — 사용자 결정.** 후보의 정본은 `docs/slices/README.md`의 "다음 슬라이스" 절이다. 체크드 산술 뒤에 +> 남은 근거는 §9-70.2가 센다 — 여전히 조용한 60행(무한 헬퍼 16 · f64 절삭·NaN 14 · 산술이 아닌 것 25 …)과, +> `-3`이 됐지만 참값이 i32에 드는 43행(정답을 주는 것은 **i64**뿐이다). > 2. **작은 항목**: C# 호스트(Phase 4) · LSP(Phase 3, 큰 일). > 3. **외부**: `X1`·`X2` — Delphi가 있는 CI 러너. 이 저장소 안에서는 닫히지 않는다. > > ⚠ **이 머신의 전체 게이트는 6회 중 2회 실패한다**(§9-63.5) — 실패를 보면 먼저 원인을 읽는다. > 강한 신호는 CI 두 잡이다. > -> 📌 **본문은 §9-69다**(`docs/history/9-69.md`). 그 앞의 2026-09-26 (2) 항목(상수 선언)은 -> 바이트 그대로 옮겼다 — 지금은 `docs/history/start-block-050.md`다. +> 📌 **본문은 §9-70이다**(`docs/history/9-70.md`). 그 앞의 2026-09-26 (3) 항목(§7 열두 도메인)은 +> 바이트 그대로 옮겼다 — 지금은 `docs/history/start-block-051.md`다. > > > ### 그 앞의 항목들 — **본문은 `docs/history/start-block-NNN.md`로 옮긴다 (2026-09-23부터)** diff --git a/docs/history/9-70.md b/docs/history/9-70.md new file mode 100644 index 0000000..7b20bcb --- /dev/null +++ b/docs/history/9-70.md @@ -0,0 +1,103 @@ +### 9-70. 체크드 정수 산술 슬라이스 (2026-09-26, E2) — **`!` 본문의 오버플로가 `-3`이 됐다** + +사용자가 `SPEC-checked-arithmetic`의 DP-O3~O9와 `OPEN_QUESTIONS.md` Q17의 권고 (A)를 확인했고(*"보고 내용을 +수용"*), 이어 *"Grok과 함께 후속 진행"* 을 요청했다. Grok 호출은 사용자의 앞선 요청대로 **한 번에 주장 하나**로 +쪼개 병렬로 보냈다. + +#### 9-70.1. 들어간 것 — PR 셋 + +| PR | 내용 | +|---|---| +| #334 | codegen(연산 넷 + 변환, 세 반환 모양 모두) · `abi.rs`의 `ML_ST_OVERFLOW = -3` · `ir::can_fail_overflow` 한 술어로 `.h`/`.pas` 선언 · 골든(`IFACE_HASH` 줄 0개 이동) · 오라클 값 7 · 머지 순간 거짓이 되는 문서 전부 | +| #335 | Q17 (A) — 인코딩 위험을 `HOST_ABI.md` 문자열 파라미터 계약 4번에, 근거 표를 §9-69.3에 | +| 이 기록의 PR | 실제 C 호스트가 `-3`을 받는다(수용 E) · 626행 재측정(수용 I) · 크기(§5) · 슬라이스 닫기 | + +오라클 값과 문서는 SPEC §6의 작업 2에서 1로 옮겼다 — 작업 1이 머지되는 순간 `LANGUAGE.md`의 wrap 문단과 +`HOST_ABI.md` 표가 거짓이 되므로 같은 PR이어야 했다. + +#### 9-70.2. 재측정 — 구현이 실험의 표를 그대로 냈다 (수용 I) + +머지된 구현으로 `mlprobe`를 빌드해 §9-69의 626행을 다시 돌렸다. + +- **600행**은 실험(A+`as`)의 출력과 같다. +- **25행**이 달랐고 전부 **`-> [T]!`·`-> string!` 본문**, 네 도메인(hostdata · records · textfmt · workmem)에 있다. + §9-69.2가 적은 대로 첫 시험은 그 본문을 계측하지 않았고, 넓힌 재측정은 **표에는** 반영됐지만 도메인별 행 + 파일(스크래치 데이터)은 갱신되지 않았다. 구현의 `-3`은 정확히 그 행들에 떨어진다. +- 행 하나는 메모 행이라 돌릴 입력이 없다. + +구현으로 다시 센 표. 위 넷은 §9-69.2 표의 A+`as` 열과 같다. 아래 둘은 그 표에 실리지 않았던 칸이고, +실험의 집계(스크래치 데이터)와 같다 — 여섯을 더하면 626이다(101 + 60 + 9 + 438 + 18, 43은 101의 부분집합): + +| 626행 | 구현 | 비교 대상 | +|---|---|---| +| 조용한 오답 161행 중 status가 됨 | **101** | §9-69.2 표 | +| 여전히 조용함 | 60 | §9-69.2 표 | +| 맞던 답이 `-3`이 됨 | 9 | §9-69.2 표 | +| status가 됐지만 참값은 i32에 든다(위 101 중) | 43 | §9-69.2 표 | +| 그대로 맞음 | 438 | 실험 집계 | +| 기타 — 원래 도메인 에러였던 행 등. 그중 둘은 도메인 에러가 `-3`으로 바뀌었다(둘 다 실패) | 18 | 실험 집계 | + +**SPEC이 예상한 유일한 차이는 한 행도 바꾸지 않았다**: 실험은 `%`에 `checked_rem`을 썼고 구현은 +`wrapping_rem`이다(DP-O5). 실험이 `-3`을 내고 구현이 내지 않는 행이 **0**이다 — 표본의 어떤 입력도 +`i32::MIN % -1`에 닿지 않는다. 이것은 기록이지 가드가 아니다(SPEC §3 I). + +#### 9-70.3. 수용 E — 실제 C 호스트 + +`hosts/c-host/host.c`에 둘을 더했다. 예제를 바꾸지 않았으므로 지문이 움직이지 않는다. + +- `boxes_checked(INT32_MIN, -1)` → `ML_ST_OVERFLOW`, out은 그대로. 바로 위의 **무한** `boxes(INT32_MIN, -1)`은 + 여전히 `INT32_MIN`으로 wrap한다 — 같은 모듈 안에서 규칙이 **본문의 것**임을 C 호스트가 본다. +- `basket_total`의 줄 합 `INT32_MAX × 2` → `ML_ST_OVERFLOW`. 전에는 wrap한 `-2`가 cap 이하라 **status 0으로 + `-2`** 를 답했다(측정: 실험 스위치를 끈 `mlprobe` — `boxes_checked(INT32_MIN, -1)`도 전에는 status 0에 `INT32_MIN`). + +`MATHLESS_GATE_D=require`에서 `GATE_D_OK`. 이름은 `pack.h`·`basket.h`가 선언한다(낼 수 있는 모듈이라서). + +#### 9-70.4. 크기 (SPEC §5) + +같은 예제를 #334 전후의 `mlc`로 빌드해 `.text`의 virtual size를 쟀다(`dumpbin /headers`): + +| 모듈 | 전 | 후 | 차 | +|---|---|---|---| +| pack | 3528 | 3603 | +75 | +| receipt | 4312 | 4328 | +16 | +| schedule | 3608 | 3763 | +155 | +| account · allocate · basket · order · shapes | — | — | 0 | +| discount(무한 함수만) | 3432 | 3432 | 0 | + +0인 다섯은 DLL 바이트가 다른데도 `.text` 크기가 같다 — 늘어난 분기가 함수 사이 정렬 패딩 안에 들어갔다. +파일 크기가 바뀐 것은 pack 하나(+512, 파일 정렬 한 칸)다. `protection.rs`의 크기 가드가 재는 `discount.dll`은 +그대로다. 성능은 재지 않았다. + +#### 9-70.5. 결함 심기 — 둘은 심기가 틀렸다 + +#334의 테스트가 떨어질 수 있는지 커밋된 트리에서 여섯을 심었고, 전부 적발됐다(각 1~4개 테스트). +처음 두 번은 **심기가** 틀렸다: + +- 체크드 `+ - *`를 끄는 첫 심기는 `match`를 남긴 채 메서드만 바꿔 **컴파일되지 않는 Rust**를 만들었다 — + 지어낸 파손이지 예상한 결함이 아니다. 분기를 죽이는 심기로 다시 했다. +- 술어 심기는 바인딩 행렬 **하나만** 떨어뜨린 것처럼 보였다. `cargo test`가 **첫 실패 바이너리에서 멈춰** 그 뒤의 + 바이너리가 돌지 않았다 — `--no-fail-fast`로 다시 읽으니 표와 골든 둘도 떨어졌다. + +#### 9-70.6. Grok + +- **#334**: 주장 하나씩 6회, 전부 CONFIRMED. 여섯째(문서 ↔ 테스트)의 UNASKED 줄이 *"중간값만 넘쳐도 실패"* + 문장에 측정이 없음을 짚었다 → `an_intermediate_overflow_fails_even_when_the_answer_fits`. +- **#335**: 첫 라운드 DISCREPANCY — `HOST_ABI.md`의 *"100바이트 한도"* 와 *"SMS는 CP949일 때만 맞다(측정)"* 가 + 저장소 안 어느 기록에도 없었다(스크래치 데이터에만). §9-69.3에 규칙·값 표를 더한 뒤 CONFIRMED. +- **이 기록의 PR**: host.c ↔ 예제 본문 CONFIRMED · `start-block-051.md`가 옮긴 블록과 바이트 동일 CONFIRMED + (SHA-256 비교) · 기록 ↔ §9-69·SPEC·색인 DISCREPANCY — *"기타 18"* 이 저장소 안 어느 표에도 없었다(실험 집계에만). + 9-70.2의 표가 칸마다 비교 대상을 적게 고쳤다. +- **타임아웃 0회.** 줄 범위와 출력 분량을 좁힌 단일 주장 호출은 모두 끝났다. + +#### 9-70.7. 그 밖에 기록할 것 + +- **스크립트 편집이 테스트 파일에 NUL 바이트를 남겼다** — `CLAUDE.md`가 이미 경고하는 함정이다. 테스트는 + 초록이었다: Rust 바이트 문자열 안의 생 NUL은 `\0`과 같은 바이트다. `grep`이 파일을 *"binary"* 라고 한 것이 + 단서였다. `chr(92)`로 복구했다. +- 실험 브랜치 `exp/checked-arith-local`은 로컬에만 있고(푸시 안 함), 구현이 들어갔으므로 이제 출발점이 아니다. + +#### 9-70.8. 남은 것 + +- **다음 슬라이스 — 사용자 결정.** 여전히 조용한 60행의 이유는 §9-69.2(무한 헬퍼 16 · 무한 export 본문 4 · + f64 절삭·NaN 14 · 산술이 아닌 것 25 · 하류 저장 상태 1)이고, 43행은 `-3`이 됐지만 정답이 아니다 — 정답을 + 주는 것은 i64뿐이다. diff --git a/docs/history/start-block-051.md b/docs/history/start-block-051.md new file mode 100644 index 0000000..5c0953e --- /dev/null +++ b/docs/history/start-block-051.md @@ -0,0 +1,20 @@ +> ### 2026-09-26 기준 (3) — **§7을 열두 도메인으로 돌렸다: 가장 강한 근거는 체크드 산술이고, 설계 결정 하나에 걸려 있다 (§9-69)** +> +> 72규칙을 한 기준과 귀속 대조로 쟀고, 1위 후보(체크드 정수 산술)를 버리는 브랜치에서 구현해 626행으로 다시 쟀다 — +> 조용한 오답 161행 중 84(A)~101(A+`as`)이 status가 되고, 기존 테스트의 동작은 하나도 바뀌지 않는다. 그 과정의 +> 결함들은 PR 셋으로 고쳤다(#329 · #330 · #331). +> +> **▶ 다음 세션 — 여기서 시작한다.** 순서대로: +> +> 1. **체크드 정수 산술 — 구현 중.** DP-O1~O9 전부 사용자 확인(2026-09-26). `docs/slices/SPEC-checked-arithmetic.md` +> §6의 작업 1(codegen·바인딩·오라클 값·문서)이 들어갔고, **작업 2가 남았다** — 실제 C 호스트가 `-3`을 받는 수용 D, +> §9-69의 161행 재측정, 크기 변화, 그리고 슬라이스 닫기. +> 2. **작은 항목**: C# 호스트(Phase 4) · LSP(Phase 3, 큰 일). +> 3. **외부**: `X1`·`X2` — Delphi가 있는 CI 러너. 이 저장소 안에서는 닫히지 않는다. +> +> ⚠ **이 머신의 전체 게이트는 6회 중 2회 실패한다**(§9-63.5) — 실패를 보면 먼저 원인을 읽는다. +> 강한 신호는 CI 두 잡이다. +> +> 📌 **본문은 §9-69다**(`docs/history/9-69.md`). 그 앞의 2026-09-26 (2) 항목(상수 선언)은 +> 바이트 그대로 옮겼다 — 지금은 `docs/history/start-block-050.md`다. +> diff --git a/docs/history/start-block-index.md b/docs/history/start-block-index.md index 6dbd1a7..a6f3816 100644 --- a/docs/history/start-block-index.md +++ b/docs/history/start-block-index.md @@ -9,6 +9,7 @@ > | 날짜 | 무엇을 했나 | 본문 | > |---|---|---| +> | 2026-09-26 (3) | **§7을 열두 도메인으로 돌렸다: 가장 강한 근거는 체크드 산술이고, 설계 결정 하나에 걸려 있다** — 같은 날 슬라이스로 닫혔다(§9-70) | §9-69 | > | 2026-09-26 (2) | **상수 선언 슬라이스가 닫혔다: 조용한 오독이 로드 거부가 됐다** — 다음 선택은 §7부터(§9-69) | §9-68 | > | 2026-09-26 | **상태 머신 예제가 경계의 공백을 쟀다: 상태 번호는 헤더와 지문 밖에 있다** — 같은 날 상수 선언 슬라이스로 닫혔다(§9-68) | §9-67 | > | 2026-09-25 (2) | **문서가 다시 커지는 근본 원인을 고쳤다: 가드가 사본을 의무로 만들고 있었다** — ⑤는 사용자 결정 (a)로 닫혔다(9-66.8) | §9-66 | diff --git a/docs/slices/README.md b/docs/slices/README.md index 8b8f2fb..e46b068 100644 --- a/docs/slices/README.md +++ b/docs/slices/README.md @@ -62,7 +62,7 @@ TDD 구현 → Grok 검증 → PR** 순서를 따른다(`CLAUDE.md` "개발 방 | [고정 소수 포맷 `fixed(x, places)`](SPEC-fixed-decimals.md) | ✅ **구현 완료** (2026-09-15) | `fixed(x, places)` — 고정 소수 십진 표기. 모듈 안 우회가 조용히 틀리던 것(`1234.05` → `"1234.5"`)을 막는다 | §7 §9-53 / #243 | | [나눗셈 가드가 왼쪽 피연산자를 건너뛴다](SPEC-division-guard-operands.md) | ✅ **구현 완료** (2026-09-23) | 제수가 0이면 `/`·`%`의 왼쪽 피연산자(배열 경계 검사)가 실행되지 않던 결함 — 왼쪽을 먼저 묶어 평가한다 | #287 / #291 | | [상수 선언 `const` · `export const`](SPEC-constants.md) | ✅ **구현 완료** (2026-09-26) | 이름 붙은 리터럴 — `export const`만 헤더(`ML__CONST_`)와 지문에 나가, 번호를 바꾼 모듈을 게이트가 거부한다 | #325 / #326·#327 | -| [체크드 정수 산술](SPEC-checked-arithmetic.md) | 🔨 **확정 · 구현 중** (2026-09-26) | `!` 본문의 i32 오버플로와 `f64 as i32`가 `-3`으로 실패한다 — DP-O1~O9 사용자 확인, §6 작업 1이 들어갔고 작업 2(C 호스트 수용 D · 재측정)가 남았다 | §9-69 / — | +| [체크드 정수 산술](SPEC-checked-arithmetic.md) | ✅ **구현 완료** (2026-09-26) | `!` 본문의 i32 오버플로와 `f64 as i32`가 `ML_ST_OVERFLOW`(`-3`)로 실패한다 — 조용한 오답 161행 중 101이 status가 된다 | §9-69 / #334 · §9-70 | > **2026-09-25에 행을 한 줄로 접었다.** 접기 전의 서술은 [`../history/slices-index.md`](../history/slices-index.md)에 > 바이트 그대로 있다. **새 행도 한 줄로 쓴다** — 행당 400 B(`every_slice_index_row_is_one_line`)이고, 경위는 그 @@ -125,8 +125,7 @@ TDD 구현 → Grok 검증 → PR** 순서를 따른다(`CLAUDE.md` "개발 방 두 번째 호스트(C#, ROADMAP Phase 4), 그리고 ROADMAP Phase 2가 이름만 두고 설계가 없던 둘 — **인터페이스 정의 파일**(설계부터)과 **개발/배포 빌드 분리**(D13, `SECURITY.md` P1). *(2026-09-25 로드맵 검토에서 더했다 — Phase 2의 다섯 항목 중 이 둘이 이 목록에 없었다.)* -§7(§9-69, 12개 도메인 72규칙과 귀속 대조)이 더한 후보: **체크드 정수 산술**(가장 강한 근거 — 확정되어 -구현 중이다, 위 색인), **i64**, **입력 문자열의 인코딩 계약**(닫힌 DP-S2의 재개 — `OPEN_QUESTIONS.md` Q17이 (A)로 열어 두었고 재검토 조건은 거기 있다), 비트 연산자, +§7(§9-69, 12개 도메인 72규칙과 귀속 대조)이 더한 후보: **i64**(체크드 산술 뒤에도 43행은 `-3`일 뿐 정답이 아니다 — §9-70.2), **입력 문자열의 인코딩 계약**(닫힌 DP-S2의 재개 — `OPEN_QUESTIONS.md` Q17이 (A)로 열어 두었고 재검토 조건은 거기 있다), 비트 연산자, 지역 작업 배열, 수학 내장 함수, 문자 단위 길이. **struct는 §9-1이 강제되지 않는다고 결론냈다** — 고르려면 그 절을 먼저 읽는다(§9-69도 귀속 0으로 다시 확인했다). 배열도 같은 결론이었고(§9-9가 다섯 번째로), **입력은 그 사실을 SPEC 첫 절에 적은 채로 열렸다**. diff --git a/docs/slices/SPEC-checked-arithmetic.md b/docs/slices/SPEC-checked-arithmetic.md index 78ccd8b..873340d 100644 --- a/docs/slices/SPEC-checked-arithmetic.md +++ b/docs/slices/SPEC-checked-arithmetic.md @@ -1,9 +1,14 @@ # SPEC — 체크드 정수 산술 (`!` 본문) -- **상태: 확정 · 구현 중.** §4의 DP-O1~O9 전부 **사용자 확인**(2026-09-26, 권고안 그대로). §6의 작업 1이 - 들어갔고 작업 2가 남았다. - - 방향은 먼저 확인받았다: 설계 **A+as** — `!` 함수 본문의 i32 산술과 `f64 as i32`가 넘치면 - 예약 음수 status로 실패한다(§9-69.2의 권장안). +> **기록 문서다.** 이 SPEC은 닫힌 슬라이스의 설계 기록이다 — 본문은 닫힌 날의 사실이고 다시 고치지 않는다. +> 현재 상태는 [`docs/STATUS.md`](../STATUS.md)가 말한다. + +> **상태: 확정 · 구현 완료** — DP-O1~O9 사용자 확인(권고안 그대로) 2026-09-26 / SPEC #333 · 구현 #334 · 호스트와 +> 재측정은 `HISTORY.md` §9-70. 수용 A~I 전부 닫혔다. **근거 수준:** E2 — 로드한 모듈의 반환값, 실제 C 호스트, +> 구현으로 다시 잰 626행(실험의 표와 같다, §9-70.2). + +- 방향은 먼저 확인받았다: 설계 **A+as** — `!` 함수 본문의 i32 산술과 `f64 as i32`가 넘치면 + 예약 음수 status로 실패한다(§9-69.2의 권장안). - 선행: `SPEC-i32.md`(DP-I4 — `+ - *` wrap) · `SPEC-unary.md`(DP-U4 — `-i32::MIN` wrap) · `SPEC-i32-division.md`(D2 행 — `i32::MIN / -1` wrap) · `SPEC-numeric-conversion.md`(§2.3 — `f64 as i32` 포화·NaN→0) · `SPEC-array-return.md`(DP-R9 — `result` 뒤의 실패) · `SPEC-fixed-decimals.md`(DP-M4 — `-2` 재사용 선례) @@ -159,7 +164,8 @@ DP-O1·O2는 방향 확인 때, DP-O3~O9는 이 표 그대로 **사용자 확인 - **무한 함수의 오버플로**(남는 20행) — 채널이 없다. `!`를 붙이면 이 슬라이스가 덮는다는 것이 저자의 탈출구다. - **i64**(정답을 주는 유일한 안), **옵트인 내장 함수**, **상수식 오버플로 진단** — 별도 후보. - **성능·`.text` 크기** — 체크 분기가 는다. `protection.rs`의 크기 가드는 `discount.dll`(무한 함수만)을 재므로 영향이 - 없을 것으로 본다(E0). 구현에서 오버플로가 있는 모듈의 크기 변화를 **재서 적는다**(가드로 만들지는 않는다). + 없을 것으로 본다(E0). **쟀다**(§9-70.4): 체크가 있는 여덟 모듈의 `.text`가 +0~+155바이트, `discount.dll`은 + 그대로다. 가드로 만들지는 않는다. - `runtime/ml_abi.h`는 `-1`만 정의하고 `-2`도 생성 헤더에만 있다 — 이 슬라이스는 그 배치를 따른다. --- @@ -173,3 +179,4 @@ DP-O1·O2는 방향 확인 때, DP-O3~O9는 이 표 그대로 **사용자 확인 오라클 값과 문서는 작업 2에서 1로 옮겼다 — 작업 1이 머지되는 순간 `LANGUAGE.md`의 wrap 문단과 `HOST_ABI.md` 표가 거짓이 되므로 같은 PR에서 고쳐야 했고, 그 문장들이 인용할 측정이 오라클 값이다. +두 작업 다 들어갔다(#334 · §9-70). diff --git a/hosts/c-host/host.c b/hosts/c-host/host.c index cd76d38..bfab59d 100644 --- a/hosts/c-host/host.c +++ b/hosts/c-host/host.c @@ -528,6 +528,16 @@ int main(int argc, char **argv) { status = boxes_checked(17, 0, &untouched); check(status == ML_PACK_ERR_E_EMPTY_BOX, "boxes_checked(17, 0) status == ML_PACK_ERR_E_EMPTY_BOX"); check(untouched == -999, "boxes_checked(17, 0) leaves the out-param untouched"); + + /* SPEC-checked-arithmetic acceptance E: the one quotient with no i32 value. `boxes` + above is the same `/` in an INFALLIBLE body and still wraps to INT32_MIN; the `!` + body answers with the reserved status instead -- the rule belongs to the body. The + name comes from pack.h, which declares it because this module can return it. */ + status = boxes_checked(INT32_MIN, -1, &untouched); + check(status == ML_ST_OVERFLOW, "boxes_checked(INT32_MIN, -1) status == ML_ST_OVERFLOW"); + check(untouched == -999, "and it leaves the out-param untouched"); + status = boxes_checked(INT32_MIN, 1, &out); + check(status == 0 && out == INT32_MIN, "boxes_checked(INT32_MIN, 1) is an answer"); } /* --- commission.dll: a declared `out` parameter. The host allocates; the module writes @@ -1366,6 +1376,15 @@ int main(int argc, char **argv) { int32_t last = -1; check(pick(qty, 3, 2, &last) == 0 && last == 4, "the last element is in range"); + /* A line total with no i32 value. Before SPEC-checked-arithmetic this product wrapped + to -2, which is <= cap, so the basket answered -2 with status 0. */ + const int32_t big_qty[1] = {INT32_MAX}; + const int32_t two[1] = {2}; + int32_t total = 0x5A5A5A5A; + check(basket_total(big_qty, 1, two, 1, 100, &total) == ML_ST_OVERFLOW, + "a line total that overflows is ML_ST_OVERFLOW, not a wrapped number"); + check(total == 0x5A5A5A5A, "and it leaves the out-param untouched"); + double best = 0.0; const double xs[3] = {1.5, 9.25, -3.0}; check(largest(xs, 3, 0.0, &best) == 0 && best == 9.25, "largest over an f64 array");