TestDecoders.cpp (5816B)
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6 #include "gtest/gtest.h" 7 8 #include "Common.h" 9 #include "imgIContainer.h" 10 #include "imgITools.h" 11 #include "ImageOps.h" 12 #include "mozilla/gfx/2D.h" 13 #include "mozilla/Preferences.h" 14 #include "nsComponentManagerUtils.h" 15 #include "nsCOMPtr.h" 16 #include "nsIInputStream.h" 17 #include "nsIRunnable.h" 18 #include "nsIThread.h" 19 #include "mozilla/RefPtr.h" 20 #include "nsString.h" 21 #include "nsThreadUtils.h" 22 23 #include "FuzzingInterfaceStream.h" 24 25 using namespace mozilla; 26 using namespace mozilla::gfx; 27 using namespace mozilla::image; 28 29 // Prevents x being optimized away if it has no side-effects. 30 // If optimized away, tools like ASan wouldn't be able to detect 31 // faulty memory accesses. 32 #define DUMMY_IF(x) \ 33 if (x) { \ 34 volatile int v; \ 35 v = 0; \ 36 (void)v; \ 37 } 38 39 class DecodeToSurfaceRunnableFuzzing : public Runnable { 40 public: 41 DecodeToSurfaceRunnableFuzzing(RefPtr<SourceSurface>& aSurface, 42 nsIInputStream* aInputStream, 43 const char* mimeType) 44 : mozilla::Runnable("DecodeToSurfaceRunnableFuzzing"), 45 mSurface(aSurface), 46 mInputStream(aInputStream), 47 mMimeType(mimeType) {} 48 49 NS_IMETHOD Run() override { 50 Go(); 51 return NS_OK; 52 } 53 54 void Go() { 55 mSurface = ImageOps::DecodeToSurface(mInputStream.forget(), mMimeType, 56 imgIContainer::DECODE_FLAGS_DEFAULT); 57 if (!mSurface) return; 58 59 if (mSurface->GetType() == SurfaceType::DATA) { 60 if (mSurface->GetFormat() == SurfaceFormat::OS_RGBX || 61 mSurface->GetFormat() == SurfaceFormat::OS_RGBA) { 62 DUMMY_IF(IntSize(1, 1) == mSurface->GetSize()); 63 DUMMY_IF(IsSolidColor(mSurface, BGRAColor::Green(), 1)); 64 } 65 } 66 } 67 68 private: 69 RefPtr<SourceSurface>& mSurface; 70 nsCOMPtr<nsIInputStream> mInputStream; 71 nsAutoCString mMimeType; 72 }; 73 74 static int RunDecodeToSurfaceFuzzing(nsCOMPtr<nsIInputStream> inputStream, 75 const char* mimeType) { 76 uint64_t len; 77 inputStream->Available(&len); 78 if (len <= 0) { 79 return 0; 80 } 81 82 // Ensure CMS state is initialized on the main thread. 83 gfxPlatform::GetCMSMode(); 84 85 nsCOMPtr<nsIThread> thread; 86 nsresult rv = 87 NS_NewNamedThread("Decoder Test", getter_AddRefs(thread), nullptr); 88 MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv)); 89 90 // We run the DecodeToSurface tests off-main-thread to ensure that 91 // DecodeToSurface doesn't require any other main-thread-only code. 92 RefPtr<SourceSurface> surface; 93 nsCOMPtr<nsIRunnable> runnable = 94 new DecodeToSurfaceRunnableFuzzing(surface, inputStream, mimeType); 95 NS_DispatchAndSpinEventLoopUntilComplete("RunDecodeToSurfaceFuzzing"_ns, 96 thread, runnable.forget()); 97 98 thread->Shutdown(); 99 100 // Explicitly release the SourceSurface on the main thread. 101 surface = nullptr; 102 103 return 0; 104 } 105 106 static int RunDecodeToSurfaceFuzzingJPEG(nsCOMPtr<nsIInputStream> inputStream) { 107 return RunDecodeToSurfaceFuzzing(inputStream, "image/jpeg"); 108 } 109 110 static int RunDecodeToSurfaceFuzzingGIF(nsCOMPtr<nsIInputStream> inputStream) { 111 return RunDecodeToSurfaceFuzzing(inputStream, "image/gif"); 112 } 113 114 static int RunDecodeToSurfaceFuzzingICO(nsCOMPtr<nsIInputStream> inputStream) { 115 return RunDecodeToSurfaceFuzzing(inputStream, "image/ico"); 116 } 117 118 static int RunDecodeToSurfaceFuzzingBMP(nsCOMPtr<nsIInputStream> inputStream) { 119 return RunDecodeToSurfaceFuzzing(inputStream, "image/bmp"); 120 } 121 122 static int RunDecodeToSurfaceFuzzingPNG(nsCOMPtr<nsIInputStream> inputStream) { 123 return RunDecodeToSurfaceFuzzing(inputStream, "image/png"); 124 } 125 126 static int RunDecodeToSurfaceFuzzingWebP(nsCOMPtr<nsIInputStream> inputStream) { 127 return RunDecodeToSurfaceFuzzing(inputStream, "image/webp"); 128 } 129 130 static int RunDecodeToSurfaceFuzzingAVIF(nsCOMPtr<nsIInputStream> inputStream) { 131 return RunDecodeToSurfaceFuzzing(inputStream, "image/avif"); 132 } 133 134 #ifdef MOZ_JXL 135 static int RunDecodeToSurfaceFuzzingJXL(nsCOMPtr<nsIInputStream> inputStream) { 136 return RunDecodeToSurfaceFuzzing(inputStream, "image/jxl"); 137 } 138 #endif 139 140 int FuzzingInitImage(int* argc, char*** argv) { 141 Preferences::SetBool("image.avif.sequence.enabled", true); 142 Preferences::SetInt("image.mem.max_legal_imgframe_size_kb", 65536); 143 #ifdef MOZ_JXL 144 Preferences::SetBool("image.jxl.enabled", true); 145 #endif 146 147 nsCOMPtr<imgITools> imgTools = 148 do_CreateInstance("@mozilla.org/image/tools;1"); 149 if (imgTools == nullptr) { 150 std::cerr << "Initializing image tools failed" << std::endl; 151 return 1; 152 } 153 154 return 0; 155 } 156 157 MOZ_FUZZING_INTERFACE_STREAM(FuzzingInitImage, RunDecodeToSurfaceFuzzingJPEG, 158 ImageJPEG); 159 160 MOZ_FUZZING_INTERFACE_STREAM(FuzzingInitImage, RunDecodeToSurfaceFuzzingGIF, 161 ImageGIF); 162 163 MOZ_FUZZING_INTERFACE_STREAM(FuzzingInitImage, RunDecodeToSurfaceFuzzingICO, 164 ImageICO); 165 166 MOZ_FUZZING_INTERFACE_STREAM(FuzzingInitImage, RunDecodeToSurfaceFuzzingBMP, 167 ImageBMP); 168 169 MOZ_FUZZING_INTERFACE_STREAM(FuzzingInitImage, RunDecodeToSurfaceFuzzingPNG, 170 ImagePNG); 171 172 MOZ_FUZZING_INTERFACE_STREAM(FuzzingInitImage, RunDecodeToSurfaceFuzzingWebP, 173 ImageWebP); 174 175 MOZ_FUZZING_INTERFACE_STREAM(FuzzingInitImage, RunDecodeToSurfaceFuzzingAVIF, 176 ImageAVIF); 177 178 #ifdef MOZ_JXL 179 MOZ_FUZZING_INTERFACE_STREAM(FuzzingInitImage, RunDecodeToSurfaceFuzzingJXL, 180 ImageJXL); 181 #endif