Skip to content

Various nanobind memory fixes#4299

Merged
garth-wells merged 18 commits into
mainfrom
garth/nanobind
Jul 18, 2026
Merged

Various nanobind memory fixes#4299
garth-wells merged 18 commits into
mainfrom
garth/nanobind

Conversation

@garth-wells

@garth-wells garth-wells commented Jul 18, 2026

Copy link
Copy Markdown
Member

Various nanobind memory fixes and improvements, and style improvements.

garth-wells and others added 10 commits July 13, 2026 23:51
- la.petsc.create_matrix: use nb::steal instead of nb::borrow, which
  leaked the Mat/Python wrapper on every call.
- Scatterer.scatter_fwd: fix a bounds check that compared local_data's
  size against remote_indices().size() instead of local_indices().size(),
  the array it's actually indexed by.
- mesh.Geometry.__init__: validate 0 < shape[1] <= 3 before padding to
  3D; an (N, >3) input previously wrote past the padded buffer.
- geometry point-distance functions (compute_distance_gjk,
  compute_distances_gjk, squared_distance, determine_point_ownership):
  add a shared validation helper so a point array's last dimension is
  checked against 3, instead of being assumed.
- fem.FiniteElement.T_apply/Tt_apply/Tt_inv_apply: guard against
  division by zero when cell_permutations is empty.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Geometry.dofmaps: fix reference_internal being a no-op on ndarrays
  appended to an nb::list return value (it only applies to the outer
  return, not per-element). Take nb::object self and pass it as the
  explicit owner of each ndarray, restoring genuine zero-copy views
  instead of copying on every access.
- create_mesh (both overloads): drop ~30 lines of duplicated Python
  partitioner marshalling logic, reusing the existing
  part::impl::create_cell_partitioner_cpp helper already used by
  create_interval/create_rectangle/create_box.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The dim > 3 check regressed to only checking the upper bound, silently
allowing shape1 == 0 (a degenerate, dimensionless Geometry) even though
the error message still documents 0 < dim <= 3. Not an out-of-bounds
issue (the padding loop simply runs zero times), but inconsistent with
the stated and intended constraint.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…nal to original_cell_indices

The setter for original_cell_index unconditionally resized to 1,
silently truncating data for a mixed-topology mesh whose getter
already rejects that case. original_cell_indices was missing
reference_internal, causing an unnecessary copy on every access.
assert(bc) was stripped by NDEBUG in Release builds, letting a None
DirichletBC in a Python-supplied list dereference a null pointer;
replaced with a real throw. discrete_curl/discrete_gradient/
interpolation_matrix leaked the newly created Mat if building the
operator threw; now destroyed on the exception path. create_matrix
no longer duplicates the Mat type-caster's take_ownership logic by
hand, and the repeated IndexMap-pair conversion is factored into a
single to_index_map_refs helper.
Only Mat and Vec had a registered type_caster, so create_index_sets
and NewtonSolver.krylov_solver had to hand-roll the same
PyPetscXxx_New/PetscObjectDereference dance; added IS and KSP casters
and simplified both call sites to use them. Also widened the
from_cpp rv_policy fallback to treat automatic/reference_internal
the same as reference/automatic_reference instead of silently
returning a null handle.
from_cpp only handled automatic/automatic_reference/reference_internal,
silently returning a null handle for reference/take_ownership (the
mirror of the gap just fixed in caster_petsc.h). Since MPICommWrapper
always wraps a plain handle by value, invert the check to allow every
policy except none. Also mark the single-argument MPI_Comm constructor
explicit to prevent accidental implicit conversions.
_V begins with an underscore followed by an uppercase letter, which
is reserved to the implementation; renamed to VDecay. Also assert
that the caller-supplied shape's element count matches the vector's
actual size, since a mismatch would silently produce a numpy view
that reads past the underlying buffer.
Each of these previously relied only on assert() (compiled out under
the Release/NDEBUG build used by the shipped wheel) or had no check
at all, letting out-of-range indices from Python reach raw
vector/array writes:

- common.cpp: create_sub_index_map's indices array
- refinement.cpp: transfer_cell_meshtag/transfer_facet_meshtag's
  parent_cell/parent_facet arrays
- refinement.h: refine()'s edges array
- la.h: MatrixCSR.add/set's rows array and x/rows/cols size
  consistency
- graph.h: AdjacencyList(data, offsets) constructor's offsets
  consistency (non-decreasing, starts at 0, matches data length)
@garth-wells garth-wells added the nanobind Issues related to nanobindings label Jul 18, 2026
garth-wells and others added 7 commits July 18, 2026 08:55
The bounds check added for heap-corruption hardening compared rows
against num_all_rows() unconditionally, but that count is only correct
when the insertion block size (bs) matches the matrix's own block
size. When they differ (e.g. inserting unblocked bs=1 indices into a
blocked bs=2 matrix, or vice versa), the valid index range must be
scaled by the ratio between the two block sizes, mirroring the three
cases MatrixCSR::add/set dispatch on internally. Fixes CI failures in
test_matrix_csr.py::test_add and ::test_set_blocked.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@garth-wells
garth-wells marked this pull request as ready for review July 18, 2026 14:09
@garth-wells
garth-wells added this pull request to the merge queue Jul 18, 2026
Merged via the queue into main with commit c873465 Jul 18, 2026
20 checks passed
@garth-wells
garth-wells deleted the garth/nanobind branch July 18, 2026 15:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

nanobind Issues related to nanobindings

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant