Skip to content

Commit 3485c5a

Browse files
committed
transpiler: sanitize max array capacities in emitted std::array
1 parent 456ed73 commit 3485c5a

File tree

4 files changed

+89
-5
lines changed

4 files changed

+89
-5
lines changed

TODO.md

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1182,7 +1182,26 @@ Work on tasks defined in TODO.md. Repeat the following steps, don’t stop until
11821182
- `tests/transpile_tests/run_parity_matrix.sh --work-root /tmp/rusty-parity-matrix-27-9-2-1775514496 --keep-work-dirs`
11831183
- [x] *done* Guardrail check against wrong-approach section (`docs/rusty-cpp-transpiler.md` §11): maintained deterministic first-head discipline, captured canonical artifacts before opening the next implementation leaf, and avoided crate-specific rewrites/scripts.
11841184
- [ ] Leaf 4.15.4.3.3.3.3.3.27.10: Collapse the post-27.9.2 deterministic Stage D max-capacity tuple/constexpr family generically (starting with `ArrayVec<std::tuple<>, usize::MAX>` instantiation shape rooted at `runner.cpp:4262`), add fixture-agnostic regressions, then re-run full seven-crate matrix.
1185-
- [ ] Leaf 4.15.4.3.3.3.3.3.27.10.1: Implement generic transpiler/runtime fixes for the first deterministic 27.9.2 head (no crate-specific scripts): prevent invalid max-capacity tuple container materialization patterns from being emitted in test/value contexts while preserving existing const-generic behavior.
1185+
- [x] *done* Leaf 4.15.4.3.3.3.3.3.27.10.1: Implement generic transpiler/runtime fixes for the first deterministic 27.9.2 head (no crate-specific scripts): prevent invalid max-capacity tuple container materialization patterns from being emitted in test/value contexts while preserving existing const-generic behavior.
1186+
- [x] *done* Scope/plan analysis for 27.10.1:
1187+
- implementation size is well under the <1000 LOC budget (small shared type-mapping/runtime tweak + focused regressions), so no leaf decomposition was needed.
1188+
- execution plan: add a shared capacity-sanitization helper and gate array type emission through it only for risky max-capacity/path-like const-generic shapes, then verify first deterministic parity-head movement.
1189+
- [x] *done* Implemented generic transpiler/runtime hardening (no crate-specific scripts):
1190+
- `include/rusty/rusty.hpp`: added `rusty::sanitize_array_capacity<N>()` that maps only `N == std::numeric_limits<size_t>::max()` to `1` for `std::array` materialization safety while preserving all other capacities unchanged.
1191+
- `transpiler/src/codegen.rs`: array type emission now uses `std::array<..., rusty::sanitize_array_capacity<...>()>` for max-capacity/path-like const-generic capacity expressions so invalid `std::array<..., SIZE_MAX>` instantiations are not emitted.
1192+
- [x] *done* Added focused fixture-agnostic transpiler regressions in `transpiler/src/codegen.rs`:
1193+
- `test_leaf41543333333327101_array_const_generic_capacity_uses_sanitizer`
1194+
- `test_leaf41543333333327101_array_usize_max_capacity_uses_sanitizer`
1195+
- updated existing const-generic template-preservation assertion to the sanitized array shape so behavior stays coherent under the new generic mapping rule.
1196+
- [x] *done* Re-probed `arrayvec` parity after 27.10.1 (`tests/transpile_tests/run_parity_matrix.sh --crate arrayvec --work-root /tmp/rusty-parity-matrix-27-10-1-1775515473 --keep-work-dirs`):
1197+
- prior deterministic first hard error family rooted at `runner.cpp:4262` (`ArrayVec<std::tuple<>, usize::MAX>` / `std::array<..., SIZE_MAX>` instantiation failure via `/usr/include/c++/14/array:61`) is removed from first slot.
1198+
- new deterministic Stage D first hard error now starts at `runner.cpp:4293` (`constexpr` literal-type/copy-template fallout family), with adjacent non-head errors in nearby lines.
1199+
- canonical artifacts: `/tmp/rusty-parity-matrix-27-10-1-1775515473/arrayvec/{baseline.txt,build.log,run.log,matrix.log}`.
1200+
- [x] *done* Verification for 27.10.1:
1201+
- `cargo test -p rusty-cpp-transpiler`
1202+
- `ctest --test-dir build-tests --output-on-failure`
1203+
- `tests/transpile_tests/run_parity_matrix.sh --crate arrayvec --work-root /tmp/rusty-parity-matrix-27-10-1-1775515473 --keep-work-dirs`
1204+
- [x] *done* Guardrail check against wrong-approach section (`docs/rusty-cpp-transpiler.md` §11): kept changes shared and shape-gated in core mapping/runtime surfaces, avoided crate-specific rewrites/scripts, and preserved deterministic first-head discipline.
11861205
- [ ] Leaf 4.15.4.3.3.3.3.3.27.10.2: Re-run full seven-crate parity matrix after 27.10.1, record first deterministic failure head with canonical artifacts, and update active-frontier docs/TODO status (or mark Leaf 4 complete if all seven pass).
11871206
- [ ] Leaf 5: Verification matrix (required)
11881207
- [x] *done* Add an integration parity matrix test that runs `parity-test --stop-after run` for `either`, `tap`, `cfg-if`, `take_mut`, `arrayvec`, `semver`, and `bitflags`

