Fix out-of-bounds traversal in reduce_util for non-contiguous tensors - #21517
Open
SuryanshSS1011 wants to merge 1 commit into
Open
Fix out-of-bounds traversal in reduce_util for non-contiguous tensors#21517SuryanshSS1011 wants to merge 1 commit into
SuryanshSS1011 wants to merge 1 commit into
Conversation
SuryanshSS1011
requested review from
kirklandsign,
larryliu0820 and
manuelcandales
as code owners
July 31, 2026 13:43
🔗 Helpful Links🧪 See artifacts and rendered test results at hud.pytorch.org/pr/pytorch/executorch/21517
Note: Links to docs will display an error until the docs builds have been completed. ❌ 2 Cancelled Jobs, 1 Unrelated Failure, 1 Unclassified FailureAs of commit 36674e6 with merge base 6683757 ( UNCLASSIFIED FAILURE - DrCI could not classify the following job because the workflow did not run on the merge base. The failure may be pre-existing on trunk or introduced by this PR:
CANCELLED JOBS - The following jobs were cancelled. Please retry:
FLAKY - The following job failed but was likely due to flakiness present on trunk:
This comment was automatically generated by Dr. CI and updates every 15 minutes. |
Contributor
Author
|
@pytorchbot label "release notes: ops & kernels" |
Contributor
|
Thanks for the PR, @SuryanshSS1011. Running CI currently. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes #16429.
dequantize_per_channelon a channels-last input writes past the end of its output. The reported symptom is wrong values, but the underlying problem is a memory error and it is not in the quantized kernel.apply_on_flat_ix_with_dim_mask_and_baseinkernels/portable/cpu/util/reduce_util.hwalks the elements that map to one output index. When the innermost dim is exhausted it rewindscurr_indexand carries into the next dim, using:curr_index -= strides[curr_dim - 1];The comment above that line states the assumption: it treats
strides[curr_dim - 1]as equal toin.size(curr_dim) * strides[curr_dim]. That identity only holds for a contiguous tensor. For a(2, 2, 3, 3)channels-last tensor, strides are[18, 1, 6, 2], and the two disagree atcurr_dim = 1(2 vs 18) andcurr_dim = 2(18 vs 1). The rewind is then wrong and the walk leaves the buffer.For
dequantize_per_channelon that tensor the walk covers indices 0 to 17, skips 18 to 34 entirely, and writes 17 times past the end of a 36 element output. Running it under the existing kernel tests produces wrong values followed bydouble free or corruption (!prev).This changes the line to subtract the value the comment describes. For a contiguous tensor the two expressions evaluate to the same number, so that path is unaffected, and it is in the carry-over rather than the inner loop, so it is not on the per-element path.
Most reduction ops do not reach this.
op_amax,op_amin,op_mean,op_sumandop_varall guard withtensor_is_default_dim_order(in)and reject non-contiguous input before the traversal runs. The ops that accept it areop_any,op_var_meananddequantize_per_channel, and I have confirmed the fault in two of them:dequantize_per_channelwrites out of bounds, andany.dims_outreads out of bounds and returns a wrong answer.I took this over adding a
tensor_is_default_dim_orderguard todequantize_per_channelto match the other five ops. A guard would stop the corruption but leaves the traversal wrong forop_anyandop_var_mean, and #16429 asks for non-contiguous dim order to be supported in portable ops rather than rejected. Happy to switch if you would rather have the guard.Relaxing the five existing guards is not part of this change.
Test plan
OpDequantizeOutTest.DequantizePerChannelChannelsLastdequantizes a(2, 2, 3, 3)channels-last int8 tensor per channel onaxis=1. Each expected value is derived from the element's channel alone, so it passes only if thekernel honors the tensor's dim order.
OpAnyOutTest.ChannelsLastMultiDimReductionreduces a channels-last tensor over dims{0, 2, 3}withkeepdim=true. The single true value sits at channels-last physical index 19, inside the range the old traversal skipped, so before this change channel 1 was reported false while channel 0 picked up out-of-bounds memory and was reported true.Both fail before this change and pass after it.
This also adds
op_dequantize_test.cppto_quantized_kernels_test_sourcesinkernels/test/CMakeLists.txt. It is already inkernels/quantized/test/targets.bzl, but the CMake target lists every other op in that directory and omits this one, so those tests do not run in a CMake build and the new one would not either.Full runs after the change:
quantized_kernels_test73 passed,portable_kernels_test1624 ran with 1520 passed and 0 failures.cc @larryliu0820 @manuelcandales @JakeStevens