Title: [200749] branches/safari-601.1.46-branch/Source/WebCore
Revision
200749
Author
matthew_han...@apple.com
Date
2016-05-12 02:11:54 -0700 (Thu, 12 May 2016)

Log Message

Merge r194290. rdar://problem/26228866

Modified Paths

Diff

Modified: branches/safari-601.1.46-branch/Source/WebCore/ChangeLog (200748 => 200749)


--- branches/safari-601.1.46-branch/Source/WebCore/ChangeLog	2016-05-12 09:11:50 UTC (rev 200748)
+++ branches/safari-601.1.46-branch/Source/WebCore/ChangeLog	2016-05-12 09:11:54 UTC (rev 200749)
@@ -1,5 +1,34 @@
 2016-05-12  Matthew Hanson  <matthew_han...@apple.com>
 
+        Merge r194290. rdar://problem/26228866
+
+    2015-12-18  Brent Fulgham  <bfulg...@apple.com>
+
+            Place an upper bound on canvas pixel count
+            https://bugs.webkit.org/show_bug.cgi?id=151825
+            <rdar://problem/23324916>
+
+            Reviewed by Simon Fraser (Relanded by Brent Fulgham)
+
+            Malformed _javascript_ can attempt to create lots of canvas contexts. Limit the amount of memory
+            we will use for this purpose to some percentage of system RAM.
+
+            * html/HTMLCanvasElement.cpp:
+            (WebCore::removeFromActivePixelMemory): Added helper function
+            (WebCore::HTMLCanvasElement::~HTMLCanvasElement): Call new 'releaseImageBufferAndContext' method
+            to ensure ImageBuffer and graphics context state are properly cleaned up.
+            (WebCore::maxActivePixels): Use one quarter of the system RAM, or 2 GB (whichever is more) as
+            an upper bound on active pixel memory.
+            (WebCore::HTMLCanvasElement::getContext): If we are attempting to create a context that will cause
+            us to exceed the allowed active pixel count, fail.
+            (WebCore::HTMLCanvasElement::releaseImageBufferAndContext): Added helper function
+            (WebCore::HTMLCanvasElement::setSurfaceSize): Use the new 'releaseImageBufferAndContext' method
+            to handle active pixel memory counts.
+            (WebCore::HTMLCanvasElement::createImageBuffer): Refuse to create a backing buffer if it will
+            exceed our available pixel memory.
+
+2016-05-12  Matthew Hanson  <matthew_han...@apple.com>
+
         Merge r190820. rdar://problem/26228881
 
     2015-10-09  Simon Fraser  <simon.fra...@apple.com>

Modified: branches/safari-601.1.46-branch/Source/WebCore/html/HTMLCanvasElement.cpp (200748 => 200749)


--- branches/safari-601.1.46-branch/Source/WebCore/html/HTMLCanvasElement.cpp	2016-05-12 09:11:50 UTC (rev 200748)
+++ branches/safari-601.1.46-branch/Source/WebCore/html/HTMLCanvasElement.cpp	2016-05-12 09:11:54 UTC (rev 200749)
@@ -47,6 +47,7 @@
 #include "ScriptController.h"
 #include "Settings.h"
 #include <math.h>
+#include <wtf/RAMSize.h>
 
 #include <runtime/JSCInlines.h>
 #include <runtime/JSLock.h>
@@ -75,6 +76,8 @@
 static const unsigned MaxCanvasArea = 16384 * 16384;
 #endif
 
+static size_t activePixelMemory = 0;
+
 HTMLCanvasElement::HTMLCanvasElement(const QualifiedName& tagName, Document& document)
     : HTMLElement(tagName, document)
     , m_size(DefaultWidth, DefaultHeight)
@@ -97,12 +100,25 @@
     return adoptRef(*new HTMLCanvasElement(tagName, document));
 }
 
+static void removeFromActivePixelMemory(size_t pixelsReleased)
+{
+    if (!pixelsReleased)
+        return;
+
+    if (pixelsReleased < activePixelMemory)
+        activePixelMemory -= pixelsReleased;
+    else
+        activePixelMemory = 0;
+}
+    
 HTMLCanvasElement::~HTMLCanvasElement()
 {
     for (auto it = m_observers.begin(), end = m_observers.end(); it != end; ++it)
         (*it)->canvasDestroyed(*this);
 
     m_context = nullptr; // Ensure this goes away before the ImageBuffer.
+
+    releaseImageBufferAndContext();
 }
 
 void HTMLCanvasElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
@@ -179,6 +195,16 @@
 }
 #endif
 
+static inline size_t maxActivePixelMemory()
+{
+    static size_t maxPixelMemory;
+    static std::once_flag onceFlag;
+    std::call_once(onceFlag, [] {
+        maxPixelMemory = std::max(ramSize() / 4, 2151 * MB);
+    });
+    return maxPixelMemory;
+}
+
 CanvasRenderingContext* HTMLCanvasElement::getContext(const String& type, CanvasContextAttributes* attrs)
 {
     // A Canvas can either be "2D" or "webgl" but never both. If you request a 2D canvas and the existing
@@ -198,6 +224,18 @@
             if (Settings* settings = document().settings())
                 usesDashbardCompatibilityMode = settings->usesDashboardBackwardCompatibilityMode();
 #endif
+
+            // Make sure we don't use more pixel memory than the system can support.
+            size_t requestedPixelMemory = 4 * width() * height();
+            if (activePixelMemory + requestedPixelMemory > maxActivePixelMemory()) {
+                StringBuilder stringBuilder;
+                stringBuilder.appendLiteral("Total canvas memory use exceeds the maximum limit (");
+                stringBuilder.appendNumber(maxActivePixelMemory() / 1024 / 1024);
+                stringBuilder.appendLiteral(" MB).");
+                document().addConsoleMessage(MessageSource::JS, MessageLevel::Warning, stringBuilder.toString());
+                return nullptr;
+            }
+
             m_context = std::make_unique<CanvasRenderingContext2D>(this, document().inQuirksMode(), usesDashbardCompatibilityMode);
 #if USE(IOSURFACE_CANVAS_BACKING_STORE) || ENABLE(ACCELERATED_2D_CANVAS)
             // Need to make sure a RenderLayer and compositing layer get created for the Canvas
@@ -426,12 +464,17 @@
     m_presentedImage = nullptr;
 }
 
+void HTMLCanvasElement::releaseImageBufferAndContext()
+{
+    m_contextStateSaver = nullptr;
+    setImageBuffer(nullptr);
+}
+    
 void HTMLCanvasElement::setSurfaceSize(const IntSize& size)
 {
     m_size = size;
     m_hasCreatedImageBuffer = false;
-    m_contextStateSaver = nullptr;
-    m_imageBuffer.reset();
+    releaseImageBufferAndContext();
     clearCopiedImage();
 }
 
@@ -571,13 +614,24 @@
         document().addConsoleMessage(MessageSource::JS, MessageLevel::Warning, stringBuilder.toString());
         return;
     }
+    
+    // Make sure we don't use more pixel memory than the system can support.
+    size_t requestedPixelMemory = 4 * width() * height();
+    if (activePixelMemory + requestedPixelMemory > maxActivePixelMemory()) {
+        StringBuilder stringBuilder;
+        stringBuilder.appendLiteral("Total canvas memory use exceeds the maximum limit (");
+        stringBuilder.appendNumber(maxActivePixelMemory() / 1024 / 1024);
+        stringBuilder.appendLiteral(" MB).");
+        document().addConsoleMessage(MessageSource::JS, MessageLevel::Warning, stringBuilder.toString());
+        return;
+    }
 
     IntSize bufferSize(deviceSize.width(), deviceSize.height());
     if (!bufferSize.width() || !bufferSize.height())
         return;
 
     RenderingMode renderingMode = shouldAccelerate(bufferSize) ? Accelerated : Unaccelerated;
-    m_imageBuffer = ImageBuffer::create(size(), 1, ColorSpaceDeviceRGB, renderingMode);
+    setImageBuffer(ImageBuffer::create(size(), 1, ColorSpaceDeviceRGB, renderingMode));
     if (!m_imageBuffer)
         return;
     m_imageBuffer->context()->setShadowsIgnoreTransforms(true);
@@ -597,6 +651,15 @@
 #endif
 }
 
+void HTMLCanvasElement::setImageBuffer(std::unique_ptr<ImageBuffer> buffer) const
+{
+    removeFromActivePixelMemory(memoryCost());
+
+    m_imageBuffer = WTF::move(buffer);
+
+    activePixelMemory += memoryCost();
+}
+
 GraphicsContext* HTMLCanvasElement::drawingContext() const
 {
     return buffer() ? m_imageBuffer->context() : nullptr;

Modified: branches/safari-601.1.46-branch/Source/WebCore/html/HTMLCanvasElement.h (200748 => 200749)


--- branches/safari-601.1.46-branch/Source/WebCore/html/HTMLCanvasElement.h	2016-05-12 09:11:50 UTC (rev 200748)
+++ branches/safari-601.1.46-branch/Source/WebCore/html/HTMLCanvasElement.h	2016-05-12 09:11:54 UTC (rev 200749)
@@ -152,6 +152,8 @@
     void clearImageBuffer() const;
 
     void setSurfaceSize(const IntSize&);
+    void setImageBuffer(std::unique_ptr<ImageBuffer>) const;
+    void releaseImageBufferAndContext();
 
     bool paintsIntoCanvasBuffer() const;
 
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to