Skip to content

Commit 4b50b2f

Browse files
authored
Address some issues and fix VS 2026 build (microsoft#26905)
Fix VS2026 build. ### Description <!-- Describe your changes. --> Fix some correctness issues. Fix VS 2026 build. ### Motivation and Context <!-- - Why is this change required? What problem does it solve? - If it fixes an open issue, please link to the issue here. -->
1 parent de2bb39 commit 4b50b2f

7 files changed

Lines changed: 102 additions & 14 deletions

File tree

include/onnxruntime/core/graph/graph.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1726,7 +1726,8 @@ class Graph { // NOLINT(clang-analyzer-optin.performance.Padding): preserve exi
17261726
#if !defined(ORT_MINIMAL_BUILD)
17271727
// Build and verify node connection (edges).
17281728
// Verify NodeArg name/type/shape matching correctly.
1729-
common::Status BuildConnections(std::unordered_set<std::string>& outer_scope_node_args_consumed);
1729+
common::Status BuildConnections(std::unordered_set<std::string>& outer_scope_node_args_consumed,
1730+
bool& removed_node_with_subgraph);
17301731

17311732
common::Status VerifyNoDuplicateName();
17321733

onnxruntime/core/graph/graph.cc

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1344,7 +1344,12 @@ Graph::Graph(const Model& owning_model,
13441344
ORT_THROW("This is an invalid model. Tensor does not have type information.");
13451345
}
13461346

1347-
if (utils::HasDataType(tensor) && (tensor.data_type() < TensorProto_DataType_DataType_ARRAYSIZE)) {
1347+
// all initializers must have a valid data type
1348+
if (!utils::HasDataType(tensor) || !tensor.DataType_IsValid(tensor.data_type())) {
1349+
ORT_THROW("This is an invalid model. Tensor '", tensor.name(), "' does not have valid data type.");
1350+
}
1351+
1352+
if ((tensor.data_type() < TensorProto_DataType_DataType_ARRAYSIZE)) {
13481353
weight_data_type_freq_[tensor.data_type()]++;
13491354
}
13501355

@@ -1669,13 +1674,14 @@ void Graph::RemoveEdge(NodeIndex src_node_index, NodeIndex dst_node_index, int s
16691674

16701675
#if !defined(ORT_MINIMAL_BUILD)
16711676
GSL_SUPPRESS(es .84) // ignoring return value from unordered_map::insert causes noisy complaint
1672-
Status Graph::BuildConnections(std::unordered_set<std::string>& outer_scope_node_args_consumed) {
1677+
Status Graph::BuildConnections(std::unordered_set<std::string>& outer_scope_node_args_consumed,
1678+
bool& removed_node_with_subgraph) {
16731679
// recurse into subgraphs first so we can update any nodes in this graph that are used by those subgraphs
16741680
if (!resolve_context_.nodes_with_subgraphs.empty()) {
16751681
for (auto* node : resolve_context_.nodes_with_subgraphs) {
16761682
for (auto& subgraph : node->MutableSubgraphs()) {
16771683
std::unordered_set<std::string> node_args_consumed;
1678-
ORT_RETURN_IF_ERROR(subgraph->BuildConnections(node_args_consumed));
1684+
ORT_RETURN_IF_ERROR(subgraph->BuildConnections(node_args_consumed, removed_node_with_subgraph));
16791685

16801686
for (auto& node_arg_name : node_args_consumed) {
16811687
auto node_arg = GetNodeArg(node_arg_name);
@@ -1805,6 +1811,10 @@ Status Graph::BuildConnections(std::unordered_set<std::string>& outer_scope_node
18051811
} else if (node.OutputDefs().empty()) {
18061812
// This is a useless node.
18071813
// It has no input/output.
1814+
if (node.ContainsSubgraph()) {
1815+
removed_node_with_subgraph = true;
1816+
}
1817+
18081818
RemoveNode(node.Index());
18091819
}
18101820
}
@@ -3683,10 +3693,17 @@ Status Graph::Resolve(const ResolveOptions& options) {
36833693
std::unordered_set<std::string> outer_scope_node_args_consumed;
36843694

36853695
// recursively build connections between nodes in this graph and all subgraphs
3686-
ORT_RETURN_IF_ERROR(BuildConnections(outer_scope_node_args_consumed));
3696+
bool removed_node_with_subgraph = false;
3697+
ORT_RETURN_IF_ERROR(BuildConnections(outer_scope_node_args_consumed, removed_node_with_subgraph));
36873698
ORT_ENFORCE(outer_scope_node_args_consumed.empty(),
36883699
"Shouldn't be possible to have NodeArgs that haven't been handled already.");
36893700

3701+
// if we removed any nodes with subgraphs, we need to refresh the list of subgraphs.
3702+
if (removed_node_with_subgraph) {
3703+
all_subgraphs.clear();
3704+
FindAllSubgraphs(all_subgraphs);
3705+
}
3706+
36903707
// topological sort of this and any subgraphs is non-recursive
36913708
auto topo_sort_func = [](Graph& graph) { return graph.PerformTopologicalSortAndCheckIsAcyclic(); };
36923709
ORT_RETURN_IF_ERROR(ForThisAndAllSubgraphs(all_subgraphs, topo_sort_func));

onnxruntime/core/session/custom_ops.cc

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1300,12 +1300,8 @@ common::Status CreateCustomRegistry(gsl::span<OrtCustomOpDomain* const> op_domai
13001300
std::unordered_map<std::string, std::vector<const OrtCustomOp*>> domain_kernels;
13011301
for (const auto* op : domain->custom_ops_) {
13021302
// define kernel
1303-
auto it = domain_kernels.find(op->GetName(op));
1304-
if (it == domain_kernels.end()) {
1305-
domain_kernels[op->GetName(op)] = {op};
1306-
} else {
1307-
domain_kernels[op->GetName(op)].push_back(op);
1308-
}
1303+
const auto* name = op->GetName(op);
1304+
domain_kernels[name].push_back(op);
13091305
}
13101306

13111307
// Creation of the schemas, one per unique name.
@@ -1319,7 +1315,8 @@ common::Status CreateCustomRegistry(gsl::span<OrtCustomOpDomain* const> op_domai
13191315
for (const auto* op : ops) {
13201316
// define kernel
13211317
auto kernel_create_info = CreateKernelCreateInfo(domain->domain_, op);
1322-
kernel_def_map[op->GetName(op)].push_back(kernel_create_info.kernel_def.get());
1318+
const auto* op_name = op->GetName(op);
1319+
kernel_def_map[op_name].push_back(kernel_create_info.kernel_def.get());
13231320
ORT_RETURN_IF_ERROR(output->RegisterCustomKernel(kernel_create_info));
13241321
// If IsCompatible returns false, then all custom operators named
13251322
// 'op->GetName(op)' are not compatible among themselves.

onnxruntime/test/framework/inference_session_test.cc

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -255,8 +255,7 @@ void RunModel(InferenceSession& session_object,
255255
if (is_preallocate_output_vec) {
256256
fetches.resize(output_names.size());
257257
for (auto& elem : fetches) {
258-
CreateMLValue<float>(TestCPUExecutionProvider()->CreatePreferredAllocators()[0], dims_mul_x, values_mul_x,
259-
&elem);
258+
AllocateMLValue<float>(TestCPUExecutionProvider()->CreatePreferredAllocators()[0], dims_mul_x, &elem);
260259
}
261260
}
262261

@@ -3069,5 +3068,26 @@ TEST(InferenceSessionTests, InterThreadPoolWithDenormalAsZero) {
30693068
}
30703069
#endif
30713070

3071+
TEST(InferenceSessionTests, BadDataTypeInInitializerIsHandled) {
3072+
// model has an initializer with a bogus data type. Graph ctor should detect and throw.
3073+
auto model_uri = ORT_TSTR("testdata/icm-31000000518082.onnx");
3074+
3075+
SessionOptions so;
3076+
so.session_logid = "TempTest.LoadModel";
3077+
InferenceSession session{so, GetEnvironment()};
3078+
ASSERT_STATUS_NOT_OK_AND_HAS_SUBSTR(session.Load(model_uri), "does not have valid data type");
3079+
}
3080+
3081+
TEST(InferenceSessionTests, GraphResolveHandlesNodeWithSubgraphBeingRemoved) {
3082+
// model has a subgraph with output that is not consumed. the node with the subgraph should get removed in
3083+
// Graph::BuildConnections and Graph::Resolve should adjust its list of subgraphs to not access the removed subgraph.
3084+
auto model_uri = ORT_TSTR("testdata/icm-31000000518483.onnx");
3085+
3086+
SessionOptions so;
3087+
so.session_logid = "TempTest.LoadModel";
3088+
InferenceSession session{so, GetEnvironment()};
3089+
ASSERT_STATUS_OK(session.Load(model_uri));
3090+
}
3091+
30723092
} // namespace test
30733093
} // namespace onnxruntime
429 Bytes
Binary file not shown.
391 Bytes
Binary file not shown.
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
from onnx import TensorProto, helper, save_model
2+
3+
# Add node with a subgraph that has no inputs or outputs.
4+
# Graph::BuildConnections should remove and the list of subgraphs in Graph::Resolve should be updated.
5+
# Other details here don't matter. Copied from ort_github_issue_10305.py
6+
if_body = helper.make_graph(
7+
[
8+
# need to use main_graph_initializer in a way that can't be constant folded
9+
helper.make_node("Constant", inputs=[], outputs=["zero"], name="Constant", value_int=0),
10+
],
11+
"if_branch_body",
12+
[
13+
# no explicit inputs
14+
],
15+
[
16+
helper.make_tensor_value_info("zero", TensorProto.BOOL, [1]),
17+
],
18+
)
19+
20+
# Create the main graph
21+
graph_proto = helper.make_graph(
22+
[
23+
# add a Transpose that can be moved past the Slice
24+
helper.make_node(
25+
"Transpose",
26+
inputs=["input:0"],
27+
outputs=["transpose:0"],
28+
name="transpose0",
29+
perm=[1, 0, 2],
30+
),
31+
helper.make_node(
32+
"If",
33+
[],
34+
[],
35+
"If1",
36+
then_branch=if_body,
37+
else_branch=if_body,
38+
),
39+
],
40+
"Main_graph",
41+
[
42+
helper.make_tensor_value_info("input:0", TensorProto.FLOAT, [2, 2, 2]),
43+
helper.make_tensor_value_info("state_var_in", TensorProto.FLOAT, [1]),
44+
],
45+
[
46+
helper.make_tensor_value_info("transpose:0", TensorProto.FLOAT, [2, 2]),
47+
],
48+
)
49+
50+
model = helper.make_model(graph_proto)
51+
# model to repro issue is invalid. can't run checker.
52+
# onnx.checker.check_model(model, True)
53+
save_model(model, "icm-31000000518483.onnx")

0 commit comments

Comments
 (0)