Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions onnxruntime/core/providers/cpu/ml/linearregressor.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
#include "core/common/narrow.h"
#include "core/providers/cpu/math/gemm.h"

#include <limits>

Check warning on line 8 in onnxruntime/core/providers/cpu/ml/linearregressor.cc

View workflow job for this annotation

GitHub Actions / Optional Lint C++

[cpplint] reported by reviewdog 🐶 Found C++ system header after other header. Should be: linearregressor.h, c system, c++ system, other. [build/include_order] [4] Raw Output: onnxruntime/core/providers/cpu/ml/linearregressor.cc:8: Found C++ system header after other header. Should be: linearregressor.h, c system, c++ system, other. [build/include_order] [4]

namespace onnxruntime {
namespace ml {

Expand Down Expand Up @@ -86,6 +88,30 @@
ptrdiff_t num_batches = input_shape.NumDimensions() <= 1 ? 1 : narrow<ptrdiff_t>(input_shape[0]);
ptrdiff_t num_features = input_shape.NumDimensions() <= 1 ? narrow<ptrdiff_t>(input_shape.Size())
: narrow<ptrdiff_t>(input_shape[1]);

// Coefficients are treated as a [num_targets, num_features] matrix.
// Validate size to prevent out-of-bounds reads in the GEMM backend.
if (num_targets_ < 0) {
return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT,
"LinearRegressor: targets attribute must be non-negative, got ", num_targets_);
}

const auto targets = static_cast<size_t>(num_targets_);
const auto features = static_cast<size_t>(num_features);
// Non-throwing overflow check: targets * features would overflow if features > max / targets.
if (targets != 0 && features > std::numeric_limits<size_t>::max() / targets) {
return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT,
"LinearRegressor: coefficients size overflow for targets (", num_targets_,
") * input features (", num_features, ")");
}

if (coefficients_.size() != targets * features) {
return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT,
"LinearRegressor: coefficients attribute size (", coefficients_.size(),
") does not match targets (", num_targets_,
") * input features (", num_features, ")");
}
Comment thread
bmehta001 marked this conversation as resolved.

Tensor& Y = *ctx->Output(0, {num_batches, num_targets_});
concurrency::ThreadPool* tp = ctx->GetOperatorThreadPool();

Expand Down
13 changes: 13 additions & 0 deletions onnxruntime/test/providers/cpu/ml/linearregressor_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -85,5 +85,18 @@ INSTANTIATE_TEST_SUITE_P(
LinearRegressorParam("SOFTMAX_ZERO", {3.442477e-14f, 1.f, 1.670142e-05f, 1.f, 1.0f, 0.f}, 2)

));

// Regression test: coefficients size must match targets * num_features.
// A mismatch previously caused an out-of-bounds read in MLAS SGEMM packing.
TEST(LinearRegressorTest, CoefficientsSizeMismatch) {
OpTester test("LinearRegressor", 1, onnxruntime::kMLDomain);
// 1 coefficient but input has 2 features and targets=1 → expects 2 coefficients
test.AddAttribute("coefficients", std::vector<float>{1.0f});
test.AddAttribute("targets", int64_t{1});
test.AddInput<float>("X", {1, 2}, {1.f, 2.f});
test.AddOutput<float>("Y", {1, 1}, {0.f});
test.Run(OpTester::ExpectResult::kExpectFailure, "coefficients attribute size");
}

} // namespace test
} // namespace onnxruntime
Loading