Validate runtime blob shapes in GRU, RNN, LSTM, DeformableConv2D, Gemm and MultiHeadAttention, and check int8 scale records by professor-moody · Pull Request #7152 · Tencent/ncnn · GitHub
Skip to content

Validate runtime blob shapes in GRU, RNN, LSTM, DeformableConv2D, Gemm and MultiHeadAttention, and check int8 scale records - #7152

Open
professor-moody wants to merge 3 commits into
Tencent:masterfrom
professor-moody:fix/recurrent-dcn-gemm-mha-weight-bounds
Open

professor-moody wants to merge 3 commits into
Tencent:masterfrom
professor-moody:fix/recurrent-dcn-gemm-mha-weight-bounds

Conversation

@professor-moody

@professor-moody professor-moody commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

Summary

These six layers index their weights and recurrent state with sizes derived from the loaded parameters, but use the extents of their runtime blobs as given. When a model feeds a blob whose shape disagrees with the weights (for example from a MemoryData or Reshape producer), forward reads outside the blob or weight allocation, and for the recurrent state it also writes outside it. Separately, several int8 scale records are loaded without an .empty() check and then dereferenced.

  1. GRU, RNN, LSTM: forward rejects an input whose width differs from the weight row width (weight_data_size / num_directions divided by num_output for RNN, by num_output * 3 for GRU and by hidden_size * 4 for LSTM), and explicit hidden / cell state blobs that are narrower than num_output / hidden_size or have fewer rows than directions. hidden_state[q] is written for every q < num_output, so a narrower state blob is overwritten past its end.
  2. DeformableConv2D: the input channel count must equal the weights' input channels, the offset blob needs at least 2 * kernel_w * kernel_h channels of out_h x out_w, and the mask blob at least kernel_w * kernel_h channels of out_h x out_w.
  3. Gemm: K of A must not exceed K of B, and must equal constantK when A or B is constant. When a constant C is broadcast over M or N, the runtime M / N must equal constantM / constantN. A runtime B with more K than A is still accepted, because only the first K elements are read and test_sdpa uses that shape.
  4. MultiHeadAttention: the q width must equal qdim; when append_kv is enabled, the k and v widths must equal kdim and vdim and k and v must have the same sequence length; and when past kv_cache blobs are supplied, they must be 3D with width embed_dim / num_heads, channel count num_heads (c * elempack == num_heads) and matching sequence lengths.
  5. int8 scale records: load_model of GRU, RNN, LSTM, Gemm and MultiHeadAttention returns -100 when a scale record is missing, instead of continuing with an empty Mat (or calling [0] on it for the Gemm B scale and the MultiHeadAttention output scale).

The shape checks live in a protected check_input_shapes() helper on each base layer. It is called at the top of forward() in the base implementation and in the x86, arm, loongarch, mips and riscv overrides, under NCNN_VALIDATION, and returns -1. The Vulkan implementations are not changed.

This touches no file changed by #7148 and applies on top of it.

Tests

  • New tests/test_{gru,rnn,lstm,deformableconv2d,gemm,multiheadattention}_invalid.cpp. Each runs the naive and the create_layer_cpu layer on a valid control and on mismatched shapes, and the int8 cases load a model with and without its scale records.
  • Without this change, each of the new tests fails: either forward returns 0 where -1 is expected, or AddressSanitizer reports a heap-buffer-overflow.
  • Linux x86_64, clang 21, Release and ASan+UBSan builds: ctest 195/195 (189 existing plus the 6 new tests) in both. No AddressSanitizer report in the ASan run.
  • macOS arm64, Apple clang 21, Release and ASan+UBSan builds (exercising the arm overrides): the 6 new tests pass, and so do the existing test_gru, test_rnn, test_lstm, test_deformableconv2d, test_gemm and test_multiheadattention. The one exception is test_rnn and test_lstm in the ASan build, where *_int8_with_hidden reports a value mismatch with bf16 storage; it fails the same way without this change.
  • The loongarch, mips and riscv overrides only gain the guard call. They were not compiled or run here.
  • All 49 params in benchmark/ load identically with and without this change. The 35 vision models, including vision_transformer (which uses Gemm and MultiHeadAttention), produce byte-identical outputs with zero weights and with patterned weights.

Note: This patch was prepared with AI assistance and verified by human review and local test execution.

…m and MultiHeadAttention, and check int8 scale records

- GRU, RNN, LSTM: validate input width against weight row width and
  validate explicit hidden/cell state blob extents before forward loops.
- DeformableConv2D: validate input channel count against weights and
  check offset/mask channel and spatial dimensions.
- Gemm: validate K and constant M/N/K compatibility before packing.
- MultiHeadAttention: validate q/k/v widths against qdim/kdim/vdim and
  require matching k/v sequence lengths.
- GRU, RNN, LSTM, Gemm, MultiHeadAttention: return -100 from load_model
  when an int8 scale blob is empty.
- Add tests/test_{gru,rnn,lstm,deformableconv2d,gemm,multiheadattention}_invalid.cpp.
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 20, 2026 •

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: de25c0b083

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/layer/multiheadattention.cpp Outdated
Comment on lines +1754 to +1757
if (q_blob.w != qdim || k_blob.w != kdim || v_blob.w != vdim)
return -1;

if (k_blob.h * k_blob.elempack != v_blob.h * v_blob.elempack)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Skip K/V checks when reusing a cross-attention cache

When CPU cross-attention runs with kv_cache enabled, distinct q/k inputs, and nonempty cache slots (for example, five unmasked bottoms with empty current k/v at 1/2 and cached tensors at 3/4), forward() sets append_kv false and never reads the current k/v blobs. These unconditional width and length checks now return -1 before that branch, breaking cache-reuse calls that previously needed only q and the cached tensors; gate current-k/v validation on whether the cache is empty or being appended.

Useful? React with 👍 / 👎.

… in int8 scale tests

- src/layer/multiheadattention.cpp: gate live k_blob and v_blob shape checks
  in check_input_shapes() on append_kv so cross-attention kv_cache reuse
  with populated cached_xk/cached_xv is accepted, and validate past_xk_blob
  and past_xv_blob dimensions and sequence-length agreement.
- tests/test_multiheadattention_invalid.cpp: add
  test_multiheadattention_kv_cache_cross() covering cross-attention kv_cache
  population, reuse with empty live k/v, and mismatched past cache rejection.
- tests/test_{gemm,gru,lstm,multiheadattention,rnn}_invalid.cpp: assert
  ret == expected_ret directly in test_*_int8_scales().

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 54f33e011e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/layer/multiheadattention.cpp Outdated

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Validate all KV-cache axes before accepting the cache

With kv_cache enabled and caller-provided nonempty caches, these are 3-D Mats whose sequence axis is h and whose packed axis is c. This comparison instead uses h * elempack and never checks dims, w == embed_dim / num_heads, or c * elempack == num_heads; a cache with too few columns or heads therefore passes and is later indexed via channel(q).row(j)[l] (or copied into a num_heads allocation), causing out-of-bounds access, while the optimized forwards now reject otherwise valid equal-h K/V caches whose channel packings differ. Compare h directly and validate the logical head count and head width for both caches.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Updated MultiHeadAttention::check_input_shapes to validate that non-empty past_xk_blob and past_xv_blob have dims == 3, w == embed_dim / num_heads, past_xk_blob.h == past_xv_blob.h, and c * elempack == num_heads, and added test_multiheadattention_kv_cache_shape coverage in tests/test_multiheadattention_invalid.cpp.

…apes

- src/layer/multiheadattention.cpp: require non-empty past_xk_blob and
  past_xv_blob to have dims == 3, w == embed_dim / num_heads,
  past_xk_blob.h == past_xv_blob.h, and c * elempack == num_heads.
- tests/test_multiheadattention_invalid.cpp: add
  test_multiheadattention_kv_cache_shape() covering valid 3D past_k/past_v
  and mismatched empty, h, w, c, and dims.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant