Reject createImageBitmap promise when the cropRect or resize is too big

At this moment, creating an ImageBitmap has several options such as flipY
and premultiplyAlpha = false. So in some cases, we would have to convert
the premultiplied input to unpremul format, and that involves allocating
new memory. To prevent any potential integer overflow or OOM situation,
this CL checks the size of the cropRect and the resizeWidth(resizeHeight),
if the width * height * bytesPerPixel is larger than size_t range, we reject
the promise. By doing the check at the beginning of each ImageBitmap constructor,
we can guarantee that the subsequent multiplication of
width * height * bytesPerPixel will not overflow.

This CL also correct other places where there could be
potential integer overflow. In particular, since we have checked at
the beginning of each ImageBitmap constructor, it should be safe
to use size_t for any computation of width * height in the code.

TBR=kbr@chromium.org, haraken@chromium.org
BUG=638615
CQ_INCLUDE_TRYBOTS=master.tryserver.chromium.win:win_optional_gpu_tests_rel;master.tryserver.chromium.mac:mac_optional_gpu_tests_rel

Review-Url: https://codereview.chromium.org/2249853008
Cr-Commit-Position: refs/heads/master@{#414687}
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-createImageBitmap-drawImage-video.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-createImageBitmap-drawImage-video.html
index b11baffc..16073ec 100644
--- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-createImageBitmap-drawImage-video.html
+++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-createImageBitmap-drawImage-video.html
@@ -77,7 +77,7 @@
         checkCrop(imageBitmaps.negativeCrop);
         checkEmpty(imageBitmaps.empty);
         checkEmpty(imageBitmaps.emptyTwo);
-        createImageBitmap(video, 0, 0, Math.pow(10, 6), Math.pow(10, 6)).then(function() {
+        createImageBitmap(video, 0, 0, 0x8000, 0x8000).then(function() {
             testFailed('Creating a huge ImageBitmap is resolved unexpectedly.');
             finishJSTest();
          }, function() {
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-createImageBitmap-drawImage.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-createImageBitmap-drawImage.html
index 982eefe..9a9ae564 100644
--- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-createImageBitmap-drawImage.html
+++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-createImageBitmap-drawImage.html
@@ -186,7 +186,7 @@
         checkCrop(imageBitmaps.negativeCrop);
         checkEmpty(imageBitmaps.empty);
         checkEmpty(imageBitmaps.emptyTwo);
-        createImageBitmap(element, 0, 0, Math.pow(10, 6), Math.pow(10, 6)).then(function() {
+        createImageBitmap(element, 0, 0, 0x8000, 0x8000).then(function() {
             testFailed('Creating a huge ImageBitmap is resolved unexpectedly.');
             finishJSTest();
         }, function() {
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-createImageBitmap-size-tooBig.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-createImageBitmap-size-tooBig.html
new file mode 100644
index 0000000..e29cc56
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-createImageBitmap-size-tooBig.html
@@ -0,0 +1,103 @@
+<!DOCTYPE HTML>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script>
+function testImageBitmap(source)
+{
+    return createImageBitmap(source, 0, 0, 0x8000, 0x8000, {imageOrientation: "flipY", premultiplyAlpha: "none"}).then(function() {
+        assert_true(false, "Promise should be rejected if the cropRect is too big.");
+    }, function() {
+        return createImageBitmap(source, 5, 5, 10, 10, {resizeWidth: 0x8000, resizeHeight: 0x8000}).then(function() {
+            assert_true(false, "Promise should be rejected if the resizeWidth or resizeHeight is too big.");
+        }, function() {
+        });
+    });
+}
+
+function initializeTestCanvas()
+{
+    var testCanvas = document.createElement("canvas");
+    testCanvas.width = 20;
+    testCanvas.height = 20;
+    var testCtx = testCanvas.getContext("2d");
+    testCtx.fillStyle = "rgb(255, 0, 0)";
+    testCtx.fillRect(0, 0, 10, 10);
+    testCtx.fillStyle = "rgb(0, 255, 0)";
+    testCtx.fillRect(10, 0, 10, 10);
+    testCtx.fillStyle = "rgb(0, 0, 255)";
+    testCtx.fillRect(0, 10, 10, 10);
+    testCtx.fillStyle = "rgb(0, 0, 0)";
+    testCtx.fillRect(10, 10, 10, 10);
+    return testCanvas;
+}
+
+function getBlobWithXhr(url)
+{
+    return new Promise((resolve, reject) => {
+        var xhr = new XMLHttpRequest();
+        xhr.open("GET", url);
+        xhr.responseType = 'blob';
+        xhr.send();
+        xhr.onload = function() {
+            resolve(xhr.response);
+        };
+    });
+}
+
+function loadImage(url)
+{
+    return new Promise((resolve, reject) => {
+        var image = new Image();
+        image.onload = function() {
+            resolve(image);
+        }
+        image.src = url;
+    });
+}
+
+function loadVideo(url)
+{
+    return new Promise((resolve, reject) => {
+        var video = document.createElement("video");
+        video.oncanplaythrough = function() {
+            resolve(video);
+        };
+        video.src = url;
+    });
+}
+
+// Blob
+promise_test(function() {
+    return getBlobWithXhr('resources/pattern.png').then(testImageBitmap);
+}, 'createImageBitmap from a Blob with a big cropRect.');
+
+// HTMLCanvasElement
+promise_test(function() {
+    var testCanvas = initializeTestCanvas();
+    return testImageBitmap(testCanvas);
+}, 'createImageBitmap from a HTMLCanvasElement with a big cropRect.');
+
+// HTMLImageElement
+promise_test(function() {
+    return loadImage('resources/pattern.png').then(testImageBitmap);
+}, 'createImageBitmap from a HTMLImageElement with a big cropRect.');
+
+// ImageBitmap
+promise_test(function() {
+    var testCanvas = initializeTestCanvas();
+    return createImageBitmap(testCanvas).then(testImageBitmap);
+}, 'createImageBitmap from an ImageBitmap with a big cropRect.');
+
+// ImageData
+promise_test(function() {
+    var canvas = initializeTestCanvas();
+    var ctx = canvas.getContext("2d");
+    var data = ctx.getImageData(0, 0, 20, 20);
+    return testImageBitmap(data);
+}, 'createImageBitmap from an ImageData with a big cropRect.');
+
+// HTMLVideoElement
+promise_test(function() {
+    return loadVideo('../../compositing/resources/video.ogv').then(testImageBitmap);
+}, 'createImageBitmap from a HTMLVideoElement with resize option.');
+</script>
diff --git a/third_party/WebKit/Source/bindings/core/v8/ScriptValueSerializer.cpp b/third_party/WebKit/Source/bindings/core/v8/ScriptValueSerializer.cpp
index cbfc21c..17f0a3f 100644
--- a/third_party/WebKit/Source/bindings/core/v8/ScriptValueSerializer.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/ScriptValueSerializer.cpp
@@ -1134,8 +1134,8 @@
         m_writer.writeTransferredImageBitmap(index);
     } else {
         greyObject(object);
-        std::unique_ptr<uint8_t[]> pixelData = imageBitmap->copyBitmapData(imageBitmap->isPremultiplied() ? PremultiplyAlpha : DontPremultiplyAlpha, N32ColorType);
-        m_writer.writeImageBitmap(imageBitmap->width(), imageBitmap->height(), static_cast<uint32_t>(imageBitmap->originClean()), static_cast<uint32_t>(imageBitmap->isPremultiplied()), pixelData.get(), imageBitmap->width() * imageBitmap->height() * 4);
+        RefPtr<Uint8Array> pixelData = imageBitmap->copyBitmapData(imageBitmap->isPremultiplied() ? PremultiplyAlpha : DontPremultiplyAlpha, N32ColorType);
+        m_writer.writeImageBitmap(imageBitmap->width(), imageBitmap->height(), static_cast<uint32_t>(imageBitmap->originClean()), static_cast<uint32_t>(imageBitmap->isPremultiplied()), pixelData->data(), imageBitmap->width() * imageBitmap->height() * 4);
     }
     return nullptr;
 }
diff --git a/third_party/WebKit/Source/core/frame/ImageBitmap.cpp b/third_party/WebKit/Source/core/frame/ImageBitmap.cpp
index 032bbacabde..86600c0 100644
--- a/third_party/WebKit/Source/core/frame/ImageBitmap.cpp
+++ b/third_party/WebKit/Source/core/frame/ImageBitmap.cpp
@@ -11,6 +11,7 @@
 #include "platform/image-decoders/ImageDecoder.h"
 #include "third_party/skia/include/core/SkCanvas.h"
 #include "third_party/skia/include/core/SkSurface.h"
+#include "wtf/CheckedNumeric.h"
 #include "wtf/PtrUtil.h"
 #include "wtf/RefPtr.h"
 #include <memory>
@@ -30,6 +31,9 @@
     unsigned resizeHeight = 0;
     IntRect cropRect;
     SkFilterQuality resizeQuality = kLow_SkFilterQuality;
+    // This value should be changed in the future when we support createImageBitmap with higher
+    // bit depth, in the parseOptions() function. For now, it is always 4.
+    int bytesPerPixel = 4;
 };
 
 // The following two functions are helpers used in cropImage
@@ -100,32 +104,58 @@
     return parsedOptions;
 }
 
+bool dstBufferSizeHasOverflow(ParsedOptions options)
+{
+    CheckedNumeric<size_t> totalBytes = options.cropRect.width();
+    totalBytes *= options.cropRect.height();
+    totalBytes *= options.bytesPerPixel;
+    if (!totalBytes.IsValid())
+        return true;
+
+    if (!options.shouldScaleInput)
+        return false;
+    totalBytes = options.resizeWidth;
+    totalBytes *= options.resizeHeight;
+    totalBytes *= options.bytesPerPixel;
+    if (!totalBytes.IsValid())
+        return true;
+
+    return false;
+}
+
 } // namespace
 
-static std::unique_ptr<uint8_t[]> copySkImageData(SkImage* input, const SkImageInfo& info)
+static PassRefPtr<Uint8Array> copySkImageData(SkImage* input, const SkImageInfo& info)
 {
-    std::unique_ptr<uint8_t[]> dstPixels = wrapArrayUnique(new uint8_t[input->width() * input->height() * info.bytesPerPixel()]);
-    input->readPixels(info, dstPixels.get(), input->width() * info.bytesPerPixel(), 0, 0);
+    // The function dstBufferSizeHasOverflow() is being called at the beginning of each
+    // ImageBitmap() constructor, which makes sure that doing width * height * bytesPerPixel
+    // will never overflow size_t.
+    size_t width = static_cast<size_t>(input->width());
+    RefPtr<ArrayBuffer> dstBuffer = ArrayBuffer::createOrNull(width * input->height(), info.bytesPerPixel());
+    if (!dstBuffer)
+        return nullptr;
+    RefPtr<Uint8Array> dstPixels = Uint8Array::create(dstBuffer, 0, dstBuffer->byteLength());
+    input->readPixels(info, dstPixels->data(), width * info.bytesPerPixel(), 0, 0);
     return dstPixels;
 }
 
-static PassRefPtr<SkImage> newSkImageFromRaster(const SkImageInfo& info, std::unique_ptr<uint8_t[]> imagePixels, int imageRowBytes)
+static PassRefPtr<SkImage> newSkImageFromRaster(const SkImageInfo& info, PassRefPtr<Uint8Array> imagePixels, size_t imageRowBytes)
 {
-    return fromSkSp(SkImage::MakeFromRaster(SkPixmap(info, imagePixels.release(), imageRowBytes),
-        [](const void* pixels, void*)
+    SkPixmap pixmap(info, imagePixels->data(), imageRowBytes);
+    return fromSkSp(SkImage::MakeFromRaster(pixmap, [](const void*, void* pixels)
         {
-            delete[] static_cast<const uint8_t*>(pixels);
-        }, nullptr));
+            static_cast<Uint8Array*>(pixels)->deref();
+        }, imagePixels.leakRef()));
 }
 
-static void swizzleImageData(unsigned char* srcAddr, int height, int bytesPerRow, bool flipY)
+static void swizzleImageData(unsigned char* srcAddr, size_t height, size_t bytesPerRow, bool flipY)
 {
     if (flipY) {
-        for (int i = 0; i < height / 2; i++) {
-            int topRowStartPosition = i * bytesPerRow;
-            int bottomRowStartPosition = (height - 1 - i) * bytesPerRow;
+        for (size_t i = 0; i < height / 2; i++) {
+            size_t topRowStartPosition = i * bytesPerRow;
+            size_t bottomRowStartPosition = (height - 1 - i) * bytesPerRow;
             if (kN32_SkColorType == kBGRA_8888_SkColorType) { // needs to swizzle
-                for (int j = 0; j < bytesPerRow; j += 4) {
+                for (size_t j = 0; j < bytesPerRow; j += 4) {
                     std::swap(srcAddr[topRowStartPosition + j], srcAddr[bottomRowStartPosition + j + 2]);
                     std::swap(srcAddr[topRowStartPosition + j + 1], srcAddr[bottomRowStartPosition + j + 1]);
                     std::swap(srcAddr[topRowStartPosition + j + 2], srcAddr[bottomRowStartPosition + j]);
@@ -137,23 +167,25 @@
         }
     } else {
         if (kN32_SkColorType == kBGRA_8888_SkColorType) // needs to swizzle
-            for (int i = 0; i < height * bytesPerRow; i += 4)
+            for (size_t i = 0; i < height * bytesPerRow; i += 4)
                 std::swap(srcAddr[i], srcAddr[i + 2]);
     }
 }
 
 static PassRefPtr<SkImage> flipSkImageVertically(SkImage* input, AlphaDisposition alphaOp)
 {
-    int width = input->width();
-    int height = input->height();
-    SkImageInfo info = SkImageInfo::MakeN32(width, height, (alphaOp == PremultiplyAlpha) ? kPremul_SkAlphaType : kUnpremul_SkAlphaType);
-    int imageRowBytes = width * info.bytesPerPixel();
-    std::unique_ptr<uint8_t[]> imagePixels = copySkImageData(input, info);
-    for (int i = 0; i < height / 2; i++) {
-        int topFirstElement = i * imageRowBytes;
-        int topLastElement = (i + 1) * imageRowBytes;
-        int bottomFirstElement = (height - 1 - i) * imageRowBytes;
-        std::swap_ranges(imagePixels.get() + topFirstElement, imagePixels.get() + topLastElement, imagePixels.get() + bottomFirstElement);
+    size_t width = static_cast<size_t>(input->width());
+    size_t height = static_cast<size_t>(input->height());
+    SkImageInfo info = SkImageInfo::MakeN32(input->width(), input->height(), (alphaOp == PremultiplyAlpha) ? kPremul_SkAlphaType : kUnpremul_SkAlphaType);
+    size_t imageRowBytes = width * info.bytesPerPixel();
+    RefPtr<Uint8Array> imagePixels = copySkImageData(input, info);
+    if (!imagePixels)
+        return nullptr;
+    for (size_t i = 0; i < height / 2; i++) {
+        size_t topFirstElement = i * imageRowBytes;
+        size_t topLastElement = (i + 1) * imageRowBytes;
+        size_t bottomFirstElement = (height - 1 - i) * imageRowBytes;
+        std::swap_ranges(imagePixels->data() + topFirstElement, imagePixels->data() + topLastElement, imagePixels->data() + bottomFirstElement);
     }
     return newSkImageFromRaster(info, std::move(imagePixels), imageRowBytes);
 }
@@ -161,15 +193,19 @@
 static PassRefPtr<SkImage> premulSkImageToUnPremul(SkImage* input)
 {
     SkImageInfo info = SkImageInfo::Make(input->width(), input->height(), kN32_SkColorType, kUnpremul_SkAlphaType);
-    std::unique_ptr<uint8_t[]> dstPixels = copySkImageData(input, info);
-    return newSkImageFromRaster(info, std::move(dstPixels), input->width() * info.bytesPerPixel());
+    RefPtr<Uint8Array> dstPixels = copySkImageData(input, info);
+    if (!dstPixels)
+        return nullptr;
+    return newSkImageFromRaster(info, std::move(dstPixels), static_cast<size_t>(input->width()) * info.bytesPerPixel());
 }
 
 static PassRefPtr<SkImage> unPremulSkImageToPremul(SkImage* input)
 {
     SkImageInfo info = SkImageInfo::Make(input->width(), input->height(), kN32_SkColorType, kPremul_SkAlphaType);
-    std::unique_ptr<uint8_t[]> dstPixels = copySkImageData(input, info);
-    return newSkImageFromRaster(info, std::move(dstPixels), input->width() * info.bytesPerPixel());
+    RefPtr<Uint8Array> dstPixels = copySkImageData(input, info);
+    if (!dstPixels)
+        return nullptr;
+    return newSkImageFromRaster(info, std::move(dstPixels), static_cast<size_t>(input->width()) * info.bytesPerPixel());
 }
 
 PassRefPtr<SkImage> ImageBitmap::getSkImageFromDecoder(std::unique_ptr<ImageDecoder> decoder)
@@ -210,7 +246,6 @@
 static PassRefPtr<StaticBitmapImage> cropImage(Image* image, const ParsedOptions& parsedOptions, AlphaDisposition imageFormat = PremultiplyAlpha, ImageDecoder::GammaAndColorProfileOption colorSpaceOp = ImageDecoder::GammaAndColorProfileApplied)
 {
     ASSERT(image);
-
     IntRect imgRect(IntPoint(), IntSize(image->width(), image->height()));
     const IntRect srcRect = intersection(imgRect, parsedOptions.cropRect);
 
@@ -218,8 +253,11 @@
     // We immediately return a transparent black image with cropRect.size()
     if (srcRect.isEmpty() && !parsedOptions.premultiplyAlpha) {
         SkImageInfo info = SkImageInfo::Make(parsedOptions.resizeWidth, parsedOptions.resizeHeight, kN32_SkColorType, kUnpremul_SkAlphaType);
-        std::unique_ptr<uint8_t[]> dstPixels = wrapArrayUnique(new uint8_t[info.width() * info.height() * info.bytesPerPixel()]());
-        return StaticBitmapImage::create(newSkImageFromRaster(info, std::move(dstPixels), info.width() * info.bytesPerPixel()));
+        RefPtr<ArrayBuffer> dstBuffer = ArrayBuffer::createOrNull(static_cast<size_t>(info.width()) * info.height(), info.bytesPerPixel());
+        if (!dstBuffer)
+            return nullptr;
+        RefPtr<Uint8Array> dstPixels = Uint8Array::create(dstBuffer, 0, dstBuffer->byteLength());
+        return StaticBitmapImage::create(newSkImageFromRaster(info, std::move(dstPixels), static_cast<size_t>(info.width()) * info.bytesPerPixel()));
     }
 
     RefPtr<SkImage> skiaImage = image->imageForCurrentFrame();
@@ -276,7 +314,7 @@
     skiaImage = fromSkSp(surface->makeImageSnapshot());
 
     if (parsedOptions.premultiplyAlpha) {
-        if (imageFormat == PremultiplyAlpha)
+        if (imageFormat == DontPremultiplyAlpha)
             return StaticBitmapImage::create(unPremulSkImageToPremul(skiaImage.get()));
         return StaticBitmapImage::create(skiaImage.release());
     }
@@ -287,6 +325,8 @@
 {
     RefPtr<Image> input = image->cachedImage()->getImage();
     ParsedOptions parsedOptions = parseOptions(options, cropRect, image->bitmapSourceSize());
+    if (dstBufferSizeHasOverflow(parsedOptions))
+        return;
 
     if (options.colorSpaceConversion() == "none")
         m_image = cropImage(input.get(), parsedOptions, PremultiplyAlpha, ImageDecoder::GammaAndColorProfileIgnored);
@@ -303,6 +343,8 @@
         surface->getCanvas()->drawImage(skImage.get(), 0, 0);
         m_image = StaticBitmapImage::create(fromSkSp(surface->makeImageSnapshot()));
     }
+    if (!m_image)
+        return;
     m_image->setOriginClean(!image->wouldTaintOrigin(document->getSecurityOrigin()));
     m_image->setPremultiplied(parsedOptions.premultiplyAlpha);
 }
@@ -313,6 +355,8 @@
     if (video->webMediaPlayer())
         playerSize = video->webMediaPlayer()->naturalSize();
     ParsedOptions parsedOptions = parseOptions(options, cropRect, video->bitmapSourceSize());
+    if (dstBufferSizeHasOverflow(parsedOptions))
+        return;
 
     IntRect videoRect = IntRect(IntPoint(), playerSize);
     IntRect srcRect = intersection(parsedOptions.cropRect, videoRect);
@@ -339,6 +383,8 @@
     RefPtr<SkImage> skiaImage = buffer->newSkImageSnapshot(PreferNoAcceleration, SnapshotReasonUnknown);
     if (!parsedOptions.premultiplyAlpha)
         skiaImage = premulSkImageToUnPremul(skiaImage.get());
+    if (!skiaImage)
+        return;
     m_image = StaticBitmapImage::create(skiaImage.release());
     m_image->setOriginClean(!video->wouldTaintOrigin(document->getSecurityOrigin()));
     m_image->setPremultiplied(parsedOptions.premultiplyAlpha);
@@ -349,6 +395,8 @@
     ASSERT(canvas->isPaintable());
     RefPtr<Image> input = canvas->copiedImage(BackBuffer, PreferAcceleration);
     ParsedOptions parsedOptions = parseOptions(options, cropRect, canvas->bitmapSourceSize());
+    if (dstBufferSizeHasOverflow(parsedOptions))
+        return;
 
     bool isPremultiplyAlphaReverted = false;
     if (!parsedOptions.premultiplyAlpha) {
@@ -362,6 +410,8 @@
         parsedOptions.premultiplyAlpha = false;
         m_image = StaticBitmapImage::create(premulSkImageToUnPremul(m_image->imageForCurrentFrame().get()));
     }
+    if (!m_image)
+        return;
     m_image->setOriginClean(canvas->originClean());
     m_image->setPremultiplied(parsedOptions.premultiplyAlpha);
 }
@@ -370,6 +420,8 @@
 {
     SkImageInfo info = SkImageInfo::MakeN32(width, height, isImageBitmapPremultiplied ? kPremul_SkAlphaType : kUnpremul_SkAlphaType);
     m_image = StaticBitmapImage::create(fromSkSp(SkImage::MakeRasterCopy(SkPixmap(info, data.get(), info.bytesPerPixel() * width))));
+    if (!m_image)
+        return;
     m_image->setPremultiplied(isImageBitmapPremultiplied);
     m_image->setOriginClean(isImageBitmapOriginClean);
 }
@@ -377,13 +429,16 @@
 static PassRefPtr<SkImage> scaleSkImage(PassRefPtr<SkImage> skImage, unsigned resizeWidth, unsigned resizeHeight, SkFilterQuality resizeQuality)
 {
     SkImageInfo resizedInfo = SkImageInfo::Make(resizeWidth, resizeHeight, kN32_SkColorType, kUnpremul_SkAlphaType);
-    std::unique_ptr<uint8_t[]> resizedPixels = wrapArrayUnique(new uint8_t[resizeWidth * resizeHeight * resizedInfo.bytesPerPixel()]);
-    SkPixmap pixmap(resizedInfo, resizedPixels.release(), resizeWidth * resizedInfo.bytesPerPixel());
+    RefPtr<ArrayBuffer> dstBuffer = ArrayBuffer::createOrNull(resizeWidth * resizeHeight, resizedInfo.bytesPerPixel());
+    if (!dstBuffer)
+        return nullptr;
+    RefPtr<Uint8Array> resizedPixels = Uint8Array::create(dstBuffer, 0, dstBuffer->byteLength());
+    SkPixmap pixmap(resizedInfo, resizedPixels->data(), static_cast<size_t>(resizeWidth) * resizedInfo.bytesPerPixel());
     skImage->scalePixels(pixmap, resizeQuality);
-    return fromSkSp(SkImage::MakeFromRaster(pixmap, [](const void* pixels, void*)
+    return fromSkSp(SkImage::MakeFromRaster(pixmap, [](const void*, void* pixels)
         {
-            delete[] static_cast<const uint8_t*>(pixels);
-        }, nullptr));
+            static_cast<Uint8Array*>(pixels)->deref();
+        }, resizedPixels.release().leakRef()));
 }
 
 ImageBitmap::ImageBitmap(ImageData* data, Optional<IntRect> cropRect, const ImageBitmapOptions& options)
@@ -391,64 +446,72 @@
     // TODO(xidachen): implement the resize option
     IntRect dataSrcRect = IntRect(IntPoint(), data->size());
     ParsedOptions parsedOptions = parseOptions(options, cropRect, data->bitmapSourceSize());
+    if (dstBufferSizeHasOverflow(parsedOptions))
+        return;
     IntRect srcRect = cropRect ? intersection(parsedOptions.cropRect, dataSrcRect) : dataSrcRect;
 
     // treat non-premultiplyAlpha as a special case
     if (!parsedOptions.premultiplyAlpha) {
         unsigned char* srcAddr = data->data()->data();
-        int srcHeight = data->size().height();
-        int dstHeight = parsedOptions.cropRect.height();
 
         // Using kN32 type, swizzle input if necessary.
-        SkImageInfo info = SkImageInfo::Make(parsedOptions.cropRect.width(), dstHeight, kN32_SkColorType, kUnpremul_SkAlphaType);
-        int srcPixelBytesPerRow = info.bytesPerPixel() * data->size().width();
-        int dstPixelBytesPerRow = info.bytesPerPixel() * parsedOptions.cropRect.width();
+        SkImageInfo info = SkImageInfo::Make(parsedOptions.cropRect.width(), parsedOptions.cropRect.height(), kN32_SkColorType, kUnpremul_SkAlphaType);
+        size_t bytesPerPixel = static_cast<size_t>(info.bytesPerPixel());
+        size_t srcPixelBytesPerRow = bytesPerPixel * data->size().width();
+        size_t dstPixelBytesPerRow = bytesPerPixel * parsedOptions.cropRect.width();
         RefPtr<SkImage> skImage;
         if (parsedOptions.cropRect == IntRect(IntPoint(), data->size())) {
-            swizzleImageData(srcAddr, srcHeight, srcPixelBytesPerRow, parsedOptions.flipY);
+            swizzleImageData(srcAddr, data->size().height(), srcPixelBytesPerRow, parsedOptions.flipY);
             skImage = fromSkSp(SkImage::MakeRasterCopy(SkPixmap(info, srcAddr, dstPixelBytesPerRow)));
             // restore the original ImageData
-            swizzleImageData(srcAddr, srcHeight, srcPixelBytesPerRow, parsedOptions.flipY);
+            swizzleImageData(srcAddr, data->size().height(), srcPixelBytesPerRow, parsedOptions.flipY);
         } else {
-            std::unique_ptr<uint8_t[]> copiedDataBuffer = wrapArrayUnique(new uint8_t[dstHeight * dstPixelBytesPerRow]());
+            RefPtr<ArrayBuffer> dstBuffer = ArrayBuffer::createOrNull(static_cast<size_t>(parsedOptions.cropRect.height()) * parsedOptions.cropRect.width(), bytesPerPixel);
+            if (!dstBuffer)
+                return;
+            RefPtr<Uint8Array> copiedDataBuffer = Uint8Array::create(dstBuffer, 0, dstBuffer->byteLength());
             if (!srcRect.isEmpty()) {
                 IntPoint srcPoint = IntPoint((parsedOptions.cropRect.x() > 0) ? parsedOptions.cropRect.x() : 0, (parsedOptions.cropRect.y() > 0) ? parsedOptions.cropRect.y() : 0);
                 IntPoint dstPoint = IntPoint((parsedOptions.cropRect.x() >= 0) ? 0 : -parsedOptions.cropRect.x(), (parsedOptions.cropRect.y() >= 0) ? 0 : -parsedOptions.cropRect.y());
-                int copyHeight = srcHeight - srcPoint.y();
+                int copyHeight = data->size().height() - srcPoint.y();
                 if (parsedOptions.cropRect.height() < copyHeight)
                     copyHeight = parsedOptions.cropRect.height();
                 int copyWidth = data->size().width() - srcPoint.x();
                 if (parsedOptions.cropRect.width() < copyWidth)
                     copyWidth = parsedOptions.cropRect.width();
                 for (int i = 0; i < copyHeight; i++) {
-                    int srcStartCopyPosition = (i + srcPoint.y()) * srcPixelBytesPerRow + srcPoint.x() * info.bytesPerPixel();
-                    int srcEndCopyPosition = srcStartCopyPosition + copyWidth * info.bytesPerPixel();
-                    int dstStartCopyPosition;
+                    size_t srcStartCopyPosition = (i + srcPoint.y()) * srcPixelBytesPerRow + srcPoint.x() * bytesPerPixel;
+                    size_t srcEndCopyPosition = srcStartCopyPosition + copyWidth * bytesPerPixel;
+                    size_t dstStartCopyPosition;
                     if (parsedOptions.flipY)
-                        dstStartCopyPosition = (dstHeight -1 - dstPoint.y() - i) * dstPixelBytesPerRow + dstPoint.x() * info.bytesPerPixel();
+                        dstStartCopyPosition = (parsedOptions.cropRect.height() -1 - dstPoint.y() - i) * dstPixelBytesPerRow + dstPoint.x() * bytesPerPixel;
                     else
-                        dstStartCopyPosition = (dstPoint.y() + i) * dstPixelBytesPerRow + dstPoint.x() * info.bytesPerPixel();
-                    for (int j = 0; j < srcEndCopyPosition - srcStartCopyPosition; j++) {
+                        dstStartCopyPosition = (dstPoint.y() + i) * dstPixelBytesPerRow + dstPoint.x() * bytesPerPixel;
+                    for (size_t j = 0; j < srcEndCopyPosition - srcStartCopyPosition; j++) {
                         // swizzle when necessary
                         if (kN32_SkColorType == kBGRA_8888_SkColorType) {
                             if (j % 4 == 0)
-                                copiedDataBuffer[dstStartCopyPosition + j] = srcAddr[srcStartCopyPosition + j + 2];
+                                copiedDataBuffer->data()[dstStartCopyPosition + j] = srcAddr[srcStartCopyPosition + j + 2];
                             else if (j % 4 == 2)
-                                copiedDataBuffer[dstStartCopyPosition + j] = srcAddr[srcStartCopyPosition + j - 2];
+                                copiedDataBuffer->data()[dstStartCopyPosition + j] = srcAddr[srcStartCopyPosition + j - 2];
                             else
-                                copiedDataBuffer[dstStartCopyPosition + j] = srcAddr[srcStartCopyPosition + j];
+                                copiedDataBuffer->data()[dstStartCopyPosition + j] = srcAddr[srcStartCopyPosition + j];
                         } else {
-                            copiedDataBuffer[dstStartCopyPosition + j] = srcAddr[srcStartCopyPosition + j];
+                            copiedDataBuffer->data()[dstStartCopyPosition + j] = srcAddr[srcStartCopyPosition + j];
                         }
                     }
                 }
             }
             skImage = newSkImageFromRaster(info, std::move(copiedDataBuffer), dstPixelBytesPerRow);
         }
+        if (!skImage)
+            return;
         if (parsedOptions.shouldScaleInput)
             m_image = StaticBitmapImage::create(scaleSkImage(skImage, parsedOptions.resizeWidth, parsedOptions.resizeHeight, parsedOptions.resizeQuality));
         else
             m_image = StaticBitmapImage::create(skImage);
+        if (!m_image)
+            return;
         m_image->setPremultiplied(parsedOptions.premultiplyAlpha);
         return;
     }
@@ -471,6 +534,8 @@
     RefPtr<SkImage> skImage = buffer->newSkImageSnapshot(PreferNoAcceleration, SnapshotReasonUnknown);
     if (parsedOptions.flipY)
         skImage = flipSkImageVertically(skImage.get(), PremultiplyAlpha);
+    if (!skImage)
+        return;
     if (parsedOptions.shouldScaleInput) {
         sk_sp<SkSurface> surface = SkSurface::MakeRasterN32Premul(parsedOptions.resizeWidth, parsedOptions.resizeHeight);
         if (!surface)
@@ -490,6 +555,8 @@
     if (!input)
         return;
     ParsedOptions parsedOptions = parseOptions(options, cropRect, input->size());
+    if (dstBufferSizeHasOverflow(parsedOptions))
+        return;
 
     m_image = cropImage(input.get(), parsedOptions, bitmap->isPremultiplied() ? PremultiplyAlpha : DontPremultiplyAlpha);
     if (!m_image)
@@ -503,10 +570,13 @@
     bool originClean = image->originClean();
     RefPtr<Image> input = image;
     ParsedOptions parsedOptions = parseOptions(options, cropRect, input->size());
+    if (dstBufferSizeHasOverflow(parsedOptions))
+        return;
 
-    m_image = cropImage(input.get(), parsedOptions, DontPremultiplyAlpha);
+    m_image = cropImage(input.get(), parsedOptions);
     if (!m_image)
         return;
+
     m_image->setOriginClean(originClean);
     m_image->setPremultiplied(parsedOptions.premultiplyAlpha);
 }
@@ -581,11 +651,11 @@
     return ImageBitmap::create(StaticBitmapImage::create(fromSkSp(image)));
 }
 
-std::unique_ptr<uint8_t[]> ImageBitmap::copyBitmapData(AlphaDisposition alphaOp, DataColorFormat format)
+PassRefPtr<Uint8Array> ImageBitmap::copyBitmapData(AlphaDisposition alphaOp, DataColorFormat format)
 {
     SkImageInfo info = SkImageInfo::Make(width(), height(), (format == RGBAColorType) ? kRGBA_8888_SkColorType : kN32_SkColorType, (alphaOp == PremultiplyAlpha) ? kPremul_SkAlphaType : kUnpremul_SkAlphaType);
-    std::unique_ptr<uint8_t[]> dstPixels = copySkImageData(m_image->imageForCurrentFrame().get(), info);
-    return dstPixels;
+    RefPtr<Uint8Array> dstPixels = copySkImageData(m_image->imageForCurrentFrame().get(), info);
+    return dstPixels.release();
 }
 
 unsigned long ImageBitmap::width() const
diff --git a/third_party/WebKit/Source/core/frame/ImageBitmap.h b/third_party/WebKit/Source/core/frame/ImageBitmap.h
index 001062d..b6f2590 100644
--- a/third_party/WebKit/Source/core/frame/ImageBitmap.h
+++ b/third_party/WebKit/Source/core/frame/ImageBitmap.h
@@ -57,7 +57,7 @@
     static ImageBitmap* take(ScriptPromiseResolver*, sk_sp<SkImage>);
 
     StaticBitmapImage* bitmapImage() const { return (m_image) ? m_image.get() : nullptr; }
-    std::unique_ptr<uint8_t[]> copyBitmapData(AlphaDisposition alphaOp = DontPremultiplyAlpha, DataColorFormat format = RGBAColorType);
+    PassRefPtr<Uint8Array> copyBitmapData(AlphaDisposition = DontPremultiplyAlpha, DataColorFormat = RGBAColorType);
     unsigned long width() const;
     unsigned long height() const;
     IntSize size() const;
diff --git a/third_party/WebKit/Source/core/imagebitmap/ImageBitmapFactories.cpp b/third_party/WebKit/Source/core/imagebitmap/ImageBitmapFactories.cpp
index 06bb8d81..980a5ed 100644
--- a/third_party/WebKit/Source/core/imagebitmap/ImageBitmapFactories.cpp
+++ b/third_party/WebKit/Source/core/imagebitmap/ImageBitmapFactories.cpp
@@ -250,7 +250,6 @@
 
     RefPtr<StaticBitmapImage> image = StaticBitmapImage::create(frame);
     image->setOriginClean(true);
-
     ImageBitmap* imageBitmap = ImageBitmap::create(image, m_cropRect, m_options);
     if (imageBitmap && imageBitmap->bitmapImage()) {
         m_resolver->resolve(imageBitmap);
diff --git a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp
index f7c810a..597217d 100644
--- a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp
+++ b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp
@@ -4525,8 +4525,8 @@
     }
     RefPtr<SkImage> skImage = bitmap->bitmapImage()->imageForCurrentFrame();
     SkPixmap pixmap;
-    std::unique_ptr<uint8_t[]> pixelData;
     uint8_t* pixelDataPtr = nullptr;
+    RefPtr<Uint8Array> pixelData;
     // In the case where an ImageBitmap is not texture backed, peekPixels() always succeed.
     // However, when it is texture backed and !canUseTexImageByGPU, we do a GPU read back.
     bool peekSucceed = skImage->peekPixels(&pixmap);
@@ -4534,7 +4534,7 @@
         pixelDataPtr = static_cast<uint8_t*>(pixmap.writable_addr());
     } else {
         pixelData = bitmap->copyBitmapData(bitmap->isPremultiplied() ? PremultiplyAlpha : DontPremultiplyAlpha);
-        pixelDataPtr = pixelData.get();
+        pixelDataPtr = pixelData->data();
     }
     Vector<uint8_t> data;
     bool needConversion = true;