Skip to content
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

Limit decoded images to 2^26 pixels by default #82

Merged
merged 1 commit into from
Oct 2, 2018

Conversation

zealousidealroll
Copy link
Contributor

Fixes #80

@bvssvni
Copy link
Contributor

bvssvni commented Sep 1, 2018

Looks good to me.

@HeroicKatora
Copy link
Member

The limit appears somewhat arbitrary to me. Is it referring to a limit already established in another library?

@HeroicKatora
Copy link
Member

HeroicKatora commented Sep 1, 2018

Considering that it triggers on a quadratic image of width and length each 2^13 = 8192 which is already well in range of some of the better cameras (current DSLR having 20-40M at the moment) and might even become a monitor resolution in the foreseeable future. For example, IMAX is estimated at just about 10000x7000 according to Wikipedia. And Japan wants to record the 2020 olympics in 16k resolution (close to 132M).

@oyvindln
Copy link
Contributor

oyvindln commented Sep 1, 2018

In the BMP decoder in image there is a max of 2^16, though one may not expect bmp images to be quite as large as a png image (as they are not, or only very slightly compressed).

There is also a limit on how much memory the decoder allocates at a first try, and it will only allocate more if there is actually image data for it. Maybe something similar could be done here.

Ideally though it would be nice if a limit could be specified, so the caller could give some reasonable expected max size based on say the file size.

@HeroicKatora
Copy link
Member

HeroicKatora commented Sep 1, 2018

The max in BMP is enforced for width and height individually, so in total limit the size to something slightly smaller than 2^32. The limit proposed here is for the actual pixel count, width*height.

The suggestion on additional memory optimization sounds sensible, so like an adjusted read_to_end where we have a slightly different heuristic because we expect the full image instead of an unknown amount of data.

@oyvindln
Copy link
Contributor

oyvindln commented Sep 2, 2018

Yeah I meant to write 2^16 in one direction but I somehow missed it.

@zealousidealroll
Copy link
Contributor Author

The limit was copied from the flif crate.

@HeroicKatora
Copy link
Member

Ah, I didn't realize that. In the corresponding pull request, the choice was explained as follows:

Default values allow maximum size of DecodingImage's data equal to 2^26, which is equal to 512 MB.

Now I wonder if we should differentiate between a pixel and a memory limit. png allows bit depths of up to 16 bit and up to 4 samples per pixel, leading to up to 16=2^4 bytes per pixel in the most extreme case. Setting a limit on the number of pixels would enforce somewhere between 32MiBi and 1024MiBi of memory usage, depending on the colour format.

However, that is more of a bikeshedding issue for now, with prior art demonstrated it might be sensible to just merge it for now. Increasing the default limit in the future or adding alternative and optional additional limits should not be a breaking change anyways.

pub struct Limits {
/// max number of pixels: `width * height` (default: 67M = 2<sup>26</sup>)
pixels: u64,
}

Choose a reason for hiding this comment

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

I think there shouldn't be any problems with making pixels field public. This will also allow us to remove set_pixels setter.

/// assert!(decoder.read_info().is_ok());
/// ```
pub fn set_limits(&mut self, limits: Limits) {
self.limits = limits;

Choose a reason for hiding this comment

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

How about using new_with_limits(r: R, limits: Limits) method instead? It will allow to create decoder in one line and new can be defined as Self::new_with_limits(r, Default::default()).

@Shnatsel
Copy link
Contributor

Shnatsel commented Sep 14, 2018

For reference, libpng enforces 1,000,000 by 1,000,000 pixels limit by default, which is roughly 2^40 pixels or 2^44 bytes per image in the extreme case.

Source and further information: https://libpng.sourceforge.io/decompression_bombs.html

@zealousidealroll
Copy link
Contributor Author

zealousidealroll commented Sep 14, 2018

2^40 pixels

  • Even with a measly 256 colors (so it would be 2^40 bytes), that's bigger than the entire address space on a 32-bit system. If nothing else, the limits should never be higher than 2^27 on a 32-bit system (making 2^31 bytes at 2^4=16 bytes per pixel, which will exactly fill the userland-accessible address space on a 32-bit system where the upper half is reserved for the operating system). If you think anyone's going to need higher, then it should probably be conditional on the platform.

  • According to my quick Wikipedia visit, an 8K picture is 2^25 pixels. In the immortal words of Bill Gates, 8K should be enough for anybody.

@bvssvni
Copy link
Contributor

bvssvni commented Oct 2, 2018

Merging.

@bvssvni bvssvni merged commit 91aca94 into image-rs:master Oct 2, 2018
@zealousidealroll zealousidealroll deleted the decode-limits branch October 2, 2018 20:48
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.

None yet

6 participants