From 522265bdd06a15cf3b07fb5a2fe2a14cdabb9a1a Mon Sep 17 00:00:00 2001 From: Bryan Bernhart Date: Thu, 17 Sep 2026 13:47:48 -0700 Subject: [PATCH] Fix OOB read in InferenceContextImpl::getInputData when a trailing optional input is omitted 'Pads' on ConvTransposeWithDynamicPads is schema-optional, so a node can validly supply only [X, W]. InferenceContextImpl::getInputData (graph.cc) indexed node_.InputDefs() by the ONNX input index without checking it against InputDefs().size(), so shape inference on such a node read past the end of the vector. Add the same bounds check already used by DataPropagationContextImpl::getInputData. --- onnxruntime/core/graph/graph.cc | 6 +++++ .../conv_transpose_with_dynamic_pads_test.cc | 22 +++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/onnxruntime/core/graph/graph.cc b/onnxruntime/core/graph/graph.cc index 257669c979bf1..90a680e19fe22 100644 --- a/onnxruntime/core/graph/graph.cc +++ b/onnxruntime/core/graph/graph.cc @@ -2748,6 +2748,12 @@ class InferenceContextImpl : public ONNX_NAMESPACE::InferenceContext { } const TensorProto* getInputData(size_t index) const override { + // A schema-optional input that's omitted (not even an empty placeholder) shrinks InputDefs(), + // so callers can pass an index the node doesn't actually have. + if (index >= getNumInputs()) { + return nullptr; + } + auto def = node_.InputDefs()[index]; if (!def) return nullptr; diff --git a/onnxruntime/test/contrib_ops/conv_transpose_with_dynamic_pads_test.cc b/onnxruntime/test/contrib_ops/conv_transpose_with_dynamic_pads_test.cc index 345a143d5b87c..b88985c8a2d42 100644 --- a/onnxruntime/test/contrib_ops/conv_transpose_with_dynamic_pads_test.cc +++ b/onnxruntime/test/contrib_ops/conv_transpose_with_dynamic_pads_test.cc @@ -2,7 +2,11 @@ // Licensed under the MIT License. #include "gtest/gtest.h" +#include "core/graph/model.h" #include "test/providers/provider_test_utils.h" +#include "test/test_environment.h" +#include "test/unittest_util/graph_transform_test_builder.h" +#include "test/util/include/asserts.h" #include "default_providers.h" namespace onnxruntime { @@ -147,5 +151,23 @@ TEST(ContribOpTest, ConvTransposeWithDynamicPads_NegativePads_Dml) { } #endif // USE_DML +// 'Pads' is schema-optional; a node may validly supply only X and W. Shape inference must not +// index past the end of InputDefs() when reading the omitted Pads input. +TEST(ContribOpTest, ConvTransposeWithDynamicPads_PadsOmitted_ShapeInferenceOnly) { + std::unordered_map domain_to_version{{kOnnxDomain, 17}, {kMSDomain, 1}}; + Model model("conv_transpose_with_dynamic_pads_pads_omitted", /*is_onnx_domain_only=*/false, ModelMetaData(), + PathString(), IOnnxRuntimeOpSchemaRegistryList(), domain_to_version, {}, + DefaultLoggingManager().DefaultLogger()); + + ModelTestBuilder builder(model.MainGraph()); + NodeArg* x = builder.MakeInput(std::vector{1, 1, 3, 3}); + NodeArg* w = builder.MakeInput(std::vector{1, 1, 3, 3}); + NodeArg* y = builder.MakeOutput(); + builder.AddNode("ConvTransposeWithDynamicPads", {x, w}, {y}, kMSDomain); + builder.SetGraphOutputs(); + + ASSERT_STATUS_OK(model.MainGraph().Resolve()); +} + } // namespace test } // namespace onnxruntime