Drop APNG frames that don't fit entirely within the destination surface. (flutter/engine#56928)
As per the [spec](https://www.w3.org/TR/png/#fcTL-chunk): > The frame must be rendered within the region defined by x_offset, y_offset, width, and height. This region may not fall outside of the default image; thus x_offset plus width must not be greater than the [IHDR](https://www.w3.org/TR/png/#11IHDR) width; similarly y_offset plus height must not be greater than the [IHDR](https://www.w3.org/TR/png/#11IHDR) height.
This commit is contained in:
parent
7b1b6d13f2
commit
ba21393f49
BIN
engine/src/flutter/lib/ui/fixtures/out_of_bounds.apng
Normal file
BIN
engine/src/flutter/lib/ui/fixtures/out_of_bounds.apng
Normal file
Binary file not shown.
After Width: | Height: | Size: 126 B |
@ -197,7 +197,7 @@ TEST(ImageDecoderNoGLTest, ImpellerWideGamutIndexedPng) {
|
||||
#endif // IMPELLER_SUPPORTS_RENDERING
|
||||
}
|
||||
|
||||
TEST(ImageDecoderNoGLTest, ImepllerUnmultipliedAlphaPng) {
|
||||
TEST(ImageDecoderNoGLTest, ImpellerUnmultipliedAlphaPng) {
|
||||
#if defined(OS_FUCHSIA)
|
||||
GTEST_SKIP() << "Fuchsia can't load the test fixtures.";
|
||||
#endif
|
||||
|
@ -110,6 +110,20 @@ bool APNGImageGenerator::GetPixels(const SkImageInfo& info,
|
||||
<< ") of APNG due to the frame missing data (frame_info).";
|
||||
return false;
|
||||
}
|
||||
if (frame.x_offset + frame_info.width() >
|
||||
static_cast<unsigned int>(info.width()) ||
|
||||
frame.y_offset + frame_info.height() >
|
||||
static_cast<unsigned int>(info.height())) {
|
||||
FML_DLOG(ERROR)
|
||||
<< "Decoded image at index " << image_index
|
||||
<< " (frame index: " << frame_index
|
||||
<< ") rejected because the destination region (x: " << frame.x_offset
|
||||
<< ", y: " << frame.y_offset << ", width: " << frame_info.width()
|
||||
<< ", height: " << frame_info.height()
|
||||
<< ") is not entirely within the destination surface (width: "
|
||||
<< info.width() << ", height: " << info.height() << ").";
|
||||
return false;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
/// 3. Composite the frame onto the canvas.
|
||||
@ -630,7 +644,19 @@ uint32_t APNGImageGenerator::ChunkHeader::ComputeChunkCrc32() {
|
||||
bool APNGImageGenerator::RenderDefaultImage(const SkImageInfo& info,
|
||||
void* pixels,
|
||||
size_t row_bytes) {
|
||||
SkCodec::Result result = images_[0].codec->getPixels(info, pixels, row_bytes);
|
||||
APNGImage& frame = images_[0];
|
||||
SkImageInfo frame_info = frame.codec->getInfo();
|
||||
if (frame_info.width() > info.width() ||
|
||||
frame_info.height() > info.height()) {
|
||||
FML_DLOG(ERROR)
|
||||
<< "Default image rejected because the destination region (width: "
|
||||
<< frame_info.width() << ", height: " << frame_info.height()
|
||||
<< ") is not entirely within the destination surface (width: "
|
||||
<< info.width() << ", height: " << info.height() << ").";
|
||||
return false;
|
||||
}
|
||||
|
||||
SkCodec::Result result = frame.codec->getPixels(info, pixels, row_bytes);
|
||||
if (result != SkCodec::kSuccess) {
|
||||
FML_DLOG(ERROR) << "Failed to decode the APNG's default/fallback image. "
|
||||
"SkCodec::Result: "
|
||||
|
@ -252,6 +252,26 @@ void main() {
|
||||
imageData = (await image.toByteData())!;
|
||||
expect(imageData.getUint32(imageData.lengthInBytes - 4), 0x00000000);
|
||||
});
|
||||
|
||||
test(
|
||||
'Animated apng frame decode does not crash with invalid destination region',
|
||||
() async {
|
||||
final Uint8List data = File(
|
||||
path.join('flutter', 'lib', 'ui', 'fixtures', 'out_of_bounds.apng'),
|
||||
).readAsBytesSync();
|
||||
|
||||
final ui.Codec codec = await ui.instantiateImageCodec(data);
|
||||
try {
|
||||
await codec.getNextFrame();
|
||||
fail('exception not thrown');
|
||||
} on Exception catch (e) {
|
||||
if (impellerEnabled) {
|
||||
expect(e.toString(), contains('Could not decompress image.'));
|
||||
} else {
|
||||
expect(e.toString(), contains('Codec failed'));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// Returns a File handle to a file in the skia/resources directory.
|
||||
|
Loading…
x
Reference in New Issue
Block a user