jump-dev / MathOptInterface.jl

A data structure for mathematical optimization problems
http://jump.dev/MathOptInterface.jl/
Other
387 stars 87 forks source link

ReverseAD doesn't error for out-of-bound writes #2440

Closed odow closed 6 months ago

odow commented 6 months ago

Test added by https://github.com/jump-dev/MathOptInterface.jl/pull/2438 did not allocate enough space for Hessian, but no error was thrown.

Caused GC fault in https://github.com/jump-dev/MathOptInterface.jl/pull/2439

See https://github.com/jump-dev/MathOptInterface.jl/blob/2ea481baaf3bc097bedcb36a90c16a98be9dd11f/src/Nonlinear/ReverseAD/forward_over_reverse.jl#L109-L116

Test needs to be

function test_timers()
    x = MOI.VariableIndex(1)
    model = Nonlinear.Model()
    Nonlinear.set_objective(model, :(log($x)))
    Nonlinear.add_constraint(model, :(sin($x)), MOI.LessThan(0.5))
    evaluator = Nonlinear.Evaluator(model, Nonlinear.SparseReverseMode(), [x])
    y = [1.2]
    g = [NaN]
    MOI.initialize(evaluator, [:Grad, :Jac, :Hess])
    MOI.eval_objective(evaluator, y)
    MOI.eval_constraint(evaluator, g, y)
    MOI.eval_objective_gradient(evaluator, g, y)
    MOI.eval_constraint_gradient(evaluator, g, y, 1)
    J = zeros(length(MOI.jacobian_structure(evaluator)))
    MOI.eval_constraint_jacobian(evaluator, J, y)
    H = zeros(length(MOI.hessian_objective_structure(evaluator)))
    MOI.eval_hessian_objective(evaluator, H, y)
    H = zeros(length(MOI.hessian_constraint_structure(evaluator, 1)))
    MOI.eval_hessian_constraint(evaluator, H, y, 1)
    H = zeros(length(MOI.hessian_lagrangian_structure(evaluator)))
    MOI.eval_hessian_lagrangian(evaluator, H, y, 1.0, [1.0])
    timers = [
        evaluator.initialize_timer,
        evaluator.eval_objective_timer,
        evaluator.eval_constraint_timer,
        evaluator.eval_objective_gradient_timer,
        evaluator.eval_constraint_gradient_timer,
        evaluator.eval_constraint_jacobian_timer,
        evaluator.eval_hessian_objective_timer,
        evaluator.eval_hessian_constraint_timer,
        evaluator.eval_hessian_lagrangian_timer,
    ]
    @test all(>=(0.0), timers)
    if !Sys.iswindows()
        # Windows times only in milliseconds, which can be too coarse to
        # accurately measure and test.
        @test sum(timers) > 0.0
    end
    return
end