Prevent Cubic transform from looping on out-of-range input#185875
Prevent Cubic transform from looping on out-of-range input#185875auto-submit[bot] merged 3 commits into
Conversation
There was a problem hiding this comment.
Code Review
This pull request updates the Cubic.transformInternal method to clamp input values outside the unit interval [0, 1] to 0.0 or 1.0 and adds a regression test for this behavior. Review feedback identifies that double.nan is currently unhandled, which could lead to an infinite loop in the binary search, and suggests adding an explicit check for NaN along with a corresponding test case.
54d43e1 to
5404f85
Compare
| if (t.isNaN || t <= 0.0) { | ||
| return 0.0; | ||
| } | ||
| if (t >= 1.0) { | ||
| return 1.0; | ||
| } |
There was a problem hiding this comment.
Are you sure that we should correct this rather than throwing an error? I think at least for t.isNaN we should probably throw.
Also, why should we return 0 and 1? If we're not going to throw, we should probably just clamp t between 0 and 1 and return the evaluated value.
There was a problem hiding this comment.
return the evaluated value.
Or maybe that should be equivalent to 0 and 1 anyway:
flutter/packages/flutter/lib/src/animation/curves.dart
Lines 84 to 85 in 583dec7
There was a problem hiding this comment.
@gabrimatic can you share your thoughts on the above questions?
There was a problem hiding this comment.
Yes, agreed on NaN: it should not be silently mapped to an endpoint. The latest commit changes that path to throw ArgumentError instead.
For finite values outside [0, 1], my reasoning is that clamping is the better release-mode behavior here than throwing from Cubic.transformInternal. The public validation path is still unchanged: Curve.transform asserts that t is in range in debug mode. The bug is that, once that assert is stripped in profile/release, an invalid finite value can reach the Cubic inverse solver and spin forever instead of terminating.
Returning 0.0 / 1.0 is the same semantic result as clamping t to the nearest endpoint and applying the curve endpoint contract. Curve.transform, CurveTween, and CurvedAnimation already special-case endpoints so curves produce exact endpoint values there. There is also existing precedent for clamping animation progress before applying curve behavior, for example Interval and the interpolation simulation path.
I returned the endpoints directly rather than clamping and then running the Cubic solver because the solver is approximate by design (_cubicErrorBound). At the boundary, going through the binary search can produce a value that is only near the endpoint, while the curve contract expects exact 0.0 and 1.0 at the endpoints.
So the intended behavior is: keep debug assertions for invalid public transform calls, throw for NaN because there is no meaningful nearest endpoint, and clamp finite out-of-range release/profile values to the exact nearest endpoint so this path always terminates.
Piinks
left a comment
There was a problem hiding this comment.
This LGTM thank you @gabrimatic
59a5eed to
8640bb7
Compare
Roll Flutter from 2ba5420a7049 to 1bdf4af29076 (43 revisions) flutter/flutter@2ba5420...1bdf4af 2026-06-05 engine-flutter-autoroll@skia.org Roll Packages from 03352b5 to 61bdbb4 (5 revisions) (flutter/flutter#187612) 2026-06-05 engine-flutter-autoroll@skia.org Roll Skia from 6e003d7f69c8 to a47a9a2c8ae5 (1 revision) (flutter/flutter#187610) 2026-06-05 engine-flutter-autoroll@skia.org Roll Dart SDK from aad8be4ce307 to 6a9a0efe66eb (10 revisions) (flutter/flutter#187609) 2026-06-05 engine-flutter-autoroll@skia.org Roll Skia from 494f1bf55f51 to 6e003d7f69c8 (2 revisions) (flutter/flutter#187607) 2026-06-05 engine-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from ZE1Jy9CtVVi-tjBAE... to N_LiSaBSUsE2LDZgG... (flutter/flutter#187597) 2026-06-05 engine-flutter-autoroll@skia.org Roll Skia from 59556fdb8c33 to 494f1bf55f51 (2 revisions) (flutter/flutter#187596) 2026-06-04 engine-flutter-autoroll@skia.org Roll Skia from 8eb107046fd5 to 59556fdb8c33 (1 revision) (flutter/flutter#187590) 2026-06-04 34871572+gmackall@users.noreply.github.com Remove `embedded_android_views_integration_test.dart` (flutter/flutter#187465) 2026-06-04 burak.karahan@mail.ru Remove Material imports from rendering editable tests (flutter/flutter#186951) 2026-06-04 jason-simmons@users.noreply.github.com [Impeller] Wait for the Vulkan device to become idle before destroying Vulkan objects in the AHBSwapchainImplVK destructor (flutter/flutter#187477) 2026-06-04 chris@bracken.jp [iOS] Eliminate unnecessary redeclaration of FlutterDisplayLink (flutter/flutter#187557) 2026-06-04 engine-flutter-autoroll@skia.org Roll Skia from 928ded2a31af to 8eb107046fd5 (1 revision) (flutter/flutter#187583) 2026-06-04 34871572+gmackall@users.noreply.github.com Log stdout in adb.dart (flutter/flutter#187531) 2026-06-04 mvincentong@gmail.com Clarify RouterDelegate popRoute bubbling (flutter/flutter#186875) 2026-06-04 engine-flutter-autoroll@skia.org Roll Skia from 928ded2a31af to 8eb107046fd5 (1 revision) (flutter/flutter#187584) 2026-06-04 1063596+reidbaker@users.noreply.github.com Add updating-android-sdk agent skill for rolling Android SDK in CIPD (flutter/flutter#187576) 2026-06-04 Rusino@users.noreply.github.com Fixing alignment issue (flutter/flutter#187518) 2026-06-04 brackenavaron@gmail.com [Material Cross Imports] Clean up Material Divider usages (flutter/flutter#187300) 2026-06-04 engine-flutter-autoroll@skia.org Roll Skia from cecc0e0da9ae to 928ded2a31af (6 revisions) (flutter/flutter#187574) 2026-06-04 31859944+LongCatIsLooong@users.noreply.github.com Use swift demangle to verify internal Swift symbols (flutter/flutter#186835) 2026-06-04 1063596+reidbaker@users.noreply.github.com Add android 37 platform and build tools to script for android cipd bundle creation (flutter/flutter#187571) 2026-06-04 jason-simmons@users.noreply.github.com [Impeller] Increase the precision of the IPSampleWithTileModeOES coords parameter to match the input coordinates in the tiled_texture_fill_external shader (flutter/flutter#187545) 2026-06-04 engine-flutter-autoroll@skia.org Roll Packages from b11504f to 03352b5 (4 revisions) (flutter/flutter#187569) 2026-06-04 iinozemtsev@google.com Roll Dart SDK to Dart 3.13 beta2 (flutter/flutter#187555) 2026-06-04 engine-flutter-autoroll@skia.org Roll Skia from 611e3f8ceb93 to cecc0e0da9ae (1 revision) (flutter/flutter#187562) 2026-06-04 6655696+guidezpl@users.noreply.github.com Add step to bootstrap Flutter tool in coverage workflow (flutter/flutter#187199) 2026-06-04 engine-flutter-autoroll@skia.org Roll Skia from 4fdb859c8da7 to 611e3f8ceb93 (4 revisions) (flutter/flutter#187554) 2026-06-04 engine-flutter-autoroll@skia.org Roll Skia from 0020aae33f63 to 4fdb859c8da7 (2 revisions) (flutter/flutter#187552) 2026-06-04 engine-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from ap7MhLX4TdpWRrLS_... to ZE1Jy9CtVVi-tjBAE... (flutter/flutter#187550) 2026-06-04 stuartmorgan@google.com Add vector_math to package issue template (flutter/flutter#187536) 2026-06-04 jason-simmons@users.noreply.github.com Manual roll Dart SDK from d39850bf4a01 to 3b70b98fa7c0 (flutter/flutter#187519) 2026-06-04 engine-flutter-autoroll@skia.org Roll Skia from d625048c853a to 0020aae33f63 (20 revisions) (flutter/flutter#187539) 2026-06-04 smille2003@yandex.ru [Impeller][Windows] fix black screen on OpenGL fallback (flutter/flutter#187288) 2026-06-04 97480502+b-luk@users.noreply.github.com Fix unintentionally joined path contours (flutter/flutter#187522) 2026-06-03 matt.boetger@gmail.com fix: resolve issue #177379 by using lazy buildDirectory.dir() API in build.gradle template (flutter/flutter#187127) 2026-06-03 34871572+gmackall@users.noreply.github.com Add a skill for flake analysis (flutter/flutter#187530) 2026-06-03 30870216+gaaclarke@users.noreply.github.com adds linux impeller project flag (flutter/flutter#186982) 2026-06-03 codedoctor@linwood.dev Add support for stylus buttons (flutter/flutter#183369) 2026-06-03 46920873+gabrimatic@users.noreply.github.com Prevent Cubic transform from looping on out-of-range input (flutter/flutter#185875) 2026-06-03 bdero@google.com [Impeller] Reland: Allow attaching specific texture mip levels and slices (flutter/flutter#187470) 2026-06-03 kjlubick@users.noreply.github.com [skia] Update image deserial proc (flutter/flutter#185041) 2026-06-03 112751483+shivanshu877@users.noreply.github.com docs: update Impeller advanced blend docs for framebuffer fetch (flutter/flutter#185457) 2026-06-03 ahmedsameha1@gmail.com Handle#6537 fifth grouped tests (flutter/flutter#183720) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: ...
Fixes #171364
Cubic.transformInternaluses a binary search over the unit interval to invert the curve x-coordinate. In debug mode,Curve.transformasserts that callers pass values in[0, 1]. In profile/release, that assert is stripped, so out-of-range inputs can reach the Cubic solver. For values below0.0or above1.0, the search converges to an endpoint but may never satisfy the error bound, which can spin indefinitely and cause an ANR.This clamps the Cubic solver boundary to return the endpoint values for out-of-range inputs. That preserves the existing debug assertion path through
Curve.transform, avoids a release-mode crash, and matches the boundary behavior used by other curve wrappers such asInterval.Tests:
flutter analyze --no-pub lib/src/animation/curves.dart test/animation/curves_test.dartflutter test test/animation/curves_test.dart --plain-name="Cubic transformInternal clamps values outside the unit interval"flutter test test/animation/curves_test.dartflutter test test/animation