summaryrefslogtreecommitdiffstats
path: root/image/test/fuzzing/TestDecoders.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'image/test/fuzzing/TestDecoders.cpp')
-rw-r--r--image/test/fuzzing/TestDecoders.cpp181
1 files changed, 181 insertions, 0 deletions
diff --git a/image/test/fuzzing/TestDecoders.cpp b/image/test/fuzzing/TestDecoders.cpp
new file mode 100644
index 0000000000..c5c0dcdb27
--- /dev/null
+++ b/image/test/fuzzing/TestDecoders.cpp
@@ -0,0 +1,181 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "gtest/gtest.h"
+
+#include "Common.h"
+#include "imgIContainer.h"
+#include "imgITools.h"
+#include "ImageOps.h"
+#include "mozilla/gfx/2D.h"
+#include "mozilla/Preferences.h"
+#include "nsComponentManagerUtils.h"
+#include "nsCOMPtr.h"
+#include "nsIInputStream.h"
+#include "nsIRunnable.h"
+#include "nsIThread.h"
+#include "mozilla/RefPtr.h"
+#include "nsString.h"
+#include "nsThreadUtils.h"
+
+#include "FuzzingInterfaceStream.h"
+
+using namespace mozilla;
+using namespace mozilla::gfx;
+using namespace mozilla::image;
+
+// Prevents x being optimized away if it has no side-effects.
+// If optimized away, tools like ASan wouldn't be able to detect
+// faulty memory accesses.
+#define DUMMY_IF(x) \
+ if (x) { \
+ volatile int v; \
+ v = 0; \
+ (void)v; \
+ }
+
+class DecodeToSurfaceRunnableFuzzing : public Runnable {
+ public:
+ DecodeToSurfaceRunnableFuzzing(RefPtr<SourceSurface>& aSurface,
+ nsIInputStream* aInputStream,
+ const char* mimeType)
+ : mozilla::Runnable("DecodeToSurfaceRunnableFuzzing"),
+ mSurface(aSurface),
+ mInputStream(aInputStream),
+ mMimeType(mimeType) {}
+
+ NS_IMETHOD Run() override {
+ Go();
+ return NS_OK;
+ }
+
+ void Go() {
+ mSurface = ImageOps::DecodeToSurface(mInputStream.forget(), mMimeType,
+ imgIContainer::DECODE_FLAGS_DEFAULT);
+ if (!mSurface) return;
+
+ if (mSurface->GetType() == SurfaceType::DATA) {
+ if (mSurface->GetFormat() == SurfaceFormat::OS_RGBX ||
+ mSurface->GetFormat() == SurfaceFormat::OS_RGBA) {
+ DUMMY_IF(IntSize(1, 1) == mSurface->GetSize());
+ DUMMY_IF(IsSolidColor(mSurface, BGRAColor::Green(), 1));
+ }
+ }
+ }
+
+ private:
+ RefPtr<SourceSurface>& mSurface;
+ nsCOMPtr<nsIInputStream> mInputStream;
+ nsAutoCString mMimeType;
+};
+
+static int RunDecodeToSurfaceFuzzing(nsCOMPtr<nsIInputStream> inputStream,
+ const char* mimeType) {
+ uint64_t len;
+ inputStream->Available(&len);
+ if (len <= 0) {
+ return 0;
+ }
+
+ // Ensure CMS state is initialized on the main thread.
+ gfxPlatform::GetCMSMode();
+
+ nsCOMPtr<nsIThread> thread;
+ nsresult rv =
+ NS_NewNamedThread("Decoder Test", getter_AddRefs(thread), nullptr);
+ MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
+
+ // We run the DecodeToSurface tests off-main-thread to ensure that
+ // DecodeToSurface doesn't require any other main-thread-only code.
+ RefPtr<SourceSurface> surface;
+ nsCOMPtr<nsIRunnable> runnable =
+ new DecodeToSurfaceRunnableFuzzing(surface, inputStream, mimeType);
+ NS_DispatchAndSpinEventLoopUntilComplete("RunDecodeToSurfaceFuzzing"_ns,
+ thread, runnable.forget());
+
+ thread->Shutdown();
+
+ // Explicitly release the SourceSurface on the main thread.
+ surface = nullptr;
+
+ return 0;
+}
+
+static int RunDecodeToSurfaceFuzzingJPEG(nsCOMPtr<nsIInputStream> inputStream) {
+ return RunDecodeToSurfaceFuzzing(inputStream, "image/jpeg");
+}
+
+static int RunDecodeToSurfaceFuzzingGIF(nsCOMPtr<nsIInputStream> inputStream) {
+ return RunDecodeToSurfaceFuzzing(inputStream, "image/gif");
+}
+
+static int RunDecodeToSurfaceFuzzingICO(nsCOMPtr<nsIInputStream> inputStream) {
+ return RunDecodeToSurfaceFuzzing(inputStream, "image/ico");
+}
+
+static int RunDecodeToSurfaceFuzzingBMP(nsCOMPtr<nsIInputStream> inputStream) {
+ return RunDecodeToSurfaceFuzzing(inputStream, "image/bmp");
+}
+
+static int RunDecodeToSurfaceFuzzingPNG(nsCOMPtr<nsIInputStream> inputStream) {
+ return RunDecodeToSurfaceFuzzing(inputStream, "image/png");
+}
+
+static int RunDecodeToSurfaceFuzzingWebP(nsCOMPtr<nsIInputStream> inputStream) {
+ return RunDecodeToSurfaceFuzzing(inputStream, "image/webp");
+}
+
+static int RunDecodeToSurfaceFuzzingAVIF(nsCOMPtr<nsIInputStream> inputStream) {
+ return RunDecodeToSurfaceFuzzing(inputStream, "image/avif");
+}
+
+#ifdef MOZ_JXL
+static int RunDecodeToSurfaceFuzzingJXL(nsCOMPtr<nsIInputStream> inputStream) {
+ return RunDecodeToSurfaceFuzzing(inputStream, "image/jxl");
+}
+#endif
+
+int FuzzingInitImage(int* argc, char*** argv) {
+ Preferences::SetBool("image.avif.sequence.enabled", true);
+ Preferences::SetBool("image.mem.max_legal_imgframe_size_kb", 65536);
+#ifdef MOZ_JXL
+ Preferences::SetBool("image.jxl.enabled", true);
+#endif
+
+ nsCOMPtr<imgITools> imgTools =
+ do_CreateInstance("@mozilla.org/image/tools;1");
+ if (imgTools == nullptr) {
+ std::cerr << "Initializing image tools failed" << std::endl;
+ return 1;
+ }
+
+ return 0;
+}
+
+MOZ_FUZZING_INTERFACE_STREAM(FuzzingInitImage, RunDecodeToSurfaceFuzzingJPEG,
+ ImageJPEG);
+
+MOZ_FUZZING_INTERFACE_STREAM(FuzzingInitImage, RunDecodeToSurfaceFuzzingGIF,
+ ImageGIF);
+
+MOZ_FUZZING_INTERFACE_STREAM(FuzzingInitImage, RunDecodeToSurfaceFuzzingICO,
+ ImageICO);
+
+MOZ_FUZZING_INTERFACE_STREAM(FuzzingInitImage, RunDecodeToSurfaceFuzzingBMP,
+ ImageBMP);
+
+MOZ_FUZZING_INTERFACE_STREAM(FuzzingInitImage, RunDecodeToSurfaceFuzzingPNG,
+ ImagePNG);
+
+MOZ_FUZZING_INTERFACE_STREAM(FuzzingInitImage, RunDecodeToSurfaceFuzzingWebP,
+ ImageWebP);
+
+MOZ_FUZZING_INTERFACE_STREAM(FuzzingInitImage, RunDecodeToSurfaceFuzzingAVIF,
+ ImageAVIF);
+
+#ifdef MOZ_JXL
+MOZ_FUZZING_INTERFACE_STREAM(FuzzingInitImage, RunDecodeToSurfaceFuzzingJXL,
+ ImageJXL);
+#endif