Fix INT64 initializer data propagation - #28778
Conversation
20a5b9c to
e7a713a
Compare
e7a713a to
dc97eae
Compare
There was a problem hiding this comment.
Pull request overview
Fixes a buffer overrun in Graph::SaveShapeValuesFromDataPropagation when materializing in-memory-external INT64 initializers during shape/data propagation, and adds a regression model + session-load test to cover the scenario.
Changes:
- Fix
INT64initializer materialization by validating element count, resizing the destinationTensorShapeVector, and then copying. - Add a new regression model to exercise the in-memory-external
INT64initializer path during graph re-resolution. - Extend
ShapeInferenceV2Test.PartialDataPropagationTestto load the new model under BASIC optimizations.
Reviewed changes
Copilot reviewed 3 out of 4 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| onnxruntime/core/graph/graph.cc | Fixes INT64 in-memory-external initializer copying by validating size and resizing before memcpy. |
| onnxruntime/test/testdata/test_shape_data_propagation_unsqueeze_inmemory_int64.py | Adds a generator script for the regression ONNX model that triggers the affected initializer path. |
| onnxruntime/test/framework/shape_inference_test.cc | Adds a regression test case that loads the new model to ensure the session can be created without error. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
dc97eae to
1735e4e
Compare
…t/onnxruntime#28778) Co-authored-by: xadupre <22452781+xadupre@users.noreply.github.com>
…ft/onnxruntime#28778 not yet released) Co-authored-by: xadupre <22452781+xadupre@users.noreply.github.com>
…1699) * Initial plan * Add Shape→Identity→Unsqueeze shape-inference backend test case Co-authored-by: xadupre <22452781+xadupre@users.noreply.github.com> * Exclude shape_identity_unsqueeze case from ORT backend tests (microsoft/onnxruntime#28778 not yet released) Co-authored-by: xadupre <22452781+xadupre@users.noreply.github.com> * Skip shape_identity_unsqueeze ORT run in runtime_coverage (aborts old ORT) Co-authored-by: xadupre <22452781+xadupre@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: xadupre <22452781+xadupre@users.noreply.github.com>
1735e4e to
4b5adac
Compare
Review — PR #28778 (Fix INT64 initializer data propagation)Verdict: approve with one small ask. Real bug, correct fix, scoped to the actual defect. The INT64 branch was missing both the element-count enforcement and the destination What it fixesIn
The INT64 branch now mirrors INT32: size-check via the new The trigger model is well-chosen: What's right
Comments1. The ORT_RETURN_IF_NOT(tensor_element_count == element_cnt,
"The element count from Tensor for initializer '", input_name,
"' should match utils::GetTensorShapeFromTensorProto(). Tensor: ",
tensor_element_count, ", TensorProto: ", element_cnt);If you'd rather keep this PR surgical, file a follow-up — but please don't propagate the 2. 3. Branch name 4. The test loads the model and checks output count, but doesn't run inference. That's enough to exercise the buggy path (the bug fires during 5. The lambda captures 6. Consider extracting What's not covered (and probably fine)
Bottom lineShip it after the |
AI suggests using ORT_RETURN_IF_NOT() instead of ORT_ENFORCE(), but that is changing away from the previous behavior I think. So it might be to keep as is. |
Resize the TensorShapeVector destination before copying in-memory INT64 initializer data in Graph::SaveShapeValuesFromDataPropagation, matching the other initializer materialization branches. Add a regression model that exercises the in-memory-external INT64 initializer path during graph re-resolution.
4b5adac to
c9be1e6
Compare
tianleiwu
left a comment
There was a problem hiding this comment.
Review Summary
Correct, well-scoped fix for a heap buffer overflow in Graph::SaveShapeValuesFromDataPropagation on the in-memory-external INT64 initializer path. Approving.
Root cause: The previous INT64 branch copied into input_values without sizing it first:
const int64_t* src = tensor.Data<int64_t>();
memcpy(input_values.data(), src, element_cnt * sizeof(int64_t));Since input_values (a TensorShapeVector) was never resize()d, the memcpy wrote past its small-buffer/empty storage whenever the axes initializer was materialized as in-memory external data — a real out-of-bounds write surfaced by ASan.
What's good:
- Overflow fixed:
input_values.resize(element_cnt)is now done before thememcpy, matching theINT32branch and both non-in-memory branches. The copy lengthelement_cnt * sizeof(int64_t)is bounded by the validated element count, so source and destination lengths agree. - Checked element count: Switching to
tensor.DataAsSpan<int64_t>()provides a checked size for validation, consistent with the INT32 path. - Clearer diagnostics: The shared
enforce_tensor_element_count_matcheslambda replaces the duplicated, garbledORT_ENFORCEmessage ("...samefrom...") and now reports the initializer name plus observed vs. expected counts. - Targeted regression: The new
Shape -> Identity -> Unsqueezemodel reproduces the exact path whereORT_ENABLE_BASICdrops theIdentity, re-resolution re-runs data propagation after large initializers become in-memory external OrtValues, and the INT64 axes initializer hits the fixed branch.axis_count = 16keeps the checked-in model small while still exceeding the small-buffer threshold.
Prior threads: All earlier review threads are already resolved on this head (Copilot's ORT_ENFORCE message and oversized axis_count, skottmckay's request for a comment explaining the broken path, and the CodeQL duplicate-import note).
No blocking concerns and no new findings.
Description
Fixes the in-memory
INT64initializer materialization path inGraph::SaveShapeValuesFromDataPropagation.The
INT64branch now validates the tensor element count and resizes the destinationTensorShapeVectorbefore copying, matching the behavior of the other initializer materialization branches.Testing
INT64initializer path during graph re-resolution.onnxruntime_test_allwith AddressSanitizer enabled on Windows Debug.origin/mainunder ASan.Focused test: