@@ -28623,6 +28623,45 @@ fn cmplx_whole_array_with_kind_keyword_returns_correct_kind_descriptor() { |
| 28623 | 28623 | let _ = std::fs::remove_file(&src); |
| 28624 | 28624 | } |
| 28625 | 28625 | |
| 28626 | +#[test] |
| 28627 | +fn allocate_source_from_strided_section_walks_per_element() { |
| 28628 | + // F2018 §9.7.1.2: ALLOCATE(dest, source = strided_section) must |
| 28629 | + // populate dest by reading the source per-element via the |
| 28630 | + // section's per-dim memory stride, not by a flat memcpy of |
| 28631 | + // total_bytes from source base. afs_copy_array_data was doing |
| 28632 | + // ptr::copy(source.base_addr, dest.base_addr, total_bytes), which |
| 28633 | + // for a section like `idx(2, 1:n)` (stride 2 between adjacent |
| 28634 | + // dim-0=2 picks) read consecutive bytes including dim-0=1 entries. |
| 28635 | + // Surfaced inside stdlib_sparse_conversion's coo2csr_dp at line |
| 28636 | + // 426: `allocate(CSR%col, source = COO%index(2, 1:nnz))` populated |
| 28637 | + // CSR%col with row indices instead of column indices, so spmv |
| 28638 | + // walked vec_x past its declared bounds. |
| 28639 | + let src = write_program( |
| 28640 | + "program p\n implicit none\n integer, allocatable :: idx(:,:)\n integer, allocatable :: col(:)\n integer :: i, n\n n = 8\n allocate(idx(2, n), source=0)\n do i = 1, n\n idx(1, i) = (i-1) / 2 + 1\n idx(2, i) = mod(i-1, 2) + 1\n end do\n allocate(col(n), source = idx(2, 1:n))\n do i = 1, n\n if (col(i) /= idx(2, i)) error stop 1\n end do\n print *, 'ok'\nend program\n", |
| 28641 | + "f90", |
| 28642 | + ); |
| 28643 | + let out = unique_path("alloc_source_strided_section", "bin"); |
| 28644 | + let compile = Command::new(compiler("armfortas")) |
| 28645 | + .args([src.to_str().unwrap(), "-o", out.to_str().unwrap()]) |
| 28646 | + .output() |
| 28647 | + .expect("alloc-source strided compile failed to spawn"); |
| 28648 | + assert!( |
| 28649 | + compile.status.success(), |
| 28650 | + "alloc-source strided compile failed: {}", |
| 28651 | + String::from_utf8_lossy(&compile.stderr) |
| 28652 | + ); |
| 28653 | + let run = Command::new(&out).output().expect("run failed"); |
| 28654 | + assert!( |
| 28655 | + run.status.success() && String::from_utf8_lossy(&run.stdout).contains("ok"), |
| 28656 | + "alloc-source strided run failed: status={:?} stdout={} stderr={}", |
| 28657 | + run.status, |
| 28658 | + String::from_utf8_lossy(&run.stdout), |
| 28659 | + String::from_utf8_lossy(&run.stderr) |
| 28660 | + ); |
| 28661 | + let _ = std::fs::remove_file(&out); |
| 28662 | + let _ = std::fs::remove_file(&src); |
| 28663 | +} |
| 28664 | + |
| 28626 | 28665 | #[test] |
| 28627 | 28666 | fn random_number_on_array_fills_every_element() { |
| 28628 | 28667 | // F2018 §16.9.171: RANDOM_NUMBER(harvest) fills harvest with |