Commit 656a368
committed
fix(hpc/blocked_grid): UB — overlapping &mut [T] in GridBlockMut (codex P1×2)
Codex review on PR #158 flagged two P1 soundness bugs:
1. `BaseBlockIterMut::next()` yields `GridBlockMut` instances carrying
`data: &'a mut [T]` slices over the strided block footprint
(`[start..start + (BR-1)*padded_cols + BC]`). For grids with multiple
block columns, adjacent column blocks' slices overlap heavily — e.g.,
on a 64×128 padded grid with 64×64 blocks, block (0,0) covers
`data[0..8128]` and block (0,1) covers `data[64..8192]`. Two such
`&mut [T]` simultaneously live = UB.
2. `TierBlockIterMut::next()` yields `GridSuperBlockMut` instances with
`data: *mut T` set to `data_ptr.add(row_origin * padded_cols)` —
col_origin doesn't enter the offset, so adjacent super-blocks in the
same row receive IDENTICAL raw pointers spanning the full row slab.
`base_blocks_mut()` then materialized strided `&mut [T]` from these
colliding super-block pointers, propagating the UB.
Both bugs trace to the same root cause: `GridBlockMut::data` stored
a strided `&'a mut [T]` slice that referenced cells outside the block's
own column range. Adjacent column blocks fundamentally share rows that
interleave in memory; no contiguous `&mut [T]` can describe a block
without aliasing siblings.
Fix: change `GridBlockMut::data` from `&'a mut [T]` to `*mut T` + add
`data_len: usize` for bounds checking. The struct's new aliasing
invariant (documented in the type-level docstring) is: `data` is NEVER
converted to a wide `&mut [T]`; cell access happens exclusively through
`row_mut(r)`, which materializes `&mut [T]` of length BC starting at
the block's own `(row_origin + r, col_origin)`. Across blocks, these
per-row materializations target disjoint cells (each block owns its
own `[col_origin, col_origin + BC)` column range), so no two live
`&mut [T]` ever alias.
Also:
- `GridBlockMut::from_raw` is now `unsafe fn` with documented caller
contract (raw pointer + length + per-block column-disjoint invariant)
- Added `unsafe impl Send + Sync` for `GridBlockMut<T: Send/Sync>`
matching the existing pattern on `BaseBlockIterMut` / `GridSuperBlockMut`
- Renamed `GridBlockMut::padded_cols` pub(crate) accessor to
`padded_cols_stride` for naming consistency with `GridBlock`
(resolves a PR-X3.1 housekeeping item early)
- Replaced `data_mut() -> &mut [T]` pub(crate) accessor with
`data_ptr() -> *mut T` + `data_len() -> usize`. The wide-slice
accessor was the materialization vehicle for the UB.
- Updated `iter.rs::row_mut` to materialize via `slice::from_raw_parts_mut`
with a debug_assert bounds check and verbatim SAFETY comment
- Updated `super_block.rs::base_blocks_mut` to pass raw pointer + length
to the new unsafe `from_raw` (no intermediate strided slice)
- Updated `super_block.rs::tier_mut_2_mutation_visible` test to use
`row_mut(0)[0]` instead of the removed `data_mut()` accessor
All 5 gates still green:
- cargo check: PASS
- cargo test --lib hpc::blocked_grid: 111/111 PASS
- cargo test --doc hpc::blocked_grid: 79/79 PASS
- cargo fmt --check: clean
- cargo clippy -D warnings: clean
Codex audit gap noted for PR-X3.1: future audits need a SAFETY-claim
verification gate that simulates adversarial iterator usage (e.g.,
collect all yielded items into a Vec before consuming any) to catch
this class of latent UB that passes type-checking but violates the
aliasing model.1 parent 81766e6 commit 656a368
3 files changed
Lines changed: 131 additions & 55 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
448 | 448 | | |
449 | 449 | | |
450 | 450 | | |
| 451 | + | |
| 452 | + | |
| 453 | + | |
| 454 | + | |
| 455 | + | |
| 456 | + | |
| 457 | + | |
| 458 | + | |
| 459 | + | |
| 460 | + | |
| 461 | + | |
| 462 | + | |
| 463 | + | |
| 464 | + | |
| 465 | + | |
| 466 | + | |
| 467 | + | |
| 468 | + | |
| 469 | + | |
| 470 | + | |
| 471 | + | |
451 | 472 | | |
452 | 473 | | |
453 | 474 | | |
454 | 475 | | |
455 | 476 | | |
456 | 477 | | |
457 | | - | |
458 | | - | |
459 | | - | |
460 | | - | |
| 478 | + | |
| 479 | + | |
| 480 | + | |
| 481 | + | |
| 482 | + | |
| 483 | + | |
| 484 | + | |
| 485 | + | |
| 486 | + | |
461 | 487 | | |
462 | 488 | | |
463 | 489 | | |
| 490 | + | |
| 491 | + | |
| 492 | + | |
| 493 | + | |
| 494 | + | |
| 495 | + | |
| 496 | + | |
| 497 | + | |
| 498 | + | |
464 | 499 | | |
465 | 500 | | |
466 | 501 | | |
| |||
475 | 510 | | |
476 | 511 | | |
477 | 512 | | |
478 | | - | |
479 | | - | |
480 | | - | |
481 | | - | |
482 | | - | |
483 | | - | |
484 | | - | |
485 | 513 | | |
| 514 | + | |
| 515 | + | |
| 516 | + | |
| 517 | + | |
| 518 | + | |
| 519 | + | |
| 520 | + | |
| 521 | + | |
| 522 | + | |
| 523 | + | |
| 524 | + | |
486 | 525 | | |
487 | 526 | | |
488 | 527 | | |
489 | 528 | | |
490 | 529 | | |
491 | 530 | | |
492 | | - | |
| 531 | + | |
| 532 | + | |
493 | 533 | | |
494 | 534 | | |
495 | 535 | | |
| |||
542 | 582 | | |
543 | 583 | | |
544 | 584 | | |
545 | | - | |
546 | | - | |
547 | | - | |
548 | | - | |
549 | | - | |
| 585 | + | |
| 586 | + | |
| 587 | + | |
| 588 | + | |
| 589 | + | |
| 590 | + | |
550 | 591 | | |
551 | 592 | | |
552 | 593 | | |
553 | | - | |
554 | | - | |
555 | | - | |
556 | | - | |
557 | | - | |
| 594 | + | |
| 595 | + | |
| 596 | + | |
| 597 | + | |
| 598 | + | |
| 599 | + | |
| 600 | + | |
| 601 | + | |
| 602 | + | |
| 603 | + | |
| 604 | + | |
558 | 605 | | |
559 | 606 | | |
560 | 607 | | |
561 | 608 | | |
562 | 609 | | |
563 | | - | |
564 | | - | |
565 | | - | |
566 | | - | |
567 | | - | |
568 | | - | |
| 610 | + | |
| 611 | + | |
| 612 | + | |
| 613 | + | |
| 614 | + | |
| 615 | + | |
| 616 | + | |
| 617 | + | |
| 618 | + | |
| 619 | + | |
| 620 | + | |
| 621 | + | |
| 622 | + | |
| 623 | + | |
| 624 | + | |
| 625 | + | |
569 | 626 | | |
570 | 627 | | |
571 | 628 | | |
| |||
574 | 631 | | |
575 | 632 | | |
576 | 633 | | |
| 634 | + | |
577 | 635 | | |
578 | 636 | | |
579 | 637 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
305 | 305 | | |
306 | 306 | | |
307 | 307 | | |
308 | | - | |
| 308 | + | |
309 | 309 | | |
310 | | - | |
| 310 | + | |
| 311 | + | |
| 312 | + | |
| 313 | + | |
| 314 | + | |
| 315 | + | |
| 316 | + | |
| 317 | + | |
| 318 | + | |
| 319 | + | |
| 320 | + | |
| 321 | + | |
| 322 | + | |
| 323 | + | |
| 324 | + | |
| 325 | + | |
| 326 | + | |
| 327 | + | |
| 328 | + | |
| 329 | + | |
| 330 | + | |
311 | 331 | | |
312 | 332 | | |
313 | 333 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
295 | 295 | | |
296 | 296 | | |
297 | 297 | | |
298 | | - | |
299 | | - | |
300 | | - | |
301 | | - | |
302 | | - | |
303 | | - | |
304 | | - | |
305 | | - | |
306 | | - | |
307 | | - | |
308 | | - | |
309 | | - | |
310 | | - | |
311 | | - | |
312 | | - | |
313 | | - | |
314 | | - | |
315 | | - | |
316 | | - | |
317 | | - | |
| 298 | + | |
| 299 | + | |
| 300 | + | |
| 301 | + | |
| 302 | + | |
| 303 | + | |
| 304 | + | |
| 305 | + | |
| 306 | + | |
| 307 | + | |
| 308 | + | |
| 309 | + | |
| 310 | + | |
| 311 | + | |
| 312 | + | |
| 313 | + | |
| 314 | + | |
| 315 | + | |
| 316 | + | |
| 317 | + | |
318 | 318 | | |
319 | 319 | | |
320 | 320 | | |
| |||
804 | 804 | | |
805 | 805 | | |
806 | 806 | | |
807 | | - | |
808 | | - | |
809 | | - | |
810 | | - | |
811 | | - | |
| 807 | + | |
| 808 | + | |
| 809 | + | |
812 | 810 | | |
813 | 811 | | |
814 | 812 | | |
| |||
0 commit comments