Skip to content

Fix out-of-bounds read when a Loop/Scan body input is also an initializer - #32609

Merged
Akshay Sonawane (apsonawane) merged 2 commits into
microsoft:mainfrom
wangw-1991:fix_SessionState_OOB
Sep 19, 2026
Merged

Akshay Sonawane (apsonawane) merged 2 commits into
microsoft:mainfrom
wangw-1991:fix_SessionState_OOB

Conversation

@wangw-1991

@wangw-1991 Wei Wang (wangw-1991) commented Sep 15, 2026 •

Copy link
Copy Markdown
Contributor

Problem

OuterScopeNodeArgLocationAccumulator (session_state.cc) maps a Loop/Scan node's explicit inputs onto the subgraph's inputs using GraphViewer::GetInputs(), which excludes initializer-backed inputs. When a body declares an input that is also a
body initializer, GetInputs() is shorter than the parent node's input list, so indexing subgraph_inputs[arg_idx] reads past the end of the vector and dereferences an invalid NodeArg pointer during session initialization. This causes a crash / heap out-of-bounds read (observable under ASan) when loading a malformed model containing such a Loop/Scan.

Fix

In the Loop/Scan≥9 branch of OuterScopeNodeArgLocationAccumulator:

  • If subgraph.GetInputs().size() does not equal the parent node's input count, return an INVALID_GRAPH status naming the parent node and both counts, instead of indexing. When the size difference is explained by initializer-backed inputs (GetInputsIncludingInitializers() is larger), the message adds a hint pointing at that as the cause.
  • Add Loop.BodyInputAlsoInitializerIsRejected test: builds a Loop whose body input state_in is also a body initializer, and asserts InferenceSession::Initialize() fails with INVALID_GRAPH and the expected message — i.e. rejected cleanly rather than crashing. The test asserts on the status code and message text on purpose, so that it keeps covering this path rather than silently falling through to the ORT_ENFORCE downstream.

Copilot AI balanced review requested due to automatic review settings September 15, 2026 10:34
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
There may be pipelines that require an authorized user to comment /azp run to run.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The regression case still reaches an ORT_ENFORCE that aborts exception-disabled builds instead of returning a clean error.

Get a fresh assessment by requesting another Copilot review.

Pull request overview

Prevents out-of-bounds access while mapping Loop/Scan parent inputs to subgraph inputs.

Changes:

  • Selects a cardinality-matching subgraph input list and validates bounds.
  • Adds a Loop regression test for initializer-backed body inputs.
File summaries
File Description
onnxruntime/core/framework/session_state.cc Hardens subgraph input mapping.
onnxruntime/test/providers/cpu/controlflow/loop_test.cc Adds the regression test.
Review details
  • Files reviewed: 2/2 changed files
  • Comments generated: 1
  • Review effort level: Balanced (auto)

Note

Copilot is running an experiment and ran this review at Balanced.


💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread onnxruntime/core/framework/session_state.cc Outdated
@wangw-1991

Copy link
Copy Markdown
Contributor Author

Tianlei Wu (@tianleiwu) Can you help review this PR or help find suitable reviewers? Thanks.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The memory-safety fix is correct and covered; only non-blocking comment cleanup remains.

Review details
  • Files reviewed: 2/2 changed files
  • Comments generated: 1
  • Review effort level: Balanced (auto)

Note

Copilot is running an experiment and ran this review at Balanced.

Comment thread onnxruntime/test/providers/cpu/controlflow/loop_test.cc Outdated
Comment thread onnxruntime/core/framework/session_state.cc Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The implemented rejection behavior materially differs from the matching-input-list strategy stated in the PR description.

Get a fresh assessment by requesting another Copilot review.

Review details
  • Files reviewed: 2/2 changed files
  • Comments generated: 1
  • Review effort level: Balanced

Comment thread onnxruntime/core/framework/session_state.cc
@apsonawane

Copy link
Copy Markdown
Contributor

Wei Wang (@wangw-1991) can you review the one copilot comment

@wangw-1991

Copy link
Copy Markdown
Contributor Author

Wei Wang (Wei Wang (@wangw-1991)) can you review the one copilot comment

Done. Please help merge this PR if no other issues, thanks.

@apsonawane
Akshay Sonawane (apsonawane) merged commit 09dfa6a into microsoft:main Sep 19, 2026
89 of 90 checks passed
Tianlei Wu (tianleiwu) added a commit that referenced this pull request Sep 29, 2026
This cherry-picks the following commits for the release:

* #32610
* #32633
* #32641
* #32611
* #32609
* #32607
* #32679
* #32681
* #32666

CI fixes:

* #32491 (installs `uuid-dev` for the Linux minimal-build CoreML job;
that check also fails on the `rel-1.28.3` base)
* Raise the Android minimal baseline binary-size threshold from
1,440,768 to 1,443,840 bytes (release branch only). The checks added by
these fixes grow the minimal build from 1,440,538 to 1,443,098 bytes
(+2,560).

All picks except #32607 applied cleanly with `git cherry-pick -x`, in
the order they merged into main (#32666 was added afterward).

#32607 required a manual backport because `bert_defs.cc` has diverged on
main since 1.28 branched:
- `GroupQueryAttention` / `SparseAttention`: backported as-is
(`total_sequence_length_index` of 6 / 7, plus the single-element check).
The GQA call site in 1.28 has no `sliding_window_cache`, so it only gets
the new argument.
- `CausalConvWithState`: the 1.28 schema predates `channels_last`,
`state_window`, and `dilation`. Only the `ndim` in [1, 3] check and the
`weight`/`input` rank == `ndim + 2` checks are backported. These match
what the 1.28 CPU kernel already enforces.
`ChannelsLastInputRankBelowThreeIsRejected` is dropped.
- `GatedDeltaNet`: this op does not exist on 1.28.3, so its hunk and
test are dropped.

Validation (Windows x64, CPU EP, RelWithDebInfo):
- All 14 regression tests added by these PRs pass.
- `onnxruntime_test_all`: 1848 tests (including #32666's
`PluginCopiesForwardStreams`), 0 failures.
- `onnxruntime_provider_test`: 5370 tests, 0 failures.

---------

Co-authored-by: Wei Wang <wei4.wang@intel.com>
Co-authored-by: shiyi <shiyi.zou@intel.com>
Co-authored-by: Bin Miao <bin.miao@intel.com>
Co-authored-by: Bryan B <bryan.bernhart@intel.com>
Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
Co-authored-by: tianleiwu <30328909+tianleiwu@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Xiaofei Han <xiaofeihan@microsoft.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants