Skip to content

Commit c7ff4d6

Browse files
authored
Improve stacktrace of errors thrown from within a callback (#233)
1 parent 596b3a8 commit c7ff4d6

File tree

2 files changed

+33
-5
lines changed

2 files changed

+33
-5
lines changed

src/MOI_wrapper/MOI_wrapper.jl

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,7 @@ function _internal_callback(tree::Ptr{Cvoid}, info::Ptr{Cvoid})
232232
cb_data.callback_function(cb_data)
233233
catch ex
234234
glp_ios_terminate(tree)
235-
cb_data.exception = ex
235+
cb_data.exception = CapturedException(ex, catch_backtrace())
236236
end
237237
return Cint(0)
238238
end
@@ -1402,10 +1402,19 @@ function _solve_mip_problem(model::Optimizer)
14021402
#
14031403
# This next bit is _very_ important! See the note associated with
14041404
# set_callback.
1405-
if model.callback_data.exception isa InterruptException
1406-
model.solver_status = GLP_ESTOP
1407-
elseif model.callback_data.exception !== nothing
1408-
throw(model.callback_data.exception)
1405+
if model.callback_data.exception !== nothing
1406+
model.callback_data.exception::CapturedException
1407+
inner = model.callback_data.exception.ex
1408+
if inner isa InterruptException
1409+
model.solver_status = GLP_ESTOP
1410+
elseif inner isa MOI.InvalidCallbackUsage
1411+
# Special-case throwing InvalidCallbackUsage to preserve
1412+
# backwards compatibility. But it does mean that they don't have
1413+
# good backtraces...
1414+
throw(inner)
1415+
else
1416+
throw(model.callback_data.exception)
1417+
end
14091418
end
14101419
finally
14111420
for (column, lower, upper) in bounds_to_reset

test/MOI_callbacks.jl

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -577,6 +577,25 @@ function test_no_cache_InterruptException()
577577
return
578578
end
579579

580+
function test_no_cache_issue_232()
581+
model = GLPK.Optimizer()
582+
x = MOI.add_variable(model)
583+
MOI.add_constraint(model, x, MOI.ZeroOne())
584+
my_callback(args...) = error("FooBar")
585+
MOI.set(model, GLPK.CallbackFunction(), my_callback)
586+
try
587+
MOI.optimize!(model)
588+
# To ensure that if an error is not thrown from the callback we still
589+
# hit the catch block
590+
@assert false
591+
catch ex
592+
@test ex isa CapturedException
593+
@test occursin("my_callback", "$ex")
594+
@test occursin("FooBar", "$ex")
595+
end
596+
return
597+
end
598+
580599
end
581600

582601
TestCallbacks.runtests()

0 commit comments

Comments
 (0)