Skip to content

Commit 8024d2d

Browse files
Fix segfault when calling getSolTime on infeasible model's solution (#1167)
1 parent 89d0391 commit 8024d2d

File tree

3 files changed

+26
-1
lines changed

3 files changed

+26
-1
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
- Speed up MatrixExpr.sum(axis=...) via quicksum
88
- Added structured_optimization_trace recipe for structured optimization progress tracking
99
### Fixed
10+
- getBestSol() now returns None for infeasible problems instead of a Solution with NULL pointer
1011
- all fundamental callbacks now raise an error if not implemented
1112
- Fixed the type of MatrixExpr.sum(axis=...) result from MatrixVariable to MatrixExpr.
1213
- Updated IIS result in PyiisfinderExec()

src/pyscipopt/scip.pxi

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10651,7 +10651,10 @@ cdef class Model:
1065110651
Solution or None
1065210652
1065310653
"""
10654-
self._bestSol = Solution.create(self._scip, SCIPgetBestSol(self._scip))
10654+
cdef SCIP_SOL* _sol = SCIPgetBestSol(self._scip)
10655+
if _sol == NULL:
10656+
return None
10657+
self._bestSol = Solution.create(self._scip, _sol)
1065510658
return self._bestSol
1065610659

1065710660
def getSolObjVal(self, Solution sol, original=True):
@@ -10694,6 +10697,8 @@ cdef class Model:
1069410697
float
1069510698
1069610699
"""
10700+
if sol is None or sol.sol == NULL:
10701+
raise ValueError("Cannot get solution time: solution is None or NULL")
1069710702
return SCIPgetSolTime(self._scip, sol.sol)
1069810703

1069910704
def getObjVal(self, original=True):

tests/test_solution.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,25 @@ def test_getSolTime():
127127
assert m.getSolTime(s) >= 0
128128

129129

130+
def test_getBestSol_infeasible():
131+
"""Test that getBestSol returns None for infeasible problems instead of segfaulting."""
132+
m = Model()
133+
m.hideOutput()
134+
135+
x = m.addVar(ub=2)
136+
m.addCons(x >= 4) # infeasible: x <= 2 but x >= 4
137+
138+
m.optimize()
139+
140+
assert m.getStatus() == "infeasible"
141+
sol = m.getBestSol()
142+
assert sol is None
143+
144+
# getSolTime should raise ValueError for None solution
145+
with pytest.raises(ValueError):
146+
m.getSolTime(sol)
147+
148+
130149
def test_hasPrimalRay():
131150
m = Model()
132151
x = m.addVar()

0 commit comments

Comments
 (0)