Skip to content

Changes to add wheels for 3.13t/3.14t#208

Merged
vineetbansal merged 7 commits into
masterfrom
vb/py313t
May 27, 2026
Merged

Changes to add wheels for 3.13t/3.14t#208
vineetbansal merged 7 commits into
masterfrom
vb/py313t

Conversation

@vineetbansal
Copy link
Copy Markdown
Contributor

@vineetbansal vineetbansal commented May 25, 2026

Both these commits are thanks to Claude Code! The first one was just poor C on my part, which was always technically a bug but only showed up as a segfault in python 3.13t which has aggressive memory management. Here is the summary from claude:

  The pattern: py::array_t<T> objects were being destroyed before the OSQP C function consumed their data, in two ways:

  1. Block-scope destruction (update_data_mat, adjoint_derivative_compute):
  if (!P_x.is_none()) {
      auto _P_x_array = py::array_t<OSQPFloat>(P_x);  // local to this block
      _P_x = (OSQPFloat *)_P_x_array.data();
  }   // ← _P_x_array destroyed HERE; _P_x is now dangling
  osqp_update_data_mat(..., _P_x, ...);  // reads freed memory

  2. Temporary destruction at semicolon (warm_start, update_data_vec, adjoint_derivative_get_vec):
  _x = (OSQPFloat *)py::array_t<OSQPFloat>(x).data();
  //                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ temporary, destroyed at ';'
  osqp_warm_start(this->_solver, _x, ...);  // reads freed memory

  Why it worked on 3.13 but not 3.13t: Regular CPython uses a pooled allocator that doesn't zero or immediately reuse freed memory. Python 3.13t uses mimalloc,
   which is designed for concurrent use and reuses freed memory aggressively — so the next allocation in the same function (e.g., py::array_t<OSQPInt>(P_i))
  overwrites the just-freed float buffer, causing corruption and a segfault.

The second commit is related to cmake being able to find the correct python interpreter (and avoid the situation where it finds a 3.13 where it should be finding a 3.13t. Again, here is the summary from claude:

setup.py.jinja passes -DPYTHON_EXECUTABLE (pybind11's old variable), but pybind11 in "compatibility mode" still falls through to
cmake's FindPython which picks up the conda Python from PATH instead of the freethreaded one. On 3.13 this is harmless (same ABI), but on 3.13t the built .so
 gets the wrong name (cpython-313 instead of cpython-313t).

The fix is to also pass -DPython_EXECUTABLE and force PYBIND11_FINDPYTHON=NEW so cmake's FindPython respects the explicit path:

Note that we're still not saying that we'll work correctly without the GIL and we're asking it to be enabled (by not saying py::mod_gil_not_used() in our bindings - that's a separate issue.

I've gone through all changes carefully and they make sense, though I'll also run the second commit by @henryiii just to get his thoughts on this.

@vineetbansal vineetbansal requested a review from imciner2 May 25, 2026 17:49
@vineetbansal vineetbansal changed the title Changes to support Python 3.13t Changes to add wheels for 3.13t/3.14t May 25, 2026
@vineetbansal vineetbansal merged commit 4ade1ba into master May 27, 2026
21 of 22 checks passed
@henryiii
Copy link
Copy Markdown

I wouldn't worry about 3.13t. It was experimental and is being removed from cibuildwheel, pybind11, etc. Just focus on 3.14t+.

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.

3 participants