Bug 1318548 - Experimental image decoder code for LibFuzzer. r=aosmond
authorChristian Holler (:decoder) <choller@mozilla.com>
Mon, 19 Sep 2016 16:59:44 +0200
changeset 432963 4a850ded2e3e31f86b183dbf1071e92842c6428d
parent 432962 952bd76f99bcbfc6b22cc9083a8804b940c67051
child 432983 b3820db371aee902b4b903483b02ba79082951bd
push id1567
push userjlorenzo@mozilla.com
push dateThu, 02 Nov 2017 12:36:05 +0000
treeherdermozilla-release@e512c14a0406 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersaosmond
bugs1318548
milestone57.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1318548 - Experimental image decoder code for LibFuzzer. r=aosmond
image/moz.build
image/test/fuzzing/TestDecoders.cpp
image/test/fuzzing/moz.build
--- a/image/moz.build
+++ b/image/moz.build
@@ -3,16 +3,19 @@
 # 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/.
 
 DIRS += ['build', 'decoders', 'encoders']
 if CONFIG['ENABLE_TESTS']:
     DIRS += ['test/gtest']
 
+if CONFIG['FUZZING']:
+    DIRS += ['test/fuzzing']
+
 with Files('**'):
     BUG_COMPONENT = ('Core', 'ImageLib')
 
 BROWSER_CHROME_MANIFESTS += ['test/browser/browser.ini']
 
 MOCHITEST_MANIFESTS += ['test/mochitest/mochitest.ini']
 
 MOCHITEST_CHROME_MANIFESTS += ['test/mochitest/chrome.ini']
@@ -108,8 +111,14 @@ LOCAL_INCLUDES += [
 
 # Because imgFrame.cpp includes "cairo.h"
 CXXFLAGS += CONFIG['MOZ_CAIRO_CFLAGS']
 
 LOCAL_INCLUDES += CONFIG['SKIA_INCLUDES']
 
 if CONFIG['GNU_CXX']:
     CXXFLAGS += ['-Wno-error=shadow']
+
+if CONFIG['FUZZING']:
+    if CONFIG['LIBFUZZER']:
+        # Add trace-pc coverage for libfuzzer
+        CFLAGS += ['-fsanitize-coverage=trace-pc-guard']
+        CXXFLAGS += ['-fsanitize-coverage=trace-pc-guard']
new file mode 100644
--- /dev/null
+++ b/image/test/fuzzing/TestDecoders.cpp
@@ -0,0 +1,127 @@
+/* -*- 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 "nsComponentManagerUtils.h"
+#include "nsCOMPtr.h"
+#include "nsIInputStream.h"
+#include "nsIRunnable.h"
+#include "nsIStringStream.h"
+#include "nsIThread.h"
+#include "mozilla/RefPtr.h"
+#include "nsString.h"
+#include "nsThreadUtils.h"
+
+#include "FuzzingInterface.h"
+
+using namespace mozilla;
+using namespace mozilla::gfx;
+using namespace mozilla::image;
+
+static std::string mimeType = "";
+
+// 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; }
+
+class DecodeToSurfaceRunnableFuzzing : public Runnable
+{
+public:
+  DecodeToSurfaceRunnableFuzzing(RefPtr<SourceSurface>& aSurface,
+                          nsIInputStream* aInputStream)
+    : mozilla::Runnable("DecodeToSurfaceRunnableFuzzing")
+    , mSurface(aSurface)
+    , mInputStream(aInputStream)
+  { }
+
+  NS_IMETHOD Run() override
+  {
+    Go();
+    return NS_OK;
+  }
+
+  void Go()
+  {
+    mSurface =
+      ImageOps::DecodeToSurface(mInputStream,
+                                nsDependentCString(mimeType.c_str()),
+                                imgIContainer::DECODE_FLAGS_DEFAULT);
+    if (!mSurface)
+      return;
+
+    if (mSurface->GetType() == SurfaceType::DATA) {
+      if (mSurface->GetFormat() == SurfaceFormat::B8G8R8X8 ||
+          mSurface->GetFormat() == SurfaceFormat::B8G8R8A8) {
+        DUMMY_IF(IntSize(1,1) == mSurface->GetSize());
+        DUMMY_IF(IsSolidColor(mSurface, BGRAColor::Green(), 1));
+      }
+    }
+  }
+
+private:
+  RefPtr<SourceSurface>& mSurface;
+  nsCOMPtr<nsIInputStream> mInputStream;
+};
+
+static int
+RunDecodeToSurfaceFuzzing(nsCOMPtr<nsIInputStream> inputStream)
+{
+  uint64_t len;
+  inputStream->Available(&len);
+  if (len <= 0) {
+      return 0;
+  }
+
+  nsCOMPtr<nsIThread> thread;
+  nsresult rv = NS_NewThread(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 main-thread-only code.
+  RefPtr<SourceSurface> surface;
+  nsCOMPtr<nsIRunnable> runnable =
+    new DecodeToSurfaceRunnableFuzzing(surface, inputStream);
+  thread->Dispatch(runnable, nsIThread::DISPATCH_SYNC);
+
+  thread->Shutdown();
+
+  // Explicitly release the SourceSurface on the main thread.
+  surface = nullptr;
+
+  return 0;
+}
+
+int FuzzingInitImage(int *argc, char ***argv) {
+    nsCOMPtr<imgITools> imgTools =
+      do_CreateInstance("@mozilla.org/image/tools;1");
+    if (imgTools == nullptr) {
+      std::cerr << "Initializing image tools failed" << std::endl;
+      return 1;
+    }
+
+    char* mimeTypePtr = getenv("MOZ_FUZZ_IMG_MIMETYPE");
+    if (!mimeTypePtr) {
+      std::cerr << "Must specify mime-type in MOZ_FUZZ_IMG_MIMETYPE environment variable." << std::endl;
+      return 1;
+    }
+
+    mimeType = std::string(mimeTypePtr);
+    int ret = strncmp(mimeType.c_str(), "image/", strlen("image/"));
+
+    if (ret) {
+      std::cerr << "MOZ_FUZZ_IMG_MIMETYPE should start with 'image/', e.g. 'image/gif'. Return: " << ret << std::endl;
+      return 1;
+    }
+    return 0;
+}
+
+MOZ_FUZZING_INTERFACE_STREAM(FuzzingInitImage, RunDecodeToSurfaceFuzzing, Image);
new file mode 100644
--- /dev/null
+++ b/image/test/fuzzing/moz.build
@@ -0,0 +1,24 @@
+# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# 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/.
+
+Library('FuzzingImage')
+
+SOURCES += [
+    'TestDecoders.cpp',
+]
+
+FINAL_LIBRARY = 'xul-gtest'
+
+include('/ipc/chromium/chromium-config.mozbuild')
+
+LOCAL_INCLUDES += [
+    '/dom/base',
+    '/gfx/2d',
+    '/image',
+    '/image/test/gtest',
+]
+
+LOCAL_INCLUDES += CONFIG['SKIA_INCLUDES']