-
Notifications
You must be signed in to change notification settings - Fork 204
vello_common: harden gradient LUT against invalid stop positions #1311
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
- Sanitize gradient stop positions with `sanitize_stop_position` to clamp NaNs, infinities, and out-of- range values into [0, 1]. - Use sanitized positions in `determine_lut_size` and LUT ramp construction to ensure indices are finite, monotonic, and within bounds. - Keep the 4-wide write in `GradientLut::new` bounded by `lut_size` so very small LUTs cannot trigger end- index panics. - Add targeted tests to verify sanitization behavior and ensure `GradientLut` handles infinite and out-of-range stop offsets without panicking.
f291f5b to
44cc593
Compare
|
This should fix against the panic mentioned by @nicoburns in a comment in #1302. Some notes / questions:
|
| fn sanitize_stop_position(pos: f32) -> f32 { | ||
| if pos.is_nan() { | ||
| 0.0 | ||
| } else if pos.is_infinite() { | ||
| if pos.is_sign_negative() { 0.0 } else { 1.0 } | ||
| } else { | ||
| pos.clamp(0.0, 1.0) | ||
| } | ||
| } | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The following is a branchless way to do this.
| fn sanitize_stop_position(pos: f32) -> f32 { | |
| if pos.is_nan() { | |
| 0.0 | |
| } else if pos.is_infinite() { | |
| if pos.is_sign_negative() { 0.0 } else { 1.0 } | |
| } else { | |
| pos.clamp(0.0, 1.0) | |
| } | |
| } | |
| #[inline] | |
| fn sanitize_stop_position(pos: f32) -> f32 { | |
| pos.max(0.).min(1.) | |
| } |
f32:{max,min} don't propagate NaNs (so the NaN gets turned in to 0., if pos.max(0.) is first).
LaurenzV
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We already have a method that aims to validate the gradient before even encoding it:
| fn validate(gradient: &Gradient) -> Result<(), Paint> { |
So I feel like it might be better to just add this additional case here? Not much point in trying to fix a gradient that is fundamentally broken. 😄
|
I'm actually surprised this doesn't already work, because we already are checking that each stop is between 0 and 1... |
|
I will figure out why and fix it! |
|
(I already know why, just have to drive home) |
sanitize_stop_positionto clamp NaNs, infinities, and out-of- range values into [0, 1].determine_lut_sizeand LUT ramp construction to ensure indices are finite, monotonic, and within bounds.GradientLut::newbounded bylut_sizeso very small LUTs cannot trigger end- index panics.GradientLuthandles infinite and out-of-range stop offsets without panicking.