Changeset 193500 in webkit


Ignore:
Timestamp:
Dec 4, 2015 5:45:33 PM (8 years ago)
Author:
Brent Fulgham
Message:

Place an upper bound on canvas pixel count
https://bugs.webkit.org/show_bug.cgi?id=151825
<rdar://problem/23324916>

Reviewed by Simon Fraser.

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 1 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.

Location:
trunk/Source/WebCore
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r193494 r193500  
     12015-12-04  Brent Fulgham  <bfulgham@apple.com>
     2
     3        Place an upper bound on canvas pixel count
     4        https://bugs.webkit.org/show_bug.cgi?id=151825
     5        <rdar://problem/23324916>
     6
     7        Reviewed by Simon Fraser.
     8
     9        Malformed JavaScript can attempt to create lots of canvas contexts. Limit the amount of memory
     10        we will use for this purpose to some percentage of system RAM.
     11
     12        * html/HTMLCanvasElement.cpp:
     13        (WebCore::removeFromActivePixelMemory): Added helper function
     14        (WebCore::HTMLCanvasElement::~HTMLCanvasElement): Call new 'releaseImageBufferAndContext' method
     15        to ensure ImageBuffer and graphics context state are properly cleaned up.
     16        (WebCore::maxActivePixels): Use one quarter of the system RAM, or 1 GB (whichever is more) as
     17        an upper bound on active pixel memory.
     18        (WebCore::HTMLCanvasElement::getContext): If we are attempting to create a context that will cause
     19        us to exceed the allowed active pixel count, fail.
     20        (WebCore::HTMLCanvasElement::releaseImageBufferAndContext): Added helper function
     21        (WebCore::HTMLCanvasElement::setSurfaceSize): Use the new 'releaseImageBufferAndContext' method
     22        to handle active pixel memory counts.
     23        (WebCore::HTMLCanvasElement::createImageBuffer): Refuse to create a backing buffer if it will
     24        exceed our available pixel memory.
     25
    1262015-12-04  Brady Eidson  <beidson@apple.com>
    227
  • trunk/Source/WebCore/html/HTMLCanvasElement.cpp

    r192140 r193500  
    4848#include "Settings.h"
    4949#include <math.h>
     50#include <wtf/RAMSize.h>
    5051
    5152#include <runtime/JSCInlines.h>
     
    7677#endif
    7778
     79static size_t activePixelMemory = 0;
     80
    7881HTMLCanvasElement::HTMLCanvasElement(const QualifiedName& tagName, Document& document)
    7982    : HTMLElement(tagName, document)
     
    98101}
    99102
     103static void removeFromActivePixelMemory(size_t pixelsReleased)
     104{
     105    if (!pixelsReleased)
     106        return;
     107
     108    if (pixelsReleased < activePixelMemory)
     109        activePixelMemory -= pixelsReleased;
     110    else
     111        activePixelMemory = 0;
     112}
     113   
    100114HTMLCanvasElement::~HTMLCanvasElement()
    101115{
     
    104118
    105119    m_context = nullptr; // Ensure this goes away before the ImageBuffer.
     120
     121    releaseImageBufferAndContext();
    106122}
    107123
     
    179195}
    180196#endif
     197
     198static inline size_t maxActivePixelMemory()
     199{
     200    static size_t maxPixelMemory;
     201    static std::once_flag onceFlag;
     202    std::call_once(onceFlag, [] {
     203        maxPixelMemory = std::max(ramSize() / 4, 1024 * MB);
     204    });
     205    return maxPixelMemory;
     206}
    181207
    182208CanvasRenderingContext* HTMLCanvasElement::getContext(const String& type, CanvasContextAttributes* attrs)
     
    199225                usesDashbardCompatibilityMode = settings->usesDashboardBackwardCompatibilityMode();
    200226#endif
     227            size_t requestedPixelMemory = 4 * width() * height();
     228            if (activePixelMemory + requestedPixelMemory > maxActivePixelMemory())
     229                return nullptr;
     230
    201231            m_context = std::make_unique<CanvasRenderingContext2D>(this, document().inQuirksMode(), usesDashbardCompatibilityMode);
    202232#if USE(IOSURFACE_CANVAS_BACKING_STORE) || ENABLE(ACCELERATED_2D_CANVAS)
     
    427457}
    428458
     459void HTMLCanvasElement::releaseImageBufferAndContext()
     460{
     461    m_contextStateSaver = nullptr;
     462    setImageBuffer(nullptr);
     463}
     464   
    429465void HTMLCanvasElement::setSurfaceSize(const IntSize& size)
    430466{
    431467    m_size = size;
    432468    m_hasCreatedImageBuffer = false;
    433     m_contextStateSaver = nullptr;
    434     m_imageBuffer.reset();
     469    releaseImageBufferAndContext();
    435470    clearCopiedImage();
    436471}
     
    572607        return;
    573608    }
     609   
     610    // Make sure we don't use more pixel memory than the system can support.
     611    size_t requestedPixelMemory = 4 * width() * height();
     612    if (activePixelMemory + requestedPixelMemory > maxActivePixelMemory()) {
     613        StringBuilder stringBuilder;
     614        stringBuilder.appendLiteral("Total canvas memory use exceeds the maximum limit (");
     615        stringBuilder.appendNumber(maxActivePixelMemory() / 1024 / 1024);
     616        stringBuilder.appendLiteral(" MB).");
     617        document().addConsoleMessage(MessageSource::JS, MessageLevel::Warning, stringBuilder.toString());
     618        return;
     619    }
    574620
    575621    IntSize bufferSize(deviceSize.width(), deviceSize.height());
     
    578624
    579625    RenderingMode renderingMode = shouldAccelerate(bufferSize) ? Accelerated : Unaccelerated;
    580     m_imageBuffer = ImageBuffer::create(size(), renderingMode);
     626
     627    setImageBuffer(ImageBuffer::create(size(), renderingMode));
    581628    if (!m_imageBuffer)
    582629        return;
     
    596643        const_cast<HTMLCanvasElement*>(this)->setNeedsStyleRecalc(SyntheticStyleChange);
    597644#endif
     645}
     646
     647void HTMLCanvasElement::setImageBuffer(std::unique_ptr<ImageBuffer> buffer) const
     648{
     649    removeFromActivePixelMemory(memoryCost());
     650
     651    m_imageBuffer = WTF::move(buffer);
     652
     653    activePixelMemory += memoryCost();
    598654}
    599655
  • trunk/Source/WebCore/html/HTMLCanvasElement.h

    r189144 r193500  
    153153
    154154    void setSurfaceSize(const IntSize&);
     155    void setImageBuffer(std::unique_ptr<ImageBuffer>) const;
     156    void releaseImageBufferAndContext();
    155157
    156158    bool paintsIntoCanvasBuffer() const;
Note: See TracChangeset for help on using the changeset viewer.