From 6be15ad68bc9fed5ea75916bc0da4e252f5d0e91 Mon Sep 17 00:00:00 2001 From: "tairen.piao" Date: Sat, 20 Jun 2026 16:06:36 +0900 Subject: [PATCH 1/2] Fix NchwcTransformer null deref on node with unresolved schema (#28392) --- onnxruntime/core/graph/graph_utils.cc | 6 +++++- .../test/optimizer/nchwc_optimizer_test.cc | 10 ++++++++++ .../transform/transpose_cast_matmul_fp16.onnx | Bin 0 -> 762 bytes 3 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 onnxruntime/test/testdata/transform/transpose_cast_matmul_fp16.onnx diff --git a/onnxruntime/core/graph/graph_utils.cc b/onnxruntime/core/graph/graph_utils.cc index b82fc42bab3c2..7470306cab5cf 100644 --- a/onnxruntime/core/graph/graph_utils.cc +++ b/onnxruntime/core/graph/graph_utils.cc @@ -396,10 +396,14 @@ bool IsSupportedOptypeVersionAndDomain(const Node& node, bool IsSupportedOptypeVersionAndDomain(const Node& node, std::string_view op_type, gsl::span versions, std::string_view domain) { +#if !defined(ORT_MINIMAL_BUILD) + // node.Op() can be null for a node whose schema is not yet resolved. + const auto* op_schema = node.Op(); +#endif return (node.OpType() == op_type && // we don't have op schemas in the minimal build so there's no way to check the deprecated flag #if !defined(ORT_MINIMAL_BUILD) - !node.Op()->Deprecated() && + op_schema != nullptr && !op_schema->Deprecated() && #endif MatchesOpSinceVersion(node, versions) && MatchesOpSetDomain(node, domain)); } diff --git a/onnxruntime/test/optimizer/nchwc_optimizer_test.cc b/onnxruntime/test/optimizer/nchwc_optimizer_test.cc index a07f173950051..d9db43b3688d1 100644 --- a/onnxruntime/test/optimizer/nchwc_optimizer_test.cc +++ b/onnxruntime/test/optimizer/nchwc_optimizer_test.cc @@ -236,6 +236,16 @@ void NchwcOptimizerTester(const std::function& bu #ifndef DISABLE_CONTRIB_OPS +// Regression test for #28392: NchwcTransformer must not crash when a node's schema is unresolved (node.Op() == nullptr). +TEST(NchwcOptimizerTests, MatMulCastDoesNotCrashOnUnresolvedSchema) { + SessionOptions session_options; + session_options.graph_optimization_level = TransformerLevel::Level3; + session_options.session_logid = "NchwcOptimizerTests"; + InferenceSessionWrapper session{session_options, GetEnvironment()}; + ASSERT_STATUS_OK(session.Load(ORT_TSTR("testdata/transform/transpose_cast_matmul_fp16.onnx"))); + ASSERT_STATUS_OK(session.Initialize()); +} + TEST(NchwcOptimizerTests, ConvNchw) { auto test_case = [&](const std::string& activation_op_type) { auto build_test_case = [&](NchwcTestHelper& helper) { diff --git a/onnxruntime/test/testdata/transform/transpose_cast_matmul_fp16.onnx b/onnxruntime/test/testdata/transform/transpose_cast_matmul_fp16.onnx new file mode 100644 index 0000000000000000000000000000000000000000..a87f4f764d6f738688a38ff274cc2459076c5c2b GIT binary patch literal 762 zcmX|prw zM^d6zo@uf>d_KQ8W0geeum*81PD(<^l0diuHCLon@|7r|wcGsI@V5wU%BN-uV_} zpMJ9eOBd}ZaWdihD713jP#O^qx$*#yA=n@U%H!c#-ARa!55eAzUYM43Hv>B~% z;;UXrijwH!{L`s)Z8&myBdout3FS?lc(phT^ba(ky?q5<#-(Fl@=G`td7h=5dIak( zykVF0X*m3#mUhXVaC0(}Zu+naSNHcKZ@z`&*CjBq?>M|ji)N$FM!ZpLgxU9<=x$0u zzh5DcCsldU#_rRDGa6JrnH0*D?ZYd7=vEDIjQue+RdPtamlSCSP9q7EQZ1xI9RZig=@ihZPLiEuvh O@5=dzDuX8ymF5pTR4XL_ literal 0 HcmV?d00001 From 4f611c04f0cea79ab8ef8bda25d0f9b9740b8ed9 Mon Sep 17 00:00:00 2001 From: "tairen.piao" Date: Fri, 26 Jun 2026 20:46:48 +0900 Subject: [PATCH 2/2] Guard against null Op() in avx2 s8->u8 weight conversion --- .../core/optimizer/qdq_transformer/avx2_weight_s8_to_u8.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/onnxruntime/core/optimizer/qdq_transformer/avx2_weight_s8_to_u8.cc b/onnxruntime/core/optimizer/qdq_transformer/avx2_weight_s8_to_u8.cc index d0c88886e5a06..a7c3a77bc8fbd 100644 --- a/onnxruntime/core/optimizer/qdq_transformer/avx2_weight_s8_to_u8.cc +++ b/onnxruntime/core/optimizer/qdq_transformer/avx2_weight_s8_to_u8.cc @@ -180,9 +180,13 @@ Status Avx2WeightS8ToU8Transformer::ApplyImpl(Graph& graph, bool& modified, int continue; // unknown operator, next } +#if !defined(ORT_MINIMAL_BUILD) + // op_node.Op() can be null for a node whose schema is not yet resolved. + const auto* op_schema = op_node.Op(); +#endif if ( #if !defined(ORT_MINIMAL_BUILD) - !op_node.Op()->Deprecated() && + op_schema != nullptr && !op_schema->Deprecated() && #endif MatchesOpSinceVersion(op_node, it->second.versions) && graph_utils::MatchesOpSetDomain(op_node, it->second.domain)) {