Summary
For a problem containing a quadratic constraint, cuOptGetDualSolution
writes more elements than reported by cuOptGetNumConstraints.
This overruns a correctly sized caller-owned buffer.
Environment
- cuOpt 26.08.0
- Git hash:
400863c1
- CUDA 13.3
- GPU: NVIDIA RTX PRO 6000 Blackwell Workstation Edition
Standalone C reproducer
#include <cuopt/mathematical_optimization/cuopt_c.h>
#include <math.h>
#include <stdio.h>
int main(void)
{
cuOptOptimizationProblem problem = NULL;
cuOptSolverSettings settings = NULL;
cuOptSolution solution = NULL;
/*
* minimize t
*
* subject to
* t >= 0
* x1^2 + x2^2 - t^2 <= 0
* t >= -1
* x1 >= 3
* x2 >= 4
*/
const cuopt_int_t num_constraints = 1;
const cuopt_int_t num_variables = 3;
const cuopt_float_t objective[] = {1.0, 0.0, 0.0};
const cuopt_int_t row_offsets[] = {0, 1};
const cuopt_int_t column_indices[] = {0};
const cuopt_float_t matrix_values[] = {1.0};
const char constraint_sense[] = {CUOPT_GREATER_THAN};
const cuopt_float_t rhs[] = {0.0};
const cuopt_float_t lower_bounds[] = {-1.0, 3.0, 4.0};
const cuopt_float_t upper_bounds[] = {
CUOPT_INFINITY,
CUOPT_INFINITY,
CUOPT_INFINITY
};
const char variable_types[] = {
CUOPT_CONTINUOUS,
CUOPT_CONTINUOUS,
CUOPT_CONTINUOUS
};
cuopt_int_t status = cuOptCreateProblem(
num_constraints,
num_variables,
CUOPT_MINIMIZE,
0.0,
objective,
row_offsets,
column_indices,
matrix_values,
constraint_sense,
rhs,
lower_bounds,
upper_bounds,
variable_types,
&problem
);
if (status != CUOPT_SUCCESS) {
printf("cuOptCreateProblem failed: %d\n", status);
return 1;
}
const cuopt_int_t qc_row[] = {0, 1, 2};
const cuopt_int_t qc_col[] = {0, 1, 2};
const cuopt_float_t qc_coeff[] = {-1.0, 1.0, 1.0};
status = cuOptAddQuadraticConstraint(
problem,
3,
qc_row,
qc_col,
qc_coeff,
0,
NULL,
NULL,
CUOPT_LESS_THAN,
0.0
);
if (status != CUOPT_SUCCESS) {
printf("cuOptAddQuadraticConstraint failed: %d\n", status);
return 1;
}
cuopt_int_t queried_num_constraints = -1;
status = cuOptGetNumConstraints(problem, &queried_num_constraints);
if (status != CUOPT_SUCCESS) {
printf("cuOptGetNumConstraints failed: %d\n", status);
return 1;
}
printf("cuOptGetNumConstraints = %d\n", queried_num_constraints);
status = cuOptCreateSolverSettings(&settings);
if (status != CUOPT_SUCCESS) {
printf("cuOptCreateSolverSettings failed: %d\n", status);
return 1;
}
status = cuOptSetIntegerParameter(
settings,
CUOPT_METHOD,
CUOPT_METHOD_BARRIER
);
if (status != CUOPT_SUCCESS) {
printf("cuOptSetIntegerParameter failed: %d\n", status);
return 1;
}
status = cuOptSolve(problem, settings, &solution);
if (status != CUOPT_SUCCESS) {
printf("cuOptSolve failed: %d\n", status);
return 1;
}
/*
* Use an oversized sentinel buffer so the out-of-bounds writes can be
* observed without corrupting unrelated memory.
*/
const cuopt_float_t sentinel = 1.234567890123456e200;
cuopt_float_t guarded[64];
for (int i = 0; i < 64; ++i) {
guarded[i] = sentinel;
}
status = cuOptGetDualSolution(solution, guarded);
printf("cuOptGetDualSolution status = %d\n", status);
for (int i = 0; i < 64; ++i) {
if (guarded[i] != sentinel) {
printf("changed[%d] = %g\n", i, guarded[i]);
}
}
cuOptDestroySolution(&solution);
cuOptDestroySolverSettings(&settings);
cuOptDestroyProblem(&problem);
return 0;
}
Output
cuOptGetNumConstraints = 1
cuOptGetDualSolution status = 0
changed[0] = nan
changed[1] = nan
changed[2] = nan
changed[3] = nan
Recommended fix options:
- Return invalid argument when querying
cuOptGetDualSolution in this scenario
- Copy only numConstraints elements into the solution vector
Summary
For a problem containing a quadratic constraint,
cuOptGetDualSolutionwrites more elements than reported by
cuOptGetNumConstraints.This overruns a correctly sized caller-owned buffer.
Environment
400863c1Standalone C reproducer
Output
Recommended fix options:
cuOptGetDualSolutionin this scenario