Fix issues uncovered via coverity scanning
Related: RHEL-120814
This commit is contained in:
parent
07ecb81a04
commit
35d1d1cb22
379
bundled-highs-coverity-fixes.patch
Normal file
379
bundled-highs-coverity-fixes.patch
Normal file
@ -0,0 +1,379 @@
|
||||
From e9525346e36552686c6f9266c7388791bb27cb0b Mon Sep 17 00:00:00 2001
|
||||
From: fwesselm <fwesselm@mathworks.com>
|
||||
Date: Wed, 11 Dec 2024 15:55:52 +0100
|
||||
Subject: [PATCH 1/7] Fix detection of implied integral (already
|
||||
integer-constrained) variables and implicit (continuous) integer variables
|
||||
|
||||
---
|
||||
subprojects/highs/src/presolve/HPresolve.cpp | 24 +++++++++++++-------
|
||||
1 file changed, 16 insertions(+), 8 deletions(-)
|
||||
|
||||
diff --git a/subprojects/highs/src/presolve/HPresolve.cpp b/subprojects/highs/src/presolve/HPresolve.cpp
|
||||
index 5360c9e..d6dd158 100644
|
||||
--- a/subprojects/highs/src/presolve/HPresolve.cpp
|
||||
+++ b/subprojects/highs/src/presolve/HPresolve.cpp
|
||||
@@ -223,6 +223,7 @@ void HPresolve::dualImpliedFreeGetRhsAndRowType(
|
||||
}
|
||||
|
||||
bool HPresolve::isImpliedIntegral(HighsInt col) {
|
||||
+ // check if the integer constraint on a variable is implied by the model
|
||||
bool runDualDetection = true;
|
||||
|
||||
assert(model->integrality_[col] == HighsVarType::kInteger);
|
||||
@@ -263,10 +264,15 @@ bool HPresolve::isImpliedIntegral(HighsInt col) {
|
||||
|
||||
if (!runDualDetection) return false;
|
||||
|
||||
+ bool impliedIntegral = true;
|
||||
for (const HighsSliceNonzero& nz : getColumnVector(col)) {
|
||||
double scale = 1.0 / nz.value();
|
||||
- if (!rowCoefficientsIntegral(nz.index(), scale)) return false;
|
||||
+ // if row coefficients are not integral, variable is not (implied) integral
|
||||
+ bool rowIntegral = rowCoefficientsIntegral(nz.index(), scale);
|
||||
+ impliedIntegral = impliedIntegral && rowIntegral;
|
||||
+ if (!rowIntegral) continue;
|
||||
if (model->row_upper_[nz.index()] != kHighsInf) {
|
||||
+ // scale, round down and unscale right-hand side again
|
||||
double rUpper =
|
||||
std::abs(nz.value()) *
|
||||
std::floor(model->row_upper_[nz.index()] * std::abs(scale) +
|
||||
@@ -276,24 +282,26 @@ bool HPresolve::isImpliedIntegral(HighsInt col) {
|
||||
model->row_upper_[nz.index()] = rUpper;
|
||||
markChangedRow(nz.index());
|
||||
}
|
||||
- } else {
|
||||
- assert(model->row_lower_[nz.index()] != -kHighsInf);
|
||||
+ }
|
||||
+ if (model->row_lower_[nz.index()] != -kHighsInf) {
|
||||
+ // scale, round up and unscale left-hand side again
|
||||
double rLower =
|
||||
std::abs(nz.value()) *
|
||||
- std::ceil(model->row_upper_[nz.index()] * std::abs(scale) -
|
||||
+ std::ceil(model->row_lower_[nz.index()] * std::abs(scale) -
|
||||
primal_feastol);
|
||||
if (std::abs(model->row_lower_[nz.index()] - rLower) >
|
||||
options->small_matrix_value) {
|
||||
- model->row_upper_[nz.index()] = rLower;
|
||||
+ model->row_lower_[nz.index()] = rLower;
|
||||
markChangedRow(nz.index());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- return true;
|
||||
+ return impliedIntegral;
|
||||
}
|
||||
|
||||
bool HPresolve::isImpliedInteger(HighsInt col) {
|
||||
+ // check if a non-integer variable is implied integer
|
||||
bool runDualDetection = true;
|
||||
|
||||
assert(model->integrality_[col] == HighsVarType::kContinuous);
|
||||
@@ -345,11 +353,11 @@ bool HPresolve::isImpliedInteger(HighsInt col) {
|
||||
for (const HighsSliceNonzero& nz : getColumnVector(col)) {
|
||||
double scale = 1.0 / nz.value();
|
||||
if (model->row_upper_[nz.index()] != kHighsInf &&
|
||||
- fractionality(model->row_upper_[nz.index()]) > primal_feastol)
|
||||
+ fractionality(model->row_upper_[nz.index()] * scale) > primal_feastol)
|
||||
return false;
|
||||
|
||||
if (model->row_lower_[nz.index()] != -kHighsInf &&
|
||||
- fractionality(model->row_lower_[nz.index()]) > primal_feastol)
|
||||
+ fractionality(model->row_lower_[nz.index()] * scale) > primal_feastol)
|
||||
return false;
|
||||
|
||||
if (!rowCoefficientsIntegral(nz.index(), scale)) return false;
|
||||
--
|
||||
2.53.0
|
||||
|
||||
|
||||
From 7f75cc45101d393b4247e0eec00c59dc2c46f58e Mon Sep 17 00:00:00 2001
|
||||
From: Ivet Galabova <galabovaa@gmail.com>
|
||||
Date: Mon, 13 Jan 2025 16:57:56 +0000
|
||||
Subject: [PATCH 2/7] free gpu memory, localtermination wip
|
||||
|
||||
---
|
||||
subprojects/highs/src/pdlp/CupdlpWrapper.cpp | 55 +++++++++++++------
|
||||
.../highs/src/pdlp/cupdlp/cupdlp_linalg.c | 13 +++++
|
||||
2 files changed, 51 insertions(+), 17 deletions(-)
|
||||
|
||||
diff --git a/subprojects/highs/src/pdlp/CupdlpWrapper.cpp b/subprojects/highs/src/pdlp/CupdlpWrapper.cpp
|
||||
index 31fa31e..8d905da 100644
|
||||
--- a/subprojects/highs/src/pdlp/CupdlpWrapper.cpp
|
||||
+++ b/subprojects/highs/src/pdlp/CupdlpWrapper.cpp
|
||||
@@ -66,8 +66,6 @@ HighsStatus solveLpCupdlp(const HighsOptions& options, HighsTimer& timer,
|
||||
0.0; // true objVal = sig * c'x - offset, sig = 1 (min) or -1 (max)
|
||||
double sense_origin = 1; // 1 (min) or -1 (max)
|
||||
int* constraint_new_idx = NULL;
|
||||
- cupdlp_float* x_origin = cupdlp_NULL;
|
||||
- cupdlp_float* y_origin = cupdlp_NULL;
|
||||
|
||||
void* model = NULL;
|
||||
void* presolvedmodel = NULL;
|
||||
@@ -159,8 +157,6 @@ HighsStatus solveLpCupdlp(const HighsOptions& options, HighsTimer& timer,
|
||||
// CUPDLP_CALL(LP_SolvePDHG(prob, ifChangeIntParam, intParam,
|
||||
// ifChangeFloatParam, floatParam, fp));
|
||||
|
||||
- cupdlp_init_double(x_origin, nCols_origin);
|
||||
- cupdlp_init_double(y_origin, nRows);
|
||||
// Resize the highs_solution so cuPDLP-c can use it internally
|
||||
highs_solution.col_value.resize(lp.num_col_);
|
||||
highs_solution.row_value.resize(lp.num_row_);
|
||||
@@ -208,19 +204,31 @@ HighsStatus solveLpCupdlp(const HighsOptions& options, HighsTimer& timer,
|
||||
analysePdlpSolution(options, lp, highs_solution);
|
||||
#endif
|
||||
|
||||
- free(cost);
|
||||
- free(lower);
|
||||
- free(upper);
|
||||
- free(csc_beg);
|
||||
- free(csc_idx);
|
||||
- free(csc_val);
|
||||
- free(rhs);
|
||||
+ // free(cost);
|
||||
+ // free(lower);
|
||||
+ // free(upper);
|
||||
+ // free(csc_beg);
|
||||
+ // free(csc_idx);
|
||||
+ // free(csc_val);
|
||||
+ // free(rhs);
|
||||
|
||||
- free(x_origin);
|
||||
- free(y_origin);
|
||||
+ // free(constraint_new_idx);
|
||||
|
||||
- free(constraint_new_idx);
|
||||
+ // Scaling
|
||||
+#ifdef CUPDLP_CPU
|
||||
|
||||
+ if (scaling->rowScale != nullptr) free(scaling->rowScale);
|
||||
+ if (scaling->colScale != nullptr) free(scaling->colScale);
|
||||
+ free(scaling);
|
||||
+
|
||||
+#else
|
||||
+ // free problem
|
||||
+ if (scaling) {
|
||||
+ scaling_clear(scaling);
|
||||
+ }
|
||||
+#endif
|
||||
+
|
||||
+#ifdef CUPDLP_CPU
|
||||
free(prob->cost);
|
||||
free(prob->lower);
|
||||
free(prob->upper);
|
||||
@@ -248,10 +256,23 @@ HighsStatus solveLpCupdlp(const HighsOptions& options, HighsTimer& timer,
|
||||
free(csc_cpu->colMatElem);
|
||||
|
||||
free(csc_cpu);
|
||||
+#endif
|
||||
|
||||
- if (scaling->rowScale != nullptr) free(scaling->rowScale);
|
||||
- if (scaling->colScale != nullptr) free(scaling->colScale);
|
||||
- free(scaling);
|
||||
+ if (cost != NULL) cupdlp_free(cost);
|
||||
+ if (csc_beg != NULL) cupdlp_free(csc_beg);
|
||||
+ if (csc_idx != NULL) cupdlp_free(csc_idx);
|
||||
+ if (csc_val != NULL) cupdlp_free(csc_val);
|
||||
+ if (rhs != NULL) cupdlp_free(rhs);
|
||||
+ if (lower != NULL) cupdlp_free(lower);
|
||||
+ if (upper != NULL) cupdlp_free(upper);
|
||||
+ if (constraint_new_idx != NULL) cupdlp_free(constraint_new_idx);
|
||||
+
|
||||
+ // constraint type is std::vector
|
||||
+ // if (constraint_type != NULL) cupdlp_free(constraint_type);
|
||||
+
|
||||
+ // free memory
|
||||
+ csc_clear(csc_cpu);
|
||||
+ problem_clear(prob);
|
||||
|
||||
return HighsStatus::kOk;
|
||||
}
|
||||
diff --git a/subprojects/highs/src/pdlp/cupdlp/cupdlp_linalg.c b/subprojects/highs/src/pdlp/cupdlp/cupdlp_linalg.c
|
||||
index 8d28043..bf3e2fe 100644
|
||||
--- a/subprojects/highs/src/pdlp/cupdlp/cupdlp_linalg.c
|
||||
+++ b/subprojects/highs/src/pdlp/cupdlp/cupdlp_linalg.c
|
||||
@@ -801,3 +801,16 @@ void cupdlp_compute_interaction_and_movement(CUPDLPwork *w,
|
||||
cupdlp_sub(w->buffer3, iterates->aty->data, iterates->atyUpdate->data, nCols);
|
||||
cupdlp_dot(w, nCols, w->buffer2, w->buffer3, dInteraction);
|
||||
}
|
||||
+
|
||||
+double get_fabs_value(double* vec, int index) {
|
||||
+#ifdef CUPDLP_CPU
|
||||
+ return vec[index];
|
||||
+#else
|
||||
+ double result = 0;
|
||||
+ int status = -1;
|
||||
+ get_gpu_vec_element(vec, index, &result, &status);
|
||||
+ if (!status)
|
||||
+ return 0;
|
||||
+ return result;
|
||||
+#endif
|
||||
+}
|
||||
\ No newline at end of file
|
||||
--
|
||||
2.53.0
|
||||
|
||||
|
||||
From 9efff0fc9ae0eb870ea8f6b5742ea9e17c90de52 Mon Sep 17 00:00:00 2001
|
||||
From: Julian Hall <jajhall@ed.ac.uk>
|
||||
Date: Thu, 11 Dec 2025 20:23:13 +0000
|
||||
Subject: [PATCH 3/7] Modify version and URL for HiGHS release
|
||||
|
||||
Updated version and URL in CITATION.cff
|
||||
---
|
||||
subprojects/highs/CITATION.cff | 8 ++------
|
||||
1 file changed, 2 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/subprojects/highs/CITATION.cff b/subprojects/highs/CITATION.cff
|
||||
index 0987d34..da14abc 100644
|
||||
--- a/subprojects/highs/CITATION.cff
|
||||
+++ b/subprojects/highs/CITATION.cff
|
||||
@@ -6,14 +6,10 @@ authors:
|
||||
email: HighsOpt@gmail.com
|
||||
- given-names: Ivet
|
||||
family-names: Galabova
|
||||
-- given-names: Leona
|
||||
- family-names: Gottwald
|
||||
-- given-names: Michael
|
||||
- family-names: Feldmeier
|
||||
title: "HiGHS"
|
||||
-version: 1.2.2
|
||||
+version: 1.12.0
|
||||
date-released: 2022-04-18
|
||||
-url: "https://github.com/ERGO-Code/HiGHS/releases/tag/v1.2.2"
|
||||
+url: "https://github.com/ERGO-Code/HiGHS/releases/tag/v1.12.0"
|
||||
preferred-citation:
|
||||
type: article
|
||||
authors:
|
||||
--
|
||||
2.53.0
|
||||
|
||||
|
||||
From 7d971de3169912e449b2d2f8ab00f9f7be0968f0 Mon Sep 17 00:00:00 2001
|
||||
From: Charalampos Stratakis <cstratak@redhat.com>
|
||||
Date: Fri, 19 Dec 2025 17:42:13 +0100
|
||||
Subject: [PATCH 4/7] Fix use-after-close in writeSolution when ranging fails
|
||||
|
||||
Add missing return statement after returnFromWriteSolution() call
|
||||
when getRangingInterface() returns an error, preventing fprintf()
|
||||
from writing to an already-closed file handle.
|
||||
---
|
||||
subprojects/highs/src/lp_data/Highs.cpp | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/subprojects/highs/src/lp_data/Highs.cpp b/subprojects/highs/src/lp_data/Highs.cpp
|
||||
index c1c3254..a175f1c 100644
|
||||
--- a/subprojects/highs/src/lp_data/Highs.cpp
|
||||
+++ b/subprojects/highs/src/lp_data/Highs.cpp
|
||||
@@ -3272,7 +3272,7 @@ HighsStatus Highs::writeSolution(const std::string& filename,
|
||||
interpretCallStatus(options_.log_options, this->getRangingInterface(),
|
||||
return_status, "getRangingInterface");
|
||||
if (return_status == HighsStatus::kError)
|
||||
- returnFromWriteSolution(file, return_status);
|
||||
+ return returnFromWriteSolution(file, return_status);
|
||||
fprintf(file, "\n# Ranging\n");
|
||||
writeRangingFile(file, model_.lp_, info_.objective_function_value, basis_,
|
||||
solution_, ranging_, style);
|
||||
--
|
||||
2.53.0
|
||||
|
||||
|
||||
From d7a19c9fad468ca4b8e094da67ea2d8cc3760e7f Mon Sep 17 00:00:00 2001
|
||||
From: Charalampos Stratakis <cstratak@redhat.com>
|
||||
Date: Mon, 22 Dec 2025 02:02:25 +0100
|
||||
Subject: [PATCH 5/7] mip: Fix use-after-move in HighsLpRelaxation::loadModel
|
||||
|
||||
Save lpmodel.num_col_ before passing lpmodel via std::move to
|
||||
lpsolver.passModel(). After the move, lpmodel is in a valid but
|
||||
unspecified state, making access to its members undefined behavior.
|
||||
|
||||
Found by Coverity static analysis.
|
||||
---
|
||||
subprojects/highs/src/mip/HighsLpRelaxation.cpp | 5 +++--
|
||||
1 file changed, 3 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/subprojects/highs/src/mip/HighsLpRelaxation.cpp b/subprojects/highs/src/mip/HighsLpRelaxation.cpp
|
||||
index 4288f99..58e0e4d 100644
|
||||
--- a/subprojects/highs/src/mip/HighsLpRelaxation.cpp
|
||||
+++ b/subprojects/highs/src/mip/HighsLpRelaxation.cpp
|
||||
@@ -222,11 +222,12 @@ void HighsLpRelaxation::loadModel() {
|
||||
for (HighsInt i = 0; i != lpmodel.num_row_; ++i)
|
||||
lprows.push_back(LpRow::model(i));
|
||||
lpmodel.integrality_.clear();
|
||||
+ HighsInt num_col = lpmodel.num_col_;
|
||||
lpsolver.clearSolver();
|
||||
lpsolver.clearModel();
|
||||
lpsolver.passModel(std::move(lpmodel));
|
||||
- colLbBuffer.resize(lpmodel.num_col_);
|
||||
- colUbBuffer.resize(lpmodel.num_col_);
|
||||
+ colLbBuffer.resize(num_col);
|
||||
+ colUbBuffer.resize(num_col);
|
||||
}
|
||||
|
||||
void HighsLpRelaxation::resetToGlobalDomain() {
|
||||
--
|
||||
2.53.0
|
||||
|
||||
|
||||
From cba9eba8aed879bc6335d3f4d43a5cd9f891e854 Mon Sep 17 00:00:00 2001
|
||||
From: Charalampos Stratakis <cstratak@redhat.com>
|
||||
Date: Wed, 14 Jan 2026 04:50:19 +0100
|
||||
Subject: [PATCH 6/7] BUG: initialize save_value field to fix uninitialized
|
||||
memory use
|
||||
|
||||
When a HighsSimplexBadBasisChangeRecord is created, save_value is not
|
||||
set until later in applyTabooRowOut/applyTabooVariableIn. Pushing the
|
||||
struct with an uninitialized field copies garbage memory.
|
||||
|
||||
Found via Coverity static analysis
|
||||
---
|
||||
subprojects/highs/src/simplex/SimplexStruct.h | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/subprojects/highs/src/simplex/SimplexStruct.h b/subprojects/highs/src/simplex/SimplexStruct.h
|
||||
index eb49c8c..996dcc4 100644
|
||||
--- a/subprojects/highs/src/simplex/SimplexStruct.h
|
||||
+++ b/subprojects/highs/src/simplex/SimplexStruct.h
|
||||
@@ -258,7 +258,7 @@ struct HighsSimplexBadBasisChangeRecord {
|
||||
HighsInt variable_out;
|
||||
HighsInt variable_in;
|
||||
BadBasisChangeReason reason;
|
||||
- double save_value;
|
||||
+ double save_value = 0.0;
|
||||
};
|
||||
|
||||
#endif /* SIMPLEX_SIMPLEXSTRUCT_H_ */
|
||||
--
|
||||
2.53.0
|
||||
|
||||
|
||||
From ee47ee8895c789980a1e90d8e0c17f54a69b4440 Mon Sep 17 00:00:00 2001
|
||||
From: Charalampos Stratakis <cstratak@redhat.com>
|
||||
Date: Wed, 28 Jan 2026 01:23:57 +0100
|
||||
Subject: [PATCH 7/7] Initialize nowactiveatlower in ratiotest_textbook
|
||||
|
||||
The nowactiveatlower field was only set inside the conditional blocks
|
||||
when a limiting constraint was found (alpha_i < result.alpha). If both
|
||||
loops completed without finding a limiting constraint, the field remained
|
||||
uninitialized.
|
||||
|
||||
Uncovered by Coverity static analysis
|
||||
---
|
||||
subprojects/highs/src/qpsolver/ratiotest.cpp | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/subprojects/highs/src/qpsolver/ratiotest.cpp b/subprojects/highs/src/qpsolver/ratiotest.cpp
|
||||
index dd313c4..424f695 100644
|
||||
--- a/subprojects/highs/src/qpsolver/ratiotest.cpp
|
||||
+++ b/subprojects/highs/src/qpsolver/ratiotest.cpp
|
||||
@@ -17,6 +17,7 @@ static RatiotestResult ratiotest_textbook(Runtime& rt, const QpVector& p,
|
||||
RatiotestResult result;
|
||||
result.limitingconstraint = -1;
|
||||
result.alpha = alphastart;
|
||||
+ result.nowactiveatlower = false;
|
||||
|
||||
// check ratio towards variable bounds
|
||||
for (HighsInt j = 0; j < p.num_nz; j++) {
|
||||
--
|
||||
2.53.0
|
||||
|
||||
70
bundled-xfs-coverity-fixes.patch
Normal file
70
bundled-xfs-coverity-fixes.patch
Normal file
@ -0,0 +1,70 @@
|
||||
From 7f973498c9c628cd4f1d04272ea9bf81ec150912 Mon Sep 17 00:00:00 2001
|
||||
From: Charalampos Stratakis <cstratak@redhat.com>
|
||||
Date: Sat, 20 Dec 2025 01:40:34 +0100
|
||||
Subject: [PATCH 1/2] BUG: amos/amos.h: fix pointer dereference in uni2
|
||||
|
||||
The code was performing pointer arithmetic instead of incrementing
|
||||
the value, unlike the identical pattern in uni1.
|
||||
|
||||
Found by coverity static analysis.
|
||||
---
|
||||
subprojects/xsf/include/xsf/amos/amos.h | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/subprojects/xsf/include/xsf/amos/amos.h b/subprojects/xsf/include/xsf/amos/amos.h
|
||||
index 08d4ef5..48c0fff 100644
|
||||
--- a/subprojects/xsf/include/xsf/amos/amos.h
|
||||
+++ b/subprojects/xsf/include/xsf/amos/amos.h
|
||||
@@ -5304,7 +5304,7 @@ namespace amos {
|
||||
// SET UNDERFLOW AND UPDATE PARAMETERS
|
||||
//
|
||||
y[nd - 1] = 0.0;
|
||||
- nz += 1;
|
||||
+ *nz += 1;
|
||||
nd -= 1;
|
||||
if (nd == 0) {
|
||||
return;
|
||||
@@ -5312,7 +5312,7 @@ namespace amos {
|
||||
nuf = uoik(z, fnu, kode, 1, nd, y, tol, elim, alim);
|
||||
if (nuf >= 0) {
|
||||
nd -= nuf;
|
||||
- nz += nuf;
|
||||
+ *nz += nuf;
|
||||
if (nd == 0) {
|
||||
return;
|
||||
}
|
||||
--
|
||||
2.53.0
|
||||
|
||||
|
||||
From 8ff3b3f02eb7e35f3741a72c078ba49f8b8de3db Mon Sep 17 00:00:00 2001
|
||||
From: Charalampos Stratakis <cstratak@redhat.com>
|
||||
Date: Wed, 28 Jan 2026 01:54:42 +0100
|
||||
Subject: [PATCH 2/2] BUG: specfun/specfun.h: initialize kd in mtu12 to fix
|
||||
potential uninitialized use
|
||||
|
||||
The kd variable was not initialized before the kf==1/kf==2 conditional
|
||||
blocks. If kf had an unexpected value, kd would be used uninitialized
|
||||
when passed to cva2(). Initialize to 0 for consistency with mtu0.
|
||||
|
||||
Uncovered by Coverity static analysis.
|
||||
---
|
||||
subprojects/xsf/include/xsf/specfun/specfun.h | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/subprojects/xsf/include/xsf/specfun/specfun.h b/subprojects/xsf/include/xsf/specfun/specfun.h
|
||||
index 6247601..a5a3ac6 100644
|
||||
--- a/subprojects/xsf/include/xsf/specfun/specfun.h
|
||||
+++ b/subprojects/xsf/include/xsf/specfun/specfun.h
|
||||
@@ -4759,7 +4759,7 @@ namespace specfun {
|
||||
|
||||
T eps = 1.0e-14;
|
||||
T a, qm, c1, c2, u1, u2, w1, w2;
|
||||
- int kd, km, ic, k, nm = 0;
|
||||
+ int kd = 0, km, ic, k, nm = 0;
|
||||
|
||||
if ((kf == 1) && (m % 2 == 0)) {
|
||||
kd = 1;
|
||||
--
|
||||
2.53.0
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
Summary: Scientific Tools for Python
|
||||
Name: python%{python3_pkgversion}-scipy
|
||||
Version: 1.16.2
|
||||
Release: 2%{?dist}
|
||||
Release: 3%{?dist}
|
||||
|
||||
# BSD-3-Clause -- whole package except:
|
||||
# BSD-2-Clause -- scipy/_lib/_pep440.py
|
||||
@ -78,6 +78,39 @@ Source2: https://github.com/mesonbuild/meson/releases/download/1.4.1/meson-1.
|
||||
# Compatibility patch for meson 1.4.1
|
||||
Patch: compatibility-with-meson-1.4.1.patch
|
||||
|
||||
# Coverity scan fixes for scipy
|
||||
# Backported from upstream:
|
||||
# https://github.com/scipy/scipy/pull/24211
|
||||
# https://github.com/scipy/scipy/pull/24202
|
||||
# https://github.com/scipy/scipy/pull/24204
|
||||
# https://github.com/scipy/scipy/pull/24206
|
||||
# https://github.com/scipy/scipy/pull/24220
|
||||
# https://github.com/scipy/scipy/pull/24219
|
||||
# https://github.com/scipy/scipy/pull/24453
|
||||
# https://github.com/scipy/scipy/pull/24368
|
||||
# https://github.com/scipy/scipy/pull/24373
|
||||
# https://github.com/scipy/scipy/pull/24455
|
||||
# https://github.com/scipy/scipy/pull/24209
|
||||
# https://github.com/scipy/scipy/pull/24374
|
||||
# https://github.com/scipy/scipy/pull/24384
|
||||
Patch: scipy-coverity-fixes.patch
|
||||
|
||||
# Coverity scan fixes for the bundled HiGHS project
|
||||
# Backported from upstream
|
||||
# https://github.com/ERGO-Code/HiGHS/pull/2711
|
||||
# https://github.com/ERGO-Code/HiGHS/commit/f175850569ffbb2aba55b7645cec19c0132d8e63
|
||||
# https://github.com/ERGO-Code/HiGHS/commit/1f86a97198609680ce3c950401ae056e3d7aca39
|
||||
# https://github.com/ERGO-Code/HiGHS/pull/2713
|
||||
# https://github.com/ERGO-Code/HiGHS/pull/2778
|
||||
# https://github.com/ERGO-Code/HiGHS/pull/2747
|
||||
Patch: bundled-highs-coverity-fixes.patch
|
||||
|
||||
# Coverity scan fixes for the bundled xfs project
|
||||
# Backported from upstream:
|
||||
# https://github.com/scipy/xsf/pull/86
|
||||
# https://github.com/scipy/xsf/pull/91
|
||||
Patch: bundled-xfs-coverity-fixes.patch
|
||||
|
||||
BuildRequires: %{blaslib}-devel
|
||||
BuildRequires: gcc-gfortran, gcc-c++
|
||||
|
||||
@ -297,6 +330,10 @@ popd
|
||||
|
||||
|
||||
%changelog
|
||||
* Tue Feb 10 2026 Charalampos Stratakis <cstratak@redhat.com> - 1.16.2-3
|
||||
- Fix issues uncovered via coverity scanning
|
||||
Related: RHEL-120814
|
||||
|
||||
* Wed Jan 28 2026 Lumir Balhar <lbalhar@redhat.com> - 1.16.2-2
|
||||
- Rebuild with newer Cython
|
||||
|
||||
|
||||
741
scipy-coverity-fixes.patch
Normal file
741
scipy-coverity-fixes.patch
Normal file
@ -0,0 +1,741 @@
|
||||
From 0d941ffeac1ac04a6d76890bdf114d898267d488 Mon Sep 17 00:00:00 2001
|
||||
From: Charalampos Stratakis <cstratak@redhat.com>
|
||||
Date: Sat, 20 Dec 2025 00:39:36 +0100
|
||||
Subject: [PATCH 01/15] BUG: ndimage: fix potential double-free in
|
||||
NI_InitFilterOffsets
|
||||
|
||||
Null out offset pointers after freeing them in the error path of
|
||||
NI_InitFilterOffsets. Without this, callers that also free these
|
||||
pointers in their cleanup code could trigger a double-free if the
|
||||
function fails after allocation.
|
||||
|
||||
Found by Coverity static analysis.
|
||||
---
|
||||
scipy/ndimage/src/ni_support.c | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
diff --git a/scipy/ndimage/src/ni_support.c b/scipy/ndimage/src/ni_support.c
|
||||
index a6e3ff0..934ac74 100644
|
||||
--- a/scipy/ndimage/src/ni_support.c
|
||||
+++ b/scipy/ndimage/src/ni_support.c
|
||||
@@ -734,8 +734,10 @@ int NI_InitFilterOffsets(PyArrayObject *array, npy_bool *footprint,
|
||||
exit:
|
||||
if (PyErr_Occurred()) {
|
||||
free(*offsets);
|
||||
+ *offsets = NULL;
|
||||
if (coordinate_offsets) {
|
||||
free(*coordinate_offsets);
|
||||
+ *coordinate_offsets = NULL;
|
||||
}
|
||||
return 0;
|
||||
} else {
|
||||
--
|
||||
2.53.0
|
||||
|
||||
|
||||
From 51ec935d77be786ce3b5e8b95c5fa23a4dd3dbe7 Mon Sep 17 00:00:00 2001
|
||||
From: Charalampos Stratakis <cstratak@redhat.com>
|
||||
Date: Sat, 20 Dec 2025 01:08:47 +0100
|
||||
Subject: [PATCH 02/15] BUG: signal/_firfilter.cc: fix out-of-bounds read in
|
||||
pylab_convolve_2d
|
||||
|
||||
Move the type_num bounds check before using it as an array index.
|
||||
Previously, OneMultAdd[type_num] was accessed before validating that
|
||||
type_num was within bounds, which could cause an out-of-bounds read
|
||||
when passed an unsupported array dtype.
|
||||
|
||||
Also fix off-by-one error via changing > MAXTYPES to >= MAXTYPES since
|
||||
the arrays have MAXTYPES-1 elements.
|
||||
|
||||
Found by Coverity static analysis scan.
|
||||
---
|
||||
scipy/signal/_firfilter.cc | 3 ++-
|
||||
1 file changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/scipy/signal/_firfilter.cc b/scipy/signal/_firfilter.cc
|
||||
index 9636961..b1f3f19 100644
|
||||
--- a/scipy/signal/_firfilter.cc
|
||||
+++ b/scipy/signal/_firfilter.cc
|
||||
@@ -180,10 +180,11 @@ int pylab_convolve_2d (char *in, /* Input data Ns[0] x Ns[1] */
|
||||
const int type_num = (flag & TYPE_MASK) >> TYPE_SHIFT;
|
||||
/*type_size*/
|
||||
|
||||
+ if (type_num < 0 || type_num >= MAXTYPES) return -4; /* Invalid type */
|
||||
+
|
||||
OneMultAddFunction *mult_and_add = OneMultAdd[type_num];
|
||||
if (mult_and_add == NULL) return -5; /* Not available for this type */
|
||||
|
||||
- if (type_num < 0 || type_num > MAXTYPES) return -4; /* Invalid type */
|
||||
const int type_size = elsizes[type_num];
|
||||
|
||||
int64_t Os[2];
|
||||
--
|
||||
2.53.0
|
||||
|
||||
|
||||
From 94b1d8ee75e0cbf37bd970b70ba1e120d4d47d19 Mon Sep 17 00:00:00 2001
|
||||
From: Charalampos Stratakis <cstratak@redhat.com>
|
||||
Date: Sat, 20 Dec 2025 01:20:43 +0100
|
||||
Subject: [PATCH 03/15] BUG: optimize/__lbfgsb.c: fix pointer arithmetic bug in
|
||||
cauchy function
|
||||
|
||||
Change nseg += 1 to *nseg += 1 to increment the segment counter
|
||||
value rather than performing pointer arithmetic on the pointer itself.
|
||||
|
||||
Found by Coverity static analysis.
|
||||
---
|
||||
scipy/optimize/__lbfgsb.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/scipy/optimize/__lbfgsb.c b/scipy/optimize/__lbfgsb.c
|
||||
index 306f6d6..4a1dc98 100644
|
||||
--- a/scipy/optimize/__lbfgsb.c
|
||||
+++ b/scipy/optimize/__lbfgsb.c
|
||||
@@ -1694,7 +1694,7 @@ cauchy(int n, double* x, double* l, double* u,
|
||||
}
|
||||
|
||||
// Update the derivative information.
|
||||
- nseg += 1;
|
||||
+ *nseg += 1;
|
||||
dibp2 = pow(dibp, 2.0);
|
||||
|
||||
// Update f1 and f2
|
||||
--
|
||||
2.53.0
|
||||
|
||||
|
||||
From 7e65e5528db55cffb8814ecdb51e9573060695e2 Mon Sep 17 00:00:00 2001
|
||||
From: Charalampos Stratakis <cstratak@redhat.com>
|
||||
Date: Sat, 20 Dec 2025 03:43:12 +0100
|
||||
Subject: [PATCH 04/15] BUG: optimize/tnc/tnc.c: fix uninitialized xoffset when
|
||||
scale is provided
|
||||
|
||||
When calling tnc() with a non-NULL scale array but NULL offset array,
|
||||
and scale[i] != 0.0, the xoffset[i] element was never initialized.
|
||||
|
||||
The uninitialized value was then read in tnc_minimize() -> scalex().
|
||||
|
||||
Found via Coverity scan analysis.
|
||||
---
|
||||
scipy/optimize/tnc/tnc.c | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
diff --git a/scipy/optimize/tnc/tnc.c b/scipy/optimize/tnc/tnc.c
|
||||
index 0b06d0e..d902dbf 100644
|
||||
--- a/scipy/optimize/tnc/tnc.c
|
||||
+++ b/scipy/optimize/tnc/tnc.c
|
||||
@@ -353,6 +353,8 @@ int tnc(int n, double x[], double *f, double g[], tnc_function * function,
|
||||
xscale[i] = fabs(scale[i]);
|
||||
if (xscale[i] == 0.0) {
|
||||
xoffset[i] = low[i] = up[i] = x[i];
|
||||
+ } else {
|
||||
+ xoffset[i] = x[i];
|
||||
}
|
||||
} else if (low[i] != -HUGE_VAL && up[i] != HUGE_VAL) {
|
||||
xscale[i] = up[i] - low[i];
|
||||
--
|
||||
2.53.0
|
||||
|
||||
|
||||
From c7da8ee0aa7a24fe937467de4b845b0c222519ba Mon Sep 17 00:00:00 2001
|
||||
From: SoheilStar <75124326+soheil-star01@users.noreply.github.com>
|
||||
Date: Sat, 20 Dec 2025 23:21:11 +0200
|
||||
Subject: [PATCH 05/15] BUG: optimize: Remove redundant conditional in
|
||||
_shgo.sampling_custom
|
||||
|
||||
Both if and else branches executed the same code. Simplifies to a
|
||||
single assignment as confirmed by the original author.
|
||||
---
|
||||
scipy/optimize/_shgo.py | 5 +----
|
||||
1 file changed, 1 insertion(+), 4 deletions(-)
|
||||
|
||||
diff --git a/scipy/optimize/_shgo.py b/scipy/optimize/_shgo.py
|
||||
index b98a4b5..5fe0899 100644
|
||||
--- a/scipy/optimize/_shgo.py
|
||||
+++ b/scipy/optimize/_shgo.py
|
||||
@@ -1458,10 +1458,7 @@ class SHGO:
|
||||
"""
|
||||
# Generate sampling points.
|
||||
# Generate uniform sample points in [0, 1]^m \subset R^m
|
||||
- if self.n_sampled == 0:
|
||||
- self.C = self.sampling_function(n, dim)
|
||||
- else:
|
||||
- self.C = self.sampling_function(n, dim)
|
||||
+ self.C = self.sampling_function(n, dim)
|
||||
# Distribute over bounds
|
||||
for i in range(len(self.bounds)):
|
||||
self.C[:, i] = (self.C[:, i] *
|
||||
--
|
||||
2.53.0
|
||||
|
||||
|
||||
From e07ace4aa764caef5c5abe2b8aa1982bb0348164 Mon Sep 17 00:00:00 2001
|
||||
From: Charalampos Stratakis <cstratak@redhat.com>
|
||||
Date: Mon, 22 Dec 2025 01:40:36 +0100
|
||||
Subject: [PATCH 06/15] BUG: sparse.linalg: Fix copy-paste error in
|
||||
get_OPinv_matvec
|
||||
|
||||
In the type check condition for matrix M, is_pydata_spmatrix() was
|
||||
incorrectly called with A instead of M.
|
||||
---
|
||||
scipy/sparse/linalg/_eigen/arpack/arpack.py | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/scipy/sparse/linalg/_eigen/arpack/arpack.py b/scipy/sparse/linalg/_eigen/arpack/arpack.py
|
||||
index f678dea..0c70bf9 100644
|
||||
--- a/scipy/sparse/linalg/_eigen/arpack/arpack.py
|
||||
+++ b/scipy/sparse/linalg/_eigen/arpack/arpack.py
|
||||
@@ -1084,7 +1084,7 @@ def get_OPinv_matvec(A, M, sigma, hermitian=False, tol=0):
|
||||
M, sigma, tol=tol).matvec
|
||||
else:
|
||||
if ((not isdense(A) and not issparse(A) and not is_pydata_spmatrix(A)) or
|
||||
- (not isdense(M) and not issparse(M) and not is_pydata_spmatrix(A))):
|
||||
+ (not isdense(M) and not issparse(M) and not is_pydata_spmatrix(M))):
|
||||
return IterOpInv(aslinearoperator(A),
|
||||
aslinearoperator(M),
|
||||
sigma, tol=tol).matvec
|
||||
--
|
||||
2.53.0
|
||||
|
||||
|
||||
From c3d3b109da83c889a12cb1735b31ed5466b4066e Mon Sep 17 00:00:00 2001
|
||||
From: Charalampos Stratakis <cstratak@redhat.com>
|
||||
Date: Mon, 22 Dec 2025 02:23:55 +0100
|
||||
Subject: [PATCH 07/15] BUG: optimize/_direct: Fix memory leaks in
|
||||
direct_direct_()
|
||||
|
||||
Two early return paths bypassed the cleanup section, leaking all
|
||||
allocated memory (13 malloc'd buffers).
|
||||
|
||||
After direct_dirinit_() failure changed return NULL to goto
|
||||
cleanup. The ret variable is already NULL in this case.
|
||||
|
||||
After Python callback failure set ret = NULL and goto cleanup
|
||||
to ensure proper memory deallocation.
|
||||
|
||||
Found by Coverity static analysis.
|
||||
---
|
||||
scipy/optimize/_direct/DIRect.c | 5 +++--
|
||||
1 file changed, 3 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/scipy/optimize/_direct/DIRect.c b/scipy/optimize/_direct/DIRect.c
|
||||
index 05249fa..9ec6a42 100644
|
||||
--- a/scipy/optimize/_direct/DIRect.c
|
||||
+++ b/scipy/optimize/_direct/DIRect.c
|
||||
@@ -455,7 +455,7 @@
|
||||
fmax, &ifeasiblef, &iinfesiblef, ierror, args, jones,
|
||||
force_stop);
|
||||
if (!ret) {
|
||||
- return NULL;
|
||||
+ goto cleanup;
|
||||
}
|
||||
/* +-----------------------------------------------------------------------+ */
|
||||
/* | Added error checking. | */
|
||||
@@ -773,7 +773,8 @@
|
||||
PyObject* callback_py = PyObject_CallObject(callback, arg_tuple);
|
||||
Py_DECREF(arg_tuple);
|
||||
if( !callback_py ) {
|
||||
- return NULL;
|
||||
+ ret = NULL;
|
||||
+ goto cleanup;
|
||||
}
|
||||
}
|
||||
/* L10: */
|
||||
--
|
||||
2.53.0
|
||||
|
||||
|
||||
From 6f4515431ceb479e788255e5b0041670a4d28a6d Mon Sep 17 00:00:00 2001
|
||||
From: Charalampos Stratakis <cstratak@redhat.com>
|
||||
Date: Tue, 13 Jan 2026 23:07:38 +0100
|
||||
Subject: [PATCH 08/15] BUG: fix freeing of uninitialized memory in error paths
|
||||
in ndimage
|
||||
|
||||
Initialize pointer arrays immediately after allocation and error check,
|
||||
before any jumps to cleanup code. Previously, if an allocation failed
|
||||
after data_offsets, offsets, or splvals were allocated but before
|
||||
their elements were initialized, the cleanup code would attempt to free
|
||||
uninitialized pointers.
|
||||
|
||||
Found via Coverity scan analysis
|
||||
---
|
||||
scipy/ndimage/src/ni_interpolation.c | 22 ++++++++++++++--------
|
||||
1 file changed, 14 insertions(+), 8 deletions(-)
|
||||
|
||||
diff --git a/scipy/ndimage/src/ni_interpolation.c b/scipy/ndimage/src/ni_interpolation.c
|
||||
index f0f86a7..5a11419 100644
|
||||
--- a/scipy/ndimage/src/ni_interpolation.c
|
||||
+++ b/scipy/ndimage/src/ni_interpolation.c
|
||||
@@ -301,6 +301,8 @@ NI_GeometricTransform(PyArrayObject *input, int (*map)(npy_intp*, double*,
|
||||
PyErr_NoMemory();
|
||||
goto exit;
|
||||
}
|
||||
+ for(jj = 0; jj < irank; jj++)
|
||||
+ data_offsets[jj] = NULL;
|
||||
|
||||
if (mode == NI_EXTEND_GRID_CONSTANT) {
|
||||
// boolean indicating if the current point in the filter footprint is
|
||||
@@ -323,8 +325,6 @@ NI_GeometricTransform(PyArrayObject *input, int (*map)(npy_intp*, double*,
|
||||
}
|
||||
}
|
||||
|
||||
- for(jj = 0; jj < irank; jj++)
|
||||
- data_offsets[jj] = NULL;
|
||||
for(jj = 0; jj < irank; jj++) {
|
||||
data_offsets[jj] = malloc((order + 1) * sizeof(npy_intp));
|
||||
if (NPY_UNLIKELY(!data_offsets[jj])) {
|
||||
@@ -717,19 +717,25 @@ int NI_ZoomShift(PyArrayObject *input, PyArrayObject* zoom_ar,
|
||||
}
|
||||
/* store offsets, along each axis: */
|
||||
offsets = malloc(rank * sizeof(npy_intp*));
|
||||
+ if (NPY_UNLIKELY(!offsets)) {
|
||||
+ NPY_END_THREADS;
|
||||
+ PyErr_NoMemory();
|
||||
+ goto exit;
|
||||
+ }
|
||||
+ for(jj = 0; jj < rank; jj++)
|
||||
+ offsets[jj] = NULL;
|
||||
+
|
||||
/* store spline coefficients, along each axis: */
|
||||
splvals = malloc(rank * sizeof(double**));
|
||||
- /* store offsets at all edges: */
|
||||
-
|
||||
- if (NPY_UNLIKELY(!offsets || !splvals)) {
|
||||
+ if (NPY_UNLIKELY(!splvals)) {
|
||||
NPY_END_THREADS;
|
||||
PyErr_NoMemory();
|
||||
goto exit;
|
||||
}
|
||||
- for(jj = 0; jj < rank; jj++) {
|
||||
- offsets[jj] = NULL;
|
||||
+ for(jj = 0; jj < rank; jj++)
|
||||
splvals[jj] = NULL;
|
||||
- }
|
||||
+
|
||||
+ /* store offsets at all edges: */
|
||||
for(jj = 0; jj < rank; jj++) {
|
||||
offsets[jj] = malloc(odimensions[jj] * sizeof(npy_intp));
|
||||
splvals[jj] = malloc(odimensions[jj] * sizeof(double*));
|
||||
--
|
||||
2.53.0
|
||||
|
||||
|
||||
From 329c6a1df8fbe16c8d59b4a8b58abe29ec03284e Mon Sep 17 00:00:00 2001
|
||||
From: Charalampos Stratakis <cstratak@redhat.com>
|
||||
Date: Wed, 14 Jan 2026 04:14:29 +0100
|
||||
Subject: [PATCH 09/15] BUG: fix uninitialized variables in odr
|
||||
|
||||
The if-else clauses handling pwe and pwd arrays had no terminal
|
||||
else clause. If an object passed validation but didn't match any
|
||||
handling branch, ldwe,ld2we,ldwd and ld2wd would be used uninitialized.
|
||||
|
||||
Add else clauses to ensure all code paths either initialize these
|
||||
variables or exit with an error.
|
||||
|
||||
Found via Coverity static analysis
|
||||
---
|
||||
scipy/odr/__odrpack.c | 8 ++++++++
|
||||
1 file changed, 8 insertions(+)
|
||||
|
||||
diff --git a/scipy/odr/__odrpack.c b/scipy/odr/__odrpack.c
|
||||
index f86a65f..2027166 100644
|
||||
--- a/scipy/odr/__odrpack.c
|
||||
+++ b/scipy/odr/__odrpack.c
|
||||
@@ -780,6 +780,10 @@ PyObject *odr(PyObject * self, PyObject * args, PyObject * kwds)
|
||||
PYERR(PyExc_ValueError, "could not convert we to a suitable array");
|
||||
}
|
||||
} /* we */
|
||||
+ else
|
||||
+ {
|
||||
+ PYERR(PyExc_ValueError, "could not convert we to a suitable array");
|
||||
+ }
|
||||
|
||||
if (pwd == NULL)
|
||||
{
|
||||
@@ -871,6 +875,10 @@ PyObject *odr(PyObject * self, PyObject * args, PyObject * kwds)
|
||||
}
|
||||
|
||||
} /* wd */
|
||||
+ else
|
||||
+ {
|
||||
+ PYERR(PyExc_ValueError, "could not convert wd to a suitable array");
|
||||
+ }
|
||||
|
||||
|
||||
if (pifixb == NULL)
|
||||
--
|
||||
2.53.0
|
||||
|
||||
|
||||
From 9e52501a67a6e190bc81dbd91c4a14866639663c Mon Sep 17 00:00:00 2001
|
||||
From: Charalampos Stratakis <cstratak@redhat.com>
|
||||
Date: Wed, 14 Jan 2026 05:07:07 +0100
|
||||
Subject: [PATCH 10/15] BUG: fix uninitialized variable in ILU complex copy at
|
||||
sparse/SuperLU
|
||||
|
||||
The SMILU_3 case in the second loop of ilu_ccopy_to_ucol.c and
|
||||
ilu_zcopy_to_ucol.c used tmp which could be uninitialized. Compute
|
||||
the absolute value directly instead.
|
||||
|
||||
Found via Coverity static analysis
|
||||
---
|
||||
scipy/sparse/linalg/_dsolve/SuperLU/SRC/ilu_ccopy_to_ucol.c | 2 +-
|
||||
scipy/sparse/linalg/_dsolve/SuperLU/SRC/ilu_zcopy_to_ucol.c | 2 +-
|
||||
2 files changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/scipy/sparse/linalg/_dsolve/SuperLU/SRC/ilu_ccopy_to_ucol.c b/scipy/sparse/linalg/_dsolve/SuperLU/SRC/ilu_ccopy_to_ucol.c
|
||||
index 9817fe3..93a3c1b 100644
|
||||
--- a/scipy/sparse/linalg/_dsolve/SuperLU/SRC/ilu_ccopy_to_ucol.c
|
||||
+++ b/scipy/sparse/linalg/_dsolve/SuperLU/SRC/ilu_ccopy_to_ucol.c
|
||||
@@ -190,7 +190,7 @@ ilu_ccopy_to_ucol(
|
||||
c_add(sum, sum, &ucol[i]);
|
||||
break;
|
||||
case SMILU_3:
|
||||
- sum->r += tmp;
|
||||
+ sum->r += c_abs1(&ucol[i]);
|
||||
break;
|
||||
case SILU:
|
||||
default:
|
||||
diff --git a/scipy/sparse/linalg/_dsolve/SuperLU/SRC/ilu_zcopy_to_ucol.c b/scipy/sparse/linalg/_dsolve/SuperLU/SRC/ilu_zcopy_to_ucol.c
|
||||
index bb444d7..063d685 100644
|
||||
--- a/scipy/sparse/linalg/_dsolve/SuperLU/SRC/ilu_zcopy_to_ucol.c
|
||||
+++ b/scipy/sparse/linalg/_dsolve/SuperLU/SRC/ilu_zcopy_to_ucol.c
|
||||
@@ -190,7 +190,7 @@ ilu_zcopy_to_ucol(
|
||||
z_add(sum, sum, &ucol[i]);
|
||||
break;
|
||||
case SMILU_3:
|
||||
- sum->r += tmp;
|
||||
+ sum->r += z_abs1(&ucol[i]);
|
||||
break;
|
||||
case SILU:
|
||||
default:
|
||||
--
|
||||
2.53.0
|
||||
|
||||
|
||||
From 09b460c7de6e9c8ddabd52d4a49b7fbba4003d4a Mon Sep 17 00:00:00 2001
|
||||
From: ilayn <ilhanpolat@gmail.com>
|
||||
Date: Thu, 15 Jan 2026 18:10:05 +0100
|
||||
Subject: [PATCH 11/15] MAINT:optimize: Fix memleaks in DIRECT solver and
|
||||
ext.mod.
|
||||
|
||||
---
|
||||
scipy/optimize/_direct/DIRect.c | 6 +++++-
|
||||
scipy/optimize/_direct/DIRserial.c | 1 +
|
||||
scipy/optimize/_direct/DIRsubrout.c | 21 ++++++++++++++++++---
|
||||
scipy/optimize/_directmodule.c | 13 ++++++++++---
|
||||
4 files changed, 34 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/scipy/optimize/_direct/DIRect.c b/scipy/optimize/_direct/DIRect.c
|
||||
index 9ec6a42..85bdaed 100644
|
||||
--- a/scipy/optimize/_direct/DIRect.c
|
||||
+++ b/scipy/optimize/_direct/DIRect.c
|
||||
@@ -595,11 +595,15 @@
|
||||
/* +-----------------------------------------------------------------------+ */
|
||||
/* | JG 01/22/01 Added variable to keep track of the maximum value found. | */
|
||||
/* +-----------------------------------------------------------------------+ */
|
||||
- direct_dirsamplef_(c__, arrayi, &delta, &help, &start, length,
|
||||
+ Py_XDECREF(ret); /* DECREF previous return value before getting new one */
|
||||
+ ret = direct_dirsamplef_(c__, arrayi, &delta, &help, &start, length,
|
||||
logfile, f, &ifree, &maxi, point, fcn, &x[
|
||||
1], x_seq, &l[1], minf, &minpos, &u[1], n, &MAXFUNC, &
|
||||
MAXDEEP, &oops, &fmax, &ifeasiblef, &iinfesiblef,
|
||||
args, force_stop);
|
||||
+ if (!ret) {
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
if (force_stop && *force_stop) {
|
||||
*ierror = -102;
|
||||
*numiter = t;
|
||||
diff --git a/scipy/optimize/_direct/DIRserial.c b/scipy/optimize/_direct/DIRserial.c
|
||||
index 10a4870..c2c1688 100644
|
||||
--- a/scipy/optimize/_direct/DIRserial.c
|
||||
+++ b/scipy/optimize/_direct/DIRserial.c
|
||||
@@ -87,6 +87,7 @@
|
||||
if (force_stop && *force_stop) /* skip eval after forced stop */
|
||||
f[(pos << 1) + 1] = *fmax;
|
||||
else {
|
||||
+ Py_XDECREF(ret); /* DECREF previous iteration's return value */
|
||||
ret = direct_dirinfcn_(fcn, &x[1], x_seq, &l[1], &u[1], n, &f[(pos << 1) + 1],
|
||||
&kret, args);
|
||||
if (!ret) {
|
||||
diff --git a/scipy/optimize/_direct/DIRsubrout.c b/scipy/optimize/_direct/DIRsubrout.c
|
||||
index 35b10c7..718802f 100644
|
||||
--- a/scipy/optimize/_direct/DIRsubrout.c
|
||||
+++ b/scipy/optimize/_direct/DIRsubrout.c
|
||||
@@ -7,8 +7,19 @@
|
||||
#include <math.h>
|
||||
// #include "numpy/ndarrayobject.h"
|
||||
|
||||
-/* Table of constant values */
|
||||
-
|
||||
+/*
|
||||
+ * SCIPY NOTE (2026-01-15):
|
||||
+ * The following are read-only variables after initialization.
|
||||
+ *
|
||||
+ * They exist because f2c passes all arguments by reference (Fortran convention),
|
||||
+ * so literal constants need addresses. The code is still thread-safe since they
|
||||
+ * are never modified.
|
||||
+ *
|
||||
+ * Note: Cannot mark as 'const' due to f2c function signatures expecting non-const
|
||||
+ * pointers which makes the surgery more involved. Instead an f2c-free rewrite
|
||||
+ * is better for long-term maintenance.
|
||||
+ *
|
||||
+ */
|
||||
static integer c__1 = 1;
|
||||
static integer c__32 = 32;
|
||||
static integer c__0 = 0;
|
||||
@@ -1295,11 +1306,15 @@ L50:
|
||||
/* | JG 01/22/01 Added variable to keep track of the maximum value found. | */
|
||||
/* | Added variable to keep track if feasible point was found. | */
|
||||
/* +-----------------------------------------------------------------------+ */
|
||||
- direct_dirsamplef_(&c__[c_offset], &arrayi[1], &delta, &c__1, &new__, &length[
|
||||
+ Py_DECREF(ret); /* DECREF before overwriting with new return value */
|
||||
+ ret = direct_dirsamplef_(&c__[c_offset], &arrayi[1], &delta, &c__1, &new__, &length[
|
||||
length_offset], logfile, &f[3], free, maxi, &point[
|
||||
1], fcn, &x[1], x_seq, &l[1], minf, minpos, &u[1], n, maxfunc,
|
||||
maxdeep, &oops, fmax, ifeasiblef, iinfeasible, args,
|
||||
force_stop);
|
||||
+ if (!ret) {
|
||||
+ return NULL;
|
||||
+ }
|
||||
if (force_stop && *force_stop) {
|
||||
*ierror = -102;
|
||||
return ret;
|
||||
diff --git a/scipy/optimize/_directmodule.c b/scipy/optimize/_directmodule.c
|
||||
index d1bfb33..d21734d 100644
|
||||
--- a/scipy/optimize/_directmodule.c
|
||||
+++ b/scipy/optimize/_directmodule.c
|
||||
@@ -36,7 +36,7 @@ direct(PyObject *self, PyObject *args)
|
||||
|
||||
dimension = PyArray_DIMS((PyArrayObject*)lb)[0];
|
||||
x = (double *) malloc(sizeof(double) * (dimension + 1));
|
||||
- if (!(x)) {
|
||||
+ if (!x) {
|
||||
ret_code = DIRECT_OUT_OF_MEMORY;
|
||||
}
|
||||
PyObject *x_seq = PyList_New(dimension);
|
||||
@@ -46,17 +46,24 @@ direct(PyObject *self, PyObject *args)
|
||||
force_stop = 0;
|
||||
direct_return_info info;
|
||||
|
||||
- if (!direct_optimize(f, x, x_seq, f_args, dimension, lower_bounds,
|
||||
+ PyObject *direct_ret = direct_optimize(f, x, x_seq, f_args, dimension, lower_bounds,
|
||||
upper_bounds, &minf, max_feval, max_iter,
|
||||
magic_eps, magic_eps_abs, volume_reltol,
|
||||
sigma_reltol, &force_stop, fglobal, fglobal_reltol,
|
||||
- logfile, algorithm, &info, &ret_code, callback)) {
|
||||
+ logfile, algorithm, &info, &ret_code, callback);
|
||||
+ if (!direct_ret) {
|
||||
+ Py_DECREF(x_seq);
|
||||
if (x)
|
||||
free(x);
|
||||
return NULL;
|
||||
}
|
||||
+ /* DECREF the return value from direct_optimize - we only needed it for error checking */
|
||||
+ Py_DECREF(direct_ret);
|
||||
PyObject* ret_py = Py_BuildValue("Odiii", x_seq, minf, (int) ret_code,
|
||||
info.numfunc, info.numiter);
|
||||
+ /* Py_BuildValue with "O" increments refcount. We need to DECREF our
|
||||
+ original reference since the tuple now owns it. */
|
||||
+ Py_DECREF(x_seq);
|
||||
if (x)
|
||||
free(x);
|
||||
return ret_py;
|
||||
--
|
||||
2.53.0
|
||||
|
||||
|
||||
From ba52739d21f8cf3ee52775df23c05605143de74f Mon Sep 17 00:00:00 2001
|
||||
From: ilayn <ilhanpolat@gmail.com>
|
||||
Date: Thu, 15 Jan 2026 18:19:06 +0100
|
||||
Subject: [PATCH 12/15] MAINT:optimize: Enable multi-phase init to DIRECT
|
||||
|
||||
---
|
||||
scipy/optimize/_directmodule.c | 54 +++++++++++++++++++---------------
|
||||
1 file changed, 31 insertions(+), 23 deletions(-)
|
||||
|
||||
diff --git a/scipy/optimize/_directmodule.c b/scipy/optimize/_directmodule.c
|
||||
index d21734d..aa3a80b 100644
|
||||
--- a/scipy/optimize/_directmodule.c
|
||||
+++ b/scipy/optimize/_directmodule.c
|
||||
@@ -73,38 +73,46 @@ direct(PyObject *self, PyObject *args)
|
||||
* Standard Python module interface
|
||||
*/
|
||||
|
||||
-static PyMethodDef
|
||||
-DIRECTMethods[] = {
|
||||
+static struct PyMethodDef direct_module_methods[] = {
|
||||
{"direct", direct, METH_VARARGS, "DIRECT Optimization Algorithm"},
|
||||
{NULL, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
-static struct PyModuleDef moduledef = {
|
||||
- PyModuleDef_HEAD_INIT,
|
||||
- "_direct",
|
||||
- NULL,
|
||||
- -1,
|
||||
- DIRECTMethods,
|
||||
- NULL,
|
||||
- NULL,
|
||||
- NULL,
|
||||
- NULL
|
||||
-};
|
||||
|
||||
-PyMODINIT_FUNC
|
||||
-PyInit__direct(void)
|
||||
-{
|
||||
- PyObject *module;
|
||||
+static int module_exec(PyObject *module) {
|
||||
+ (void)module; /* unused */
|
||||
|
||||
- import_array();
|
||||
- module = PyModule_Create(&moduledef);
|
||||
- if (module == NULL) {
|
||||
- return module;
|
||||
- }
|
||||
+ if (_import_array() < 0) { return -1; }
|
||||
|
||||
#if Py_GIL_DISABLED
|
||||
PyUnstable_Module_SetGIL(module, Py_MOD_GIL_NOT_USED);
|
||||
#endif
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
|
||||
- return module;
|
||||
+static struct PyModuleDef_Slot direct_slots[] = {
|
||||
+ {Py_mod_exec, module_exec},
|
||||
+ {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED},
|
||||
+#if PY_VERSION_HEX >= 0x030d00f0 /* Python 3.13+ */
|
||||
+ /* signal that this module supports running without an active GIL */
|
||||
+ {Py_mod_gil, Py_MOD_GIL_NOT_USED},
|
||||
+#endif
|
||||
+ {0, NULL},
|
||||
+};
|
||||
+
|
||||
+
|
||||
+static struct PyModuleDef moduledef = {
|
||||
+ .m_base = PyModuleDef_HEAD_INIT,
|
||||
+ .m_name = "_direct",
|
||||
+ .m_size = 0,
|
||||
+ .m_methods = direct_module_methods,
|
||||
+ .m_slots = direct_slots
|
||||
+};
|
||||
+
|
||||
+
|
||||
+PyMODINIT_FUNC
|
||||
+PyInit__direct(void)
|
||||
+{
|
||||
+ return PyModuleDef_Init(&moduledef);
|
||||
}
|
||||
--
|
||||
2.53.0
|
||||
|
||||
|
||||
From da22a05e07ba8e88a1220be834b29de0ad975601 Mon Sep 17 00:00:00 2001
|
||||
From: ilayn <ilhanpolat@gmail.com>
|
||||
Date: Thu, 15 Jan 2026 20:51:09 +0100
|
||||
Subject: [PATCH 13/15] MAINT:optimize: Decref callback in DIRECT solver
|
||||
|
||||
---
|
||||
scipy/optimize/_direct/DIRect.c | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/scipy/optimize/_direct/DIRect.c b/scipy/optimize/_direct/DIRect.c
|
||||
index 85bdaed..16c6426 100644
|
||||
--- a/scipy/optimize/_direct/DIRect.c
|
||||
+++ b/scipy/optimize/_direct/DIRect.c
|
||||
@@ -780,6 +780,7 @@
|
||||
ret = NULL;
|
||||
goto cleanup;
|
||||
}
|
||||
+ Py_DECREF(callback_py); /* DECREF the callback's return value */
|
||||
}
|
||||
/* L10: */
|
||||
}
|
||||
--
|
||||
2.53.0
|
||||
|
||||
|
||||
From e38338f279ba7235d479e3ed202b118c508d82d1 Mon Sep 17 00:00:00 2001
|
||||
From: Charalampos Stratakis <cstratak@redhat.com>
|
||||
Date: Wed, 28 Jan 2026 01:00:20 +0100
|
||||
Subject: [PATCH 14/15] BUG: Initialize icoor array in NI_GeometricTransform in
|
||||
ndimage
|
||||
|
||||
The icoor array could be used uninitialized if a user-provided
|
||||
LowLevelCallable fails to write its output, or if the function is
|
||||
called without map, matrix, or coordinates set. Initialize to zero
|
||||
to ensure defined behavior in these edge cases.
|
||||
|
||||
Additionally, add explicit error when of map, matrix, or
|
||||
coordinates is not provided, rather than silently proceeding
|
||||
with zero-initialized coordinates.
|
||||
|
||||
Uncovered by Coverity static analysis
|
||||
---
|
||||
scipy/ndimage/src/ni_interpolation.c | 7 ++++++-
|
||||
1 file changed, 6 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/scipy/ndimage/src/ni_interpolation.c b/scipy/ndimage/src/ni_interpolation.c
|
||||
index 5a11419..84e9a72 100644
|
||||
--- a/scipy/ndimage/src/ni_interpolation.c
|
||||
+++ b/scipy/ndimage/src/ni_interpolation.c
|
||||
@@ -265,7 +265,7 @@ NI_GeometricTransform(PyArrayObject *input, int (*map)(npy_intp*, double*,
|
||||
npy_intp ftmp[NPY_MAXDIMS], *fcoordinates = NULL, *foffsets = NULL;
|
||||
npy_intp cstride = 0, kk, hh, ll, jj;
|
||||
npy_intp size;
|
||||
- double **splvals = NULL, icoor[NPY_MAXDIMS], tmp;
|
||||
+ double **splvals = NULL, icoor[NPY_MAXDIMS] = {0}, tmp;
|
||||
npy_intp idimensions[NPY_MAXDIMS], istrides[NPY_MAXDIMS];
|
||||
NI_Iterator io, ic;
|
||||
npy_double *matrix = matrix_ar ? (npy_double*)PyArray_DATA(matrix_ar) : NULL;
|
||||
@@ -467,6 +467,11 @@ NI_GeometricTransform(PyArrayObject *input, int (*map)(npy_intp*, double*,
|
||||
"coordinate array data type not supported");
|
||||
goto exit;
|
||||
}
|
||||
+ } else {
|
||||
+ NPY_END_THREADS;
|
||||
+ PyErr_SetString(PyExc_RuntimeError,
|
||||
+ "One of `map`, `matrix` or `coordinates` must be provided");
|
||||
+ goto exit;
|
||||
}
|
||||
|
||||
/* iterate over axes: */
|
||||
--
|
||||
2.53.0
|
||||
|
||||
|
||||
From 859399cecffdbbbc6a0f86c8aec1339200afd6fb Mon Sep 17 00:00:00 2001
|
||||
From: Charalampos Stratakis <cstratak@redhat.com>
|
||||
Date: Wed, 28 Jan 2026 02:17:37 +0100
|
||||
Subject: [PATCH 15/15] BUG: optimize: validate itmax in trlib_eigen_inverse
|
||||
|
||||
Add early return when itmax <= 0 to prevent use of uninitialized
|
||||
residuals array. The inverse iteration loop sets residuals[jj] only
|
||||
after the first iteration completes. With itmax <= 0, the loop breaks
|
||||
immediately, leaving residuals uninitialized.
|
||||
|
||||
Uncovered by Coverity static analysis
|
||||
---
|
||||
scipy/optimize/_trlib/trlib_eigen_inverse.c | 3 ++-
|
||||
1 file changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/scipy/optimize/_trlib/trlib_eigen_inverse.c b/scipy/optimize/_trlib/trlib_eigen_inverse.c
|
||||
index 79c4aaf..4156483 100644
|
||||
--- a/scipy/optimize/_trlib/trlib_eigen_inverse.c
|
||||
+++ b/scipy/optimize/_trlib/trlib_eigen_inverse.c
|
||||
@@ -78,7 +78,8 @@ trlib_int_t trlib_eigen_inverse(
|
||||
*lam_pert = -minuslam;
|
||||
|
||||
if ( *iter_inv == TRLIB_EIR_FAIL_FACTOR ) { TRLIB_PRINTLN_2("Failure on factorizing in inverse correction!") TRLIB_RETURN(TRLIB_EIR_FAIL_FACTOR) }
|
||||
-
|
||||
+ if ( itmax <= 0 ) { TRLIB_PRINTLN_2("Failure on solving inverse correction! (itmax <= 0)") TRLIB_RETURN(TRLIB_EIR_FAIL_LINSOLVE) }
|
||||
+
|
||||
// try with TRLIB_EIR_N_STARTVEC different start vectors and hope that it converges for one
|
||||
seeds[0] = time(NULL);
|
||||
for(jj = 1; jj < TRLIB_EIR_N_STARTVEC; ++jj ) { seeds[jj] = rand(); }
|
||||
--
|
||||
2.53.0
|
||||
|
||||
Loading…
Reference in New Issue
Block a user