blob: 6ba7438f15d84b1a1aa6860c9fad434c4b24725b [file]
/*
* Copyright 2014 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "include/codec/SkCodec.h"
#include "include/core/SkBitmap.h"
#include "include/core/SkData.h"
#include "include/core/SkStream.h"
#include "include/core/SkString.h"
#include "include/core/SkTypes.h"
#include "src/utils/SkOSPath.h"
#include "tests/CodecPriv.h"
#include "tests/Test.h"
#include "tools/Resources.h"
#include <array>
#include <cstddef>
#include <cstdint>
#include <memory>
#include <utility>
#if defined(SK_CODEC_DECODES_PNG_WITH_LIBPNG)
#include "include/codec/SkPngDecoder.h"
#endif
#if defined(SK_CODEC_DECODES_PNG_WITH_RUST)
#include "include/codec/SkPngRustDecoder.h"
#endif
DEF_TEST(BadImage, reporter) {
static constexpr auto badImages = std::to_array<const char*>({
"sigabort_favicon.ico",
"sigsegv_favicon.ico",
"sigsegv_favicon_2.ico",
"ico_leak01.ico",
"ico_fuzz0.ico",
"ico_fuzz1.ico",
"skbug3442.webp",
"skbug3429.webp",
"b38116746.ico",
"skbug5883.gif",
});
const char* badImagesFolder = "invalid_images";
for (size_t i = 0; i < std::size(badImages); ++i) {
SkString resourcePath = SkOSPath::Join(badImagesFolder, badImages[i]);
std::unique_ptr<SkStream> stream(GetResourceAsStream(resourcePath.c_str()));
std::unique_ptr<SkCodec> codec(SkCodec::MakeFromStream(std::move(stream)));
// These images are corrupt. It's not important whether we succeed/fail in codec
// creation or decoding. We just want to make sure that we don't crash.
if (codec) {
SkBitmap bm;
bm.allocPixels(codec->getInfo());
codec->getPixels(codec->getInfo(), bm.getPixels(),
bm.rowBytes());
}
}
}
#if defined(SK_CODEC_DECODES_ICO)
static void test_bad_png_in_ico_does_not_fallback(skiatest::Reporter* r,
const SkCodecs::Decoder& pngDecoder) {
ScopedCodecDecoders scopedDecoders;
// 1. When the PNG decoder is registered, decoding an ICO with a malformed PNG fails cleanly
// without falling back to libpng.
SkCodecs::Register(pngDecoder);
constexpr uint8_t kMalformedPng[] = {
0x89,
'P',
'N',
'G',
'\r',
'\n',
0x1A,
'\n',
0x00,
0x00,
0x00,
0x00,
};
sk_sp<SkData> badIcoData = make_ico_with_png(kMalformedPng, sizeof(kMalformedPng));
REPORTER_ASSERT(r, badIcoData);
std::unique_ptr<SkCodec> badCodec = SkCodec::MakeFromStream(SkMemoryStream::Make(badIcoData));
REPORTER_ASSERT(
r, badCodec == nullptr, "Malformed PNG in ICO should fail without fallback to libpng");
// 2. Verify that when a registered PNG decoder rejects a valid PNG that libpng could decode,
// SkIcoCodec does not fall back to libpng (or attempt a redundant second decode).
SkCodecs::Register({
"png",
pngDecoder.isFormat,
[](std::unique_ptr<SkStream>, SkCodec::Result* result, SkCodecs::DecodeContext)
-> std::unique_ptr<SkCodec> {
if (result) {
*result = SkCodec::kErrorInInput;
}
return nullptr;
},
});
sk_sp<SkData> icoWithValidPng = make_ico_from_png_resource(r, "images/mandrill_128.png");
std::unique_ptr<SkCodec> rejectedCodec =
SkCodec::MakeFromStream(SkMemoryStream::Make(icoWithValidPng));
REPORTER_ASSERT(r,
rejectedCodec == nullptr,
"SkIcoCodec must not fall back to libpng when a PNG decoder is registered");
}
#if defined(SK_CODEC_DECODES_PNG_WITH_RUST)
DEF_SERIAL_TEST(Ico_malformedPngWithRustDecoderDoesNotFallback, r) {
test_bad_png_in_ico_does_not_fallback(r, SkPngRustDecoder::Decoder());
}
#endif
#if defined(SK_CODEC_DECODES_PNG_WITH_LIBPNG)
DEF_SERIAL_TEST(Ico_malformedPngWithLibpngNoRedundantFallback, r) {
test_bad_png_in_ico_does_not_fallback(r, SkPngDecoder::Decoder());
}
#endif
#endif // SK_CODEC_DECODES_ICO