Skip to content

Audit CPLEX and Xpress _run_file / _build_direct for license-slot leaks #696

@FBumann

Description

@FBumann

Follow-up from #695 (the broader audit triggered by #679).

After fixing the Mosek/COPT/MindOpt probe and _run_file leaks, two solvers remain unaudited because they have no explicit cleanup and rely on the wrapper's __del__:

CPLEX

In Cplex._run_file (linopy/solvers.py:1765):

m = cplex.Cplex()
...
return self._make_result(status, solution, solver_model=m)

m is stored as solver_model and is only ever cleared by Solver.close() setting it to None. The Cplex Python API recommends an explicit m.end() to release the model and the underlying license slot. Whether dropping the reference reliably calls end() via __del__ is library-internal — needs verification with a real CPLEX license.

Xpress

In Xpress._run_file (linopy/solvers.py:2213) and Xpress._build_direct (linopy/solvers.py:2032):

m = xpress.problem()
m.read(...)
...
return self._solve(m, ...)

Same shape — m is the license-bearing object, stored as solver_model, no explicit m.reset() / equivalent.

Suggested approach

  • Register cleanup on _env_stack (e.g. self._env_stack.callback(m.end) for CPLEX) so close() releases the slot deterministically.
  • Verify with a real license that calling end() is idempotent and doesn't break the result accessors that other tests rely on.

Why this wasn't in #695

I don't have CPLEX or Xpress licensed locally and didn't want to ship a "fix" that only works in theory and might break working solver paths in CI. Tagging this so anyone with a CPLEX/Xpress license can pick it up.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions