Commit 1b60d8d2 by Geoff Lang Committed by Commit Bot

Add artificial limits to the total memory allocated by the NULL backend.

Fuzzer tests were capable of allocating very large chunks of memory by calling glBufferData with a null pointer. This sets a limit before the NULL backend starts returning out of memory GL errors. BUG=602737 Change-Id: Ic53ebcf999f951b96c1df82e4db57e949d03c908 Reviewed-on: https://chromium-review.googlesource.com/441184 Commit-Queue: Geoff Lang <geofflang@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent 1e031b27
...@@ -12,16 +12,21 @@ ...@@ -12,16 +12,21 @@
#include "common/debug.h" #include "common/debug.h"
#include "common/utilities.h" #include "common/utilities.h"
#include "libANGLE/angletypes.h" #include "libANGLE/angletypes.h"
#include "libANGLE/renderer/null/ContextNULL.h"
namespace rx namespace rx
{ {
BufferNULL::BufferNULL(const gl::BufferState &state) : BufferImpl(state) BufferNULL::BufferNULL(const gl::BufferState &state, AllocationTrackerNULL *allocationTracker)
: BufferImpl(state), mAllocationTracker(allocationTracker)
{ {
ASSERT(mAllocationTracker != nullptr);
} }
BufferNULL::~BufferNULL() BufferNULL::~BufferNULL()
{ {
bool memoryReleaseResult = mAllocationTracker->updateMemoryAllocation(mData.size(), 0);
ASSERT(memoryReleaseResult);
} }
gl::Error BufferNULL::setData(ContextImpl *context, gl::Error BufferNULL::setData(ContextImpl *context,
...@@ -30,6 +35,11 @@ gl::Error BufferNULL::setData(ContextImpl *context, ...@@ -30,6 +35,11 @@ gl::Error BufferNULL::setData(ContextImpl *context,
size_t size, size_t size,
GLenum usage) GLenum usage)
{ {
if (!mAllocationTracker->updateMemoryAllocation(mData.size(), size))
{
return gl::OutOfMemory() << "Unable to allocate internal buffer storage.";
}
mData.resize(size, 0); mData.resize(size, 0);
if (size > 0 && data != nullptr) if (size > 0 && data != nullptr)
{ {
......
...@@ -15,10 +15,12 @@ ...@@ -15,10 +15,12 @@
namespace rx namespace rx
{ {
class AllocationTrackerNULL;
class BufferNULL : public BufferImpl class BufferNULL : public BufferImpl
{ {
public: public:
BufferNULL(const gl::BufferState &state); BufferNULL(const gl::BufferState &state, AllocationTrackerNULL *allocationTracker);
~BufferNULL() override; ~BufferNULL() override;
gl::Error setData(ContextImpl *context, gl::Error setData(ContextImpl *context,
...@@ -52,6 +54,8 @@ class BufferNULL : public BufferImpl ...@@ -52,6 +54,8 @@ class BufferNULL : public BufferImpl
private: private:
std::vector<uint8_t> mData; std::vector<uint8_t> mData;
AllocationTrackerNULL *mAllocationTracker;
}; };
} // namespace rx } // namespace rx
......
...@@ -31,8 +31,38 @@ ...@@ -31,8 +31,38 @@
namespace rx namespace rx
{ {
ContextNULL::ContextNULL(const gl::ContextState &state) : ContextImpl(state) AllocationTrackerNULL::AllocationTrackerNULL(size_t maxTotalAllocationSize)
: mAllocatedBytes(0), mMaxBytes(maxTotalAllocationSize)
{ {
}
AllocationTrackerNULL::~AllocationTrackerNULL()
{
// ASSERT that all objects with the NULL renderer clean up after themselves
ASSERT(mAllocatedBytes == 0);
}
bool AllocationTrackerNULL::updateMemoryAllocation(size_t oldSize, size_t newSize)
{
ASSERT(mAllocatedBytes >= oldSize);
size_t sizeAfterRelease = mAllocatedBytes - oldSize;
size_t sizeAfterReallocate = sizeAfterRelease + newSize;
if (sizeAfterReallocate < sizeAfterRelease || sizeAfterReallocate > mMaxBytes)
{
// Overflow or allocation would be too large
return false;
}
mAllocatedBytes = sizeAfterReallocate;
return true;
}
ContextNULL::ContextNULL(const gl::ContextState &state, AllocationTrackerNULL *allocationTracker)
: ContextImpl(state), mAllocationTracker(allocationTracker)
{
ASSERT(mAllocationTracker != nullptr);
const gl::Version maxClientVersion(3, 1); const gl::Version maxClientVersion(3, 1);
mCaps = GenerateMinimumCaps(maxClientVersion); mCaps = GenerateMinimumCaps(maxClientVersion);
...@@ -290,7 +320,7 @@ RenderbufferImpl *ContextNULL::createRenderbuffer() ...@@ -290,7 +320,7 @@ RenderbufferImpl *ContextNULL::createRenderbuffer()
BufferImpl *ContextNULL::createBuffer(const gl::BufferState &state) BufferImpl *ContextNULL::createBuffer(const gl::BufferState &state)
{ {
return new BufferNULL(state); return new BufferNULL(state, mAllocationTracker);
} }
VertexArrayImpl *ContextNULL::createVertexArray(const gl::VertexArrayState &data) VertexArrayImpl *ContextNULL::createVertexArray(const gl::VertexArrayState &data)
......
...@@ -15,10 +15,25 @@ ...@@ -15,10 +15,25 @@
namespace rx namespace rx
{ {
class AllocationTrackerNULL : angle::NonCopyable
{
public:
explicit AllocationTrackerNULL(size_t maxTotalAllocationSize);
~AllocationTrackerNULL();
// Check if it is possible to change an allocation from oldSize to newSize. If it is possible,
// the allocation is registered and true is returned else false is returned.
bool updateMemoryAllocation(size_t oldSize, size_t newSize);
private:
size_t mAllocatedBytes;
const size_t mMaxBytes;
};
class ContextNULL : public ContextImpl class ContextNULL : public ContextImpl
{ {
public: public:
ContextNULL(const gl::ContextState &state); ContextNULL(const gl::ContextState &state, AllocationTrackerNULL *allocationTracker);
~ContextNULL() override; ~ContextNULL() override;
gl::Error initialize() override; gl::Error initialize() override;
...@@ -168,6 +183,8 @@ class ContextNULL : public ContextImpl ...@@ -168,6 +183,8 @@ class ContextNULL : public ContextImpl
gl::TextureCapsMap mTextureCaps; gl::TextureCapsMap mTextureCaps;
gl::Extensions mExtensions; gl::Extensions mExtensions;
gl::Limitations mLimitations; gl::Limitations mLimitations;
AllocationTrackerNULL *mAllocationTracker;
}; };
} // namespace rx } // namespace rx
......
...@@ -30,11 +30,16 @@ DisplayNULL::~DisplayNULL() ...@@ -30,11 +30,16 @@ DisplayNULL::~DisplayNULL()
egl::Error DisplayNULL::initialize(egl::Display *display) egl::Error DisplayNULL::initialize(egl::Display *display)
{ {
mDevice = new DeviceNULL(); mDevice = new DeviceNULL();
constexpr size_t kMaxTotalAllocationSize = 1 << 28; // 256MB
mAllocationTracker.reset(new AllocationTrackerNULL(kMaxTotalAllocationSize));
return egl::NoError(); return egl::NoError();
} }
void DisplayNULL::terminate() void DisplayNULL::terminate()
{ {
mAllocationTracker.reset();
SafeDelete(mDevice); SafeDelete(mDevice);
} }
...@@ -168,7 +173,7 @@ ImageImpl *DisplayNULL::createImage(EGLenum target, ...@@ -168,7 +173,7 @@ ImageImpl *DisplayNULL::createImage(EGLenum target,
ContextImpl *DisplayNULL::createContext(const gl::ContextState &state) ContextImpl *DisplayNULL::createContext(const gl::ContextState &state)
{ {
return new ContextNULL(state); return new ContextNULL(state, mAllocationTracker.get());
} }
StreamProducerImpl *DisplayNULL::createStreamProducerD3DTextureNV12( StreamProducerImpl *DisplayNULL::createStreamProducerD3DTextureNV12(
......
...@@ -15,6 +15,8 @@ ...@@ -15,6 +15,8 @@
namespace rx namespace rx
{ {
class AllocationTrackerNULL;
class DisplayNULL : public DisplayImpl class DisplayNULL : public DisplayImpl
{ {
public: public:
...@@ -73,6 +75,8 @@ class DisplayNULL : public DisplayImpl ...@@ -73,6 +75,8 @@ class DisplayNULL : public DisplayImpl
void generateCaps(egl::Caps *outCaps) const override; void generateCaps(egl::Caps *outCaps) const override;
DeviceImpl *mDevice; DeviceImpl *mDevice;
std::unique_ptr<AllocationTrackerNULL> mAllocationTracker;
}; };
} // namespace rx } // namespace rx
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment