Skip to content

Fix int overflow in tensor byte-size calculation#3551

Open
Forbiddem wants to merge 1 commit into
tensorflow:mainfrom
Forbiddem:fix/memory-helpers-int-overflow
Open

Fix int overflow in tensor byte-size calculation#3551
Forbiddem wants to merge 1 commit into
tensorflow:mainfrom
Forbiddem:fix/memory-helpers-int-overflow

Conversation

@Forbiddem
Copy link
Copy Markdown

@Forbiddem Forbiddem commented May 8, 2026

BUG=#3552

Summary

BytesRequiredForTensor, TfLiteEvalTensorByteLength, and
AllocateOutputDimensionsFromInput in
tensorflow/lite/micro/memory_helpers.cc all multiply tensor shape dimensions
into a signed 32-bit int element_count running product before assigning the
result to a size_t byte count. Shape dimensions and the element type size
come from the (untrusted) flatbuffer model, so a model with a shape such as
[65536, 65536] over a 4-byte element type produces a product of 2^32, which
wraps to 0 in the original code and yields *bytes = 0. Subsequent buffer
arithmetic in the allocator then operates on a tensor whose advertised size
is 0 while its dimensions imply ~17 GiB of storage, opening a memory
corruption surface when a model is loaded from an untrusted source.

This PR:

  • Performs the running product in size_t, matching the result type, and
    rejects negative shape dimensions with kTfLiteError.
  • Guards every multiplication (shape * shape and elements * type_size)
    against overflow of size_t and returns kTfLiteError when the next
    multiplication would wrap.
  • Propagates the previously discarded status of TfLiteTypeSizeOf in
    AllocateOutputDimensionsFromInput.

Test plan

  • make -f tensorflow/lite/micro/tools/make/Makefile memory_helpers_test
    builds clean.
  • gen/linux_x86_64_default_gcc/bin/memory_helpers_test — all 10 cases
    pass, including the 3 new regression tests:
    • TfLiteEvalTensorByteLengthDoesNotTruncateAcrossInt32Boundary — shape
      [65536, 65536] float32 now reports 17,179,869,184 bytes on 64-bit
      size_t platforms (previously: 0), and kTfLiteError on 32-bit
      size_t platforms.
    • TfLiteEvalTensorByteLengthRejectsSizeTOverflow — a shape that
      overflows even a 64-bit size_t is rejected with kTfLiteError.
    • TfLiteEvalTensorByteLengthRejectsNegativeDimension — a negative
      shape dimension is rejected with kTfLiteError.

Happy to switch the manual > checks to __builtin_mul_overflow if that's
preferred for this tree.

@google-cla
Copy link
Copy Markdown

google-cla Bot commented May 8, 2026

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@Forbiddem Forbiddem marked this pull request as ready for review May 8, 2026 10:23
@Forbiddem Forbiddem requested a review from a team as a code owner May 8, 2026 10:23
`BytesRequiredForTensor`, `TfLiteEvalTensorByteLength`, and
`AllocateOutputDimensionsFromInput` in `tensorflow/lite/micro/memory_helpers.cc`
all multiplied tensor shape dimensions into a signed 32-bit `int element_count`
running product before assigning the result to a `size_t` byte count. Shape
dimensions and the element type size are sourced from the (untrusted)
flatbuffer model, so a model with a shape such as [65536, 65536] over a
4-byte element type produces an element-count product of 2^32, which wraps to
0 in the original code and yields `*bytes = 0`. Subsequent buffer
arithmetic in the allocator then operates on a tensor whose advertised size
is 0 while its dimensions imply ~17 GiB of storage, opening a memory
corruption surface.

This change:

  * Performs the running product in `size_t`, matching the result type, and
    rejects negative shape dimensions with `kTfLiteError`.
  * Guards every multiplication (shape * shape and elements * type_size)
    against overflow of `size_t` and returns `kTfLiteError` when the next
    multiplication would wrap.
  * Propagates the previously discarded status of `TfLiteTypeSizeOf` in
    `AllocateOutputDimensionsFromInput`.

Adds three regression tests in `memory_helpers_test.cc`:

  * Shape [65536, 65536] float32 reports the correct 17,179,869,184 byte
    length on platforms with a 64-bit `size_t` and `kTfLiteError` on
    platforms with a 32-bit `size_t` (instead of the pre-fix value of 0).
  * A shape that overflows even a 64-bit `size_t` is rejected with
    `kTfLiteError`.
  * A negative shape dimension is rejected with `kTfLiteError`.

All existing `memory_helpers_test` cases continue to pass.
@Forbiddem Forbiddem force-pushed the fix/memory-helpers-int-overflow branch from 82a8d21 to 20b8aaf Compare May 8, 2026 10:25
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.

1 participant