Skip to content

Fix ctypes memory safety and enrich tests#35

Merged
chkwon merged 1 commit into
masterfrom
fix/ctypes-memory-safety
May 19, 2026
Merged

Fix ctypes memory safety and enrich tests#35
chkwon merged 1 commit into
masterfrom
fix/ctypes-memory-safety

Conversation

@chkwon
Copy link
Copy Markdown
Owner

@chkwon chkwon commented May 19, 2026

Summary

  • Plug a C-side memory leak. delete_solution was only called on the happy path. If RoutingSolution extraction raised mid-construction, the C-allocated Solution (plus every route's path buffer) leaked. Wrapped the extraction in try/finally.
  • Stop relying on undocumented numpy behavior for buffer lifetime. The old arr.astype(c_double).ctypes + cast(...) idiom never bound the temporary ndarray to a local — it survived only via numpy's _ctypes proxy back-reference. Replaced with named np.ascontiguousarray(arr, dtype=np.float64) locals + .ctypes.data_as(c_double_p), which pins the buffer through the C call and removes up to two redundant n² copies of the distance matrix (the old code did reshape followed by an always-copying astype).
  • Enrich the test suite (5 → 15 tests). Added regressions for the two fixes, dtype/contiguity variants (float32, non-C-contiguous dist_mtx, int demands, list coords), input-validation assertions, solver reuse, and CVRP solution invariants (every customer visited exactly once, depot not in route bodies, capacity respected).
  • Modernize CI Python matrix from ["3.11", "3.10"] to ["3.10", "3.13"].

Coverage on hygese/hygese.py is now 95% (8 missed lines are platform-specific branches like Windows-only and solve_tsp via coords).

Test plan

  • pytest hygese/tests/ -v — all 15 tests pass locally on macOS / Python 3.13 (~16 s).
  • pytest --cov=hygese hygese/tests/ — coverage on hygese/hygese.py at 95%, with the new try/finally and ascontiguousarray paths fully covered.
  • Exception-path regression: test_delete_called_on_exception monkey-patches RoutingSolution.__init__ to raise and asserts delete_solution is still invoked exactly once.
  • Zero-copy fast path: np.shares_memory(x, np.ascontiguousarray(x, dtype=np.float64)) is True when x is already float64/C-contiguous.
  • CI green on ubuntu-latest / windows-2019 / macos-latest × Python 3.10 / 3.13.

🤖 Generated with Claude Code

- Wrap RoutingSolution extraction in try/finally so delete_solution
  always runs even if extraction raises.
- Replace arr.astype(c_double).ctypes + cast(...) with named
  np.ascontiguousarray locals + .ctypes.data_as(c_double_p) so the
  numpy buffer is pinned through the C call. Also removes up to two
  redundant n^2 copies of the distance matrix.
- Add tests covering the new exception path, dtype/contiguity
  variants, input validation, solver reuse, and CVRP solution
  invariants.
- Bump CI Python matrix to 3.10 and 3.13.
- Bump version to 0.1.0.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@chkwon chkwon force-pushed the fix/ctypes-memory-safety branch from a4a50e6 to 7423f5f Compare May 19, 2026 10:49
@chkwon chkwon merged commit 1685a9b into master May 19, 2026
4 of 6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant