fix: restore input buffer size validation lost in the Nitro migration - #201
Merged
Merged
Conversation
TfLiteTensorCopyFromBuffer returns kTfLiteError and leaves the tensor untouched when the supplied byte size does not match the tensor's expected size. copyInputBuffers discarded that status, so a wrong-sized input ArrayBuffer was silently dropped and inference ran on whatever the tensor held from the previous call, returning plausible-looking but stale results instead of throwing. v2 threw "Input Buffer size (N) does not match the Input Tensor's expected size (M)!" from cpp/TensorHelpers.cpp; that check was removed when cpp/TensorHelpers.cpp was deleted in 6f86153 (margelo#172, the Nitro migration). Check the status and throw with the actual and expected byte sizes, and add harness coverage asserting a wrong-sized buffer throws instead of reusing the previous input.
Member
|
Thanks! |
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
copyInputBuffersdiscards theTfLiteStatusreturned byTfLiteTensorCopyFromBuffer. That function is documented asREQUIRES: input_data_size == TfLiteTensorByteSize(tensor)and, when the size does not match, it returnskTfLiteErrorand leaves the tensor untouched.https://github.com/mrousavy/react-native-fast-tflite/blob/691f4b8/cpp/HybridTfliteModel.cpp#L98
So passing a wrong-sized input
ArrayBuffertoday does not throw. The copy is dropped,TfLiteInterpreterInvokeruns anyway, and you get results computed from whatever was left in the input tensor from the previousrun/runSync(or the tensor's initial contents on the first call). The only surviving guard is the input tensor count check a few lines above.The user-visible symptom is "my outputs never change" rather than an error — which is what #64 describes. #120 quotes the error message that used to be raised for this exact case.
This is a regression
The check existed from
0313eec("feat: Check for input size mismatch", #17) and was removed by6f86153("feat: Migrate to Nitro Modules (for V3)", #172), which deletedcpp/TensorHelpers.cpp(‑293 lines) and did not carry the validation over into the newcpp/HybridTfliteModel.cpp.What v2 raised (
cpp/TensorHelpers.cpp:259-270at6f86153^):Worth noting: that v2 check was inside
#if DEBUG, so release builds of v2 already had the silent behaviour. The check here is unconditional — the cost is one comparison of an already-returned status code, and silently inferring on stale data is not something a release build should do either.The fix
Capture the status and throw with the actual and expected byte sizes, in the style of the surrounding errors. Requires no extra state and no extra TFLite calls on the success path.
The message produced for a 224x224x3 uint8 model given a buffer one byte short (copied verbatim from a harness run):
Testing
Three cases added to
example/__tests__/tflite.harness.tsagainst the already-bundledgoogle-quant.tflite. The third is the important one: it does not merely assert "a status code is checked", it reproduces the user-visible symptom — prime the model with one image, then pass a one-byte-short buffer holding a different image, and check the result is not byte-identical to the primed run. It then runs the same data at the correct size and asserts inference still succeeds and produces a different result, so the fix cannot pass by throwing on everything.iOS — iPhone 17 Pro Max simulator (iOS 26.3), Debug build,
yarn test:harness --harnessRunner ios:Tests: 19 passed, 19 totalTests: 3 failed, 16 passed, 19 totalAndroid — arm64 emulator (API 36), Debug build,
yarn test:harness --harnessRunner android:Tests: 19 passed, 19 totalTests: 3 failed, 16 passed, 19 totalThe counterfactual failure is identical on both platforms and shows the silent-stale-data behaviour directly:
reusedStaleInputbeingtrueis the bug: the run with the wrong-sized buffer returned the previous input's scores, byte for byte.All 16 pre-existing harness tests pass unchanged in every run above.
scripts/clang-format.shis clean, and the Android-Wall -Wextrabuild produces no new warnings (the one-Wsign-comparewarning atHybridTfliteModel.cpp:95is pre-existing and untouched).Interaction with the other open C++ PRs
Trial-merged locally against #196, #197 and #198 — all three merge cleanly with this branch, and
copyInputBufferskeeps the new check after merging #198 (which relocates the call site behind a lifecycle lock but does not change the function body).