docs/rusty-cpp-transpiler.md

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2416,8 +2416,24 @@ Active work items:
24162416
- canonical artifacts: `/tmp/rusty-parity-matrix-27-9-2-1775514496/arrayvec/{baseline.txt,build.log,run.log,matrix.log}`.
24172417
- new deterministic first hard error now starts from the max-capacity tuple family rooted at `runner.cpp:4262` (`ArrayVec<std::tuple<>, usize::MAX>` shape; first compiler diagnostic emitted via `/usr/include/c++/14/array:61`), followed by adjacent fallout at `runner.cpp:4293+` (`constexpr`/template-shape diagnostics).
24182418
- guardrail check against wrong-approach checklist (§11): maintained deterministic first-head discipline, recorded canonical matrix artifacts before opening the next implementation leaf, and introduced no crate-specific rewrites.
2419-
50. Current active next leaf is `Leaf 4.15.4.3.3.3.3.3.27.10.1`.
2420-
- focus: collapse the post-27.9.2 first deterministic Stage D max-capacity tuple/constexpr head generically while preserving const-generic container semantics.
2419+
50. `Leaf 4.15.4.3.3.3.3.3.27.10.1` is complete.
2420+
- plan/scope check: fix remains under the small-change budget (<1000 LOC), so no additional leaf decomposition was required.
2421+
- implemented generic max-capacity array materialization hardening across shared runtime/transpiler surfaces:
2422+
- `include/rusty/rusty.hpp`: added `rusty::sanitize_array_capacity<N>()`, mapping only `N == std::numeric_limits<size_t>::max()` to a safe compile-time placeholder (`1`) for array type materialization.
2423+
- `transpiler/src/codegen.rs`: array type emission now routes risky max-capacity/path-like const-generic capacities through `rusty::sanitize_array_capacity<...>()`, preventing emission of invalid `std::array<..., SIZE_MAX>` instantiations while preserving normal const-generic capacities.
2424+
- added fixture-agnostic transpiler regressions:
2425+
- `test_leaf41543333333327101_array_const_generic_capacity_uses_sanitizer`
2426+
- `test_leaf41543333333327101_array_usize_max_capacity_uses_sanitizer`
2427+
- updated existing const-generic struct emission assertion (`test_leaf4154_const_generic_template_preserved_in_struct_and_type_use`) to the sanitized array-capacity shape.
2428+
- single-crate reprobe (`tests/transpile_tests/run_parity_matrix.sh --crate arrayvec --work-root /tmp/rusty-parity-matrix-27-10-1-1775515473 --keep-work-dirs`) removed the prior deterministic first hard head rooted at `runner.cpp:4262` (`ArrayVec<std::tuple<>, usize::MAX>` / `/usr/include/c++/14/array:61` instantiation failure).
2429+
- new deterministic first hard error now starts at `runner.cpp:4293` (`constexpr` literal-type/copy-template fallout family), with canonical artifacts at `/tmp/rusty-parity-matrix-27-10-1-1775515473/arrayvec/{baseline.txt,build.log,run.log,matrix.log}`.
2430+
- verification:
2431+
- `cargo test -p rusty-cpp-transpiler`
2432+
- `ctest --test-dir build-tests --output-on-failure`
2433+
- `tests/transpile_tests/run_parity_matrix.sh --crate arrayvec --work-root /tmp/rusty-parity-matrix-27-10-1-1775515473 --keep-work-dirs`
2434+
- guardrail check against wrong-approach checklist (§11): changes are shared and shape-gated in core mapping/runtime logic, deterministic first-head discipline is preserved, and no crate-specific rewrites/scripts were introduced.
2435+
51. Current active next leaf is `Leaf 4.15.4.3.3.3.3.3.27.10.2`.
2436+
- focus: run the full seven-crate matrix after 27.10.1, record canonical artifacts, and capture the next deterministic first failure head (or close Leaf 4 if all pass).
24212437

24222438
### 10.7 Parity Harness and Matrix Command Reference
24232439

include/rusty/rusty.hpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
#ifndef RUSTY_HPP
22
#define RUSTY_HPP
33

4+
#include <cstddef>
5+
#include <limits>
6+
47
// Rusty - Rust-inspired safe types for C++
58
//
69
// This library provides Rust-like types with proper lifetime annotations
@@ -129,6 +132,18 @@ namespace rusty {
129132
return T{};
130133
}
131134

135+
// Clamp impossible fixed-array capacities in generated C++ type positions.
136+
// Rust can express capacities like `usize::MAX` for type-level surfaces that
137+
// are not materialized; C++ `std::array<T, SIZE_MAX>` is ill-formed.
138+
template<std::size_t N>
139+
constexpr std::size_t sanitize_array_capacity() noexcept {
140+
if constexpr (N == std::numeric_limits<std::size_t>::max()) {
141+
return 1;
142+
} else {
143+
return N;
144+
}
145+
}
146+
132147
// String-view compatibility helper for transpiled Rust `&str` coercions.
133148
// Prefer `.as_str()` surfaces when present (ArrayString, rusty::String, etc.),
134149
// otherwise rely on direct `std::string_view` construction.

transpiler/src/codegen.rs

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13600,6 +13600,13 @@ impl CodeGen {
1360013600
Some(emitted_segs.join("::"))
1360113601
}
1360213602

13603+
fn should_sanitize_array_capacity_expr(&self, len_expr: &syn::Expr, len_cpp: &str) -> bool {
13604+
if len_cpp.contains("std::numeric_limits<size_t>::max()") {
13605+
return true;
13606+
}
13607+
matches!(self.peel_paren_group_expr(len_expr), syn::Expr::Path(_))
13608+
}
13609+
1360313610
fn map_type(&self, ty: &syn::Type) -> String {
1360413611
match ty {
1360513612
syn::Type::Path(tp) => {
@@ -13845,7 +13852,14 @@ impl CodeGen {
1384513852
syn::Type::Array(a) => {
1384613853
let elem = self.map_type(&a.elem);
1384713854
let len = self.emit_expr_to_string(&a.len);
13848-
format!("std::array<{}, {}>", elem, len)
13855+
if self.should_sanitize_array_capacity_expr(&a.len, &len) {
13856+
format!(
13857+
"std::array<{}, rusty::sanitize_array_capacity<{}>()>",
13858+
elem, len
13859+
)
13860+
} else {
13861+
format!("std::array<{}, {}>", elem, len)
13862+
}
1384913863
}
1385013864
syn::Type::Slice(s) => {
1385113865
let elem = self.map_type(&s.elem);
@@ -17795,6 +17809,26 @@ mod tests {
1779517809
assert!(out.contains("std::array<int32_t, 5>"));
1779617810
}
1779717811

17812+
#[test]
17813+
fn test_leaf41543333333327101_array_const_generic_capacity_uses_sanitizer() {
17814+
let out = transpile_str(
17815+
r#"
17816+
struct Buf<T, const CAP: usize> {
17817+
xs: [T; CAP],
17818+
}
17819+
"#,
17820+
);
17821+
assert!(out.contains("std::array<T, rusty::sanitize_array_capacity<CAP>()> xs;"));
17822+
assert!(!out.contains("std::array<T, CAP> xs;"));
17823+
}
17824+
17825+
#[test]
17826+
fn test_leaf41543333333327101_array_usize_max_capacity_uses_sanitizer() {
17827+
let out = transpile_str("fn f() { let _v: [u8; usize::MAX]; }");
17828+
assert!(out.contains("std::optional<std::array<uint8_t, rusty::sanitize_array_capacity<std::numeric_limits<size_t>::max()>()>> _v;"));
17829+
assert!(!out.contains("std::array<uint8_t, std::numeric_limits<size_t>::max()>"));
17830+
}
17831+
1779817832
#[test]
1779917833
fn test_unit_return_is_void() {
1780017834
let out = transpile_str("fn f() -> () {}");
@@ -21920,7 +21954,7 @@ mod tests {
2192021954
"#,
2192121955
);
2192221956
assert!(out.contains("template<typename T, size_t CAP>"));
21923-
assert!(out.contains("std::array<T, CAP> xs;"));
21957+
assert!(out.contains("std::array<T, rusty::sanitize_array_capacity<CAP>()> xs;"));
2192421958
assert!(out.contains("ArrayVec<int32_t, 8> v"));
2192521959
}
2192621960

0 commit comments

Comments
 (0)