Modified: branches/safari-601-branch/Source/WebCore/ChangeLog (200723 => 200724)
--- branches/safari-601-branch/Source/WebCore/ChangeLog 2016-05-12 01:31:28 UTC (rev 200723)
+++ branches/safari-601-branch/Source/WebCore/ChangeLog 2016-05-12 01:31:31 UTC (rev 200724)
@@ -1,5 +1,34 @@
2016-05-11 Matthew Hanson <matthew_han...@apple.com>
+ Merge r194290. rdar://problem/26053735
+
+ 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-11 Matthew Hanson <matthew_han...@apple.com>
+
Merge r200375. rdar://problem/26066673
2016-05-03 Pranjal Jumde <pju...@apple.com>
Modified: branches/safari-601-branch/Source/WebCore/html/HTMLCanvasElement.cpp (200723 => 200724)
--- branches/safari-601-branch/Source/WebCore/html/HTMLCanvasElement.cpp 2016-05-12 01:31:28 UTC (rev 200723)
+++ branches/safari-601-branch/Source/WebCore/html/HTMLCanvasElement.cpp 2016-05-12 01:31:31 UTC (rev 200724)
@@ -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,25 @@
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 +652,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-branch/Source/WebCore/html/HTMLCanvasElement.h (200723 => 200724)
--- branches/safari-601-branch/Source/WebCore/html/HTMLCanvasElement.h 2016-05-12 01:31:28 UTC (rev 200723)
+++ branches/safari-601-branch/Source/WebCore/html/HTMLCanvasElement.h 2016-05-12 01:31:31 UTC (rev 200724)
@@ -152,6 +152,8 @@
void clearImageBuffer() const;
void setSurfaceSize(const IntSize&);
+ void setImageBuffer(std::unique_ptr<ImageBuffer>) const;
+ void releaseImageBufferAndContext();
bool paintsIntoCanvasBuffer() const;