Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ m.Transpose().Shape() // [3 2]

| Area | Functions / methods |
| --- | --- |
| Creation | `Zeros`, `Ones`, `Full`, `Arange`, `Linspace`, `Eye`, `FromData` |
| Creation | `New`, `Zeros`, `Ones`, `Full`, `Arange`, `Linspace`, `Eye`, `Identity`, `FromData` |
| Views & shape | `Slice` (`All`/`R`/`Rng`/`From`/`To`/`Step`), `Reshape`, `Ravel`, `Transpose`, `Copy` |
| Elementwise | `Add`/`Sub`/`Mul`/`Div` (+`*Scalar`, +`*Into`), `Map`, `Neg`, `Abs` |
| Ufuncs | `Sqrt`, `Exp`, `Log`/`Log2`/`Log10`, `Sin`/`Cos`/`Tan`, `Floor`/`Ceil`/`Round`, `Square`, `Power` |
Expand All @@ -34,6 +34,14 @@ m.Transpose().Shape() // [3 2]
| Linear algebra | `MatMul`, `Dot`, `Inner`, `Outer` |
| Memory reuse | `NewWorkspace`, `Use`, `Reset`, `Detach` |

## Untrusted input (v0.3.0)

A shape the library cannot represent is an error wrapping `ErrShapeMismatch`,
for results as well as inputs: `(2^32, 0) @ (0, 2^32)` holds no data, yet its
result would have 2^64 elements, so `MatMul` refuses it, as NumPy does. Empty
arrays with a huge axis cost nothing, and every assembly call is guarded and
fence-tested. See [Security](security.md).

## Loops: `Workspace` (v0.2.0)

Every operation returns a new array, and in a loop those results are garbage
Expand Down
69 changes: 69 additions & 0 deletions docs/security.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# Security

> Mirrored from [`SECURITY.md`](https://github.com/go-ndarray/ndarray/blob/main/SECURITY.md) at v0.3.0.

## Reporting

Report a vulnerability privately through GitHub's **Report a vulnerability**
button on [the repository](https://github.com/go-ndarray/ndarray/security) (Security → Advisories). Please do not open a public
issue for it.

## What the library guarantees

go-ndarray is pure Go (`CGO_ENABLED=0`) except for its SIMD kernels, which are
Plan 9 assembly generated by [go-asmgen](https://github.com/go-asmgen/asmgen)
for amd64, arm64, ppc64le and loong64. Those kernels are the only code Go's
bounds checks do not cover, so they are held to the following:

- **Every wrapper checks the reach of its kernel.** Before an assembly call, the
Go wrapper indexes the last element of every operand the kernel reads or
writes (`internal/kernels/{reduce,gemm}_<arch>.go`). A caller's mistake is an
index-out-of-range panic in Go, never an access outside a slice.
`TestWrappersRefuseShortOperands` passes each wrapper an operand one element
short and requires the panic.
- **The kernels stay inside their slices.** `TestKernelsStayInsideTheirSlices`
and `TestGemmMicroStaysInsideItsOperands` ([`internal/kernels/fence_test.go`](https://github.com/go-ndarray/ndarray/blob/main/internal/kernels/fence_test.go),
Linux and macOS) map each operand flush against a `PROT_NONE` page, once
ending at it and once starting after one, for every length from 1 to 70 and
every GEMM depth from 1 to 9. A read or write one element past either end is a
fault. The fence itself was checked by a kernel deliberately reading one
element too far, which faults on amd64 (4 KiB pages), arm64 (16 KiB), loong64
(16 KiB) and ppc64le (64 KiB). Prefetch instructions may point past the end:
they are hints and do not fault.
- **Shapes are validated, results included.** A shape whose element count, or
whose size in bytes, does not fit in an `int` is an error wrapping
`ErrShapeMismatch`, even when a zero dimension makes it empty, as in NumPy.
This applies to the shapes operations compute: `MatMul`, `Dot`, `Inner`,
`Concatenate`, `Stack`, broadcasting and `Linspace`. `Outer` has no error
result and panics instead.
- **Empty arrays cost nothing.** Operations on an empty array with a huge axis,
such as `(2^58, 0)`, return at once instead of walking that axis.
`TestEmptyArraysWithHugeAxesReturnPromptly` covers concatenation, the axis
reductions and the scans.

The minimum Go version (`go` in `go.mod`) is kept on a release that fixes the
standard library's known vulnerabilities; `govulncheck ./...` reports none.

## Audit log

**2026-10-04 (v0.3.0).**

- `govulncheck` found no reachable vulnerability. At `go 1.26.4`, 10 standard
library vulnerabilities were in modules the library requires but did not
call; `go 1.26.6` fixes all of them.
- Found and fixed:
- `Concatenate` summed the axis lengths without an overflow check, so 17
arrays of shape `(2^59, 0)` gave a **negative** dimension.
- `MatMul` of `(2^32, 0)` by `(0, 2^32)` returned a `(2^32, 2^32)` array whose
`Size()` was 0. A product wrapping to −1 panicked in `makeslice`.
- `Linspace` with a count above the limit panicked in `makeslice`.
- `Stack` of 9 arrays `(2^58, 0)` returned `(9, 2^58, 0)`, which `New`
rejects.
- Reducing `(2^58, 0)` over axis 0, concatenating it along its last axis, or
scanning `(0, 2^58)` walked the 2^58-long axis: effectively a hang.
- Hardened: the operand checks in front of every assembly call (above). The
fence test found no out-of-bounds access in any kernel, on real amd64
(Zen 3), arm64, ppc64le (POWER9) and loong64 (3C5000L, with LASX).
- Cost: none measurable. A single-core A/B on Zen 3 (10 interleaved rounds)
measured `MatMul` 256², `Dot1D` and `AddInto` 16 Ki within ±2%, inside the
run-to-run spread.
1 change: 1 addition & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ nav:
- Home: index.md
- Roadmap: roadmap.md
- Performance: performance.md
- Security: security.md

markdown_extensions:
- admonition
Expand Down
Loading