Prevent glDeleteQueries from deleting a live Query glDeleteQueries() instantly deletes all the es2::Query objects passed as arguments to this function. If some of these queries are still being used by the renderer, this will result in a use after free error. To solve this issue, sw::Query is now a also ref counted object. Bug chromium:904714 Change-Id: Ic1d5781bbf1724d8d07936fd49c8a172dc3d9fd4 Reviewed-on: https://swiftshader-review.googlesource.com/c/22548 Tested-by: Alexis Hétu <sugoi@google.com> Reviewed-by: Nicolas Capens <nicolascapens@google.com>
diff --git a/src/D3D9/Direct3DQuery9.cpp b/src/D3D9/Direct3DQuery9.cpp index 31d249e..b6a3b2d 100644 --- a/src/D3D9/Direct3DQuery9.cpp +++ b/src/D3D9/Direct3DQuery9.cpp
@@ -41,7 +41,7 @@ { device->removeQuery(query); - delete query; + query->release(); } } @@ -202,7 +202,7 @@ return INVALIDCALL(); } - bool signaled = !query || query->reference == 0; + bool signaled = !query || query->isReady(); if(size && signaled) {
diff --git a/src/OpenGL/libGLESv2/Query.cpp b/src/OpenGL/libGLESv2/Query.cpp index 027f8ab..8728621 100644 --- a/src/OpenGL/libGLESv2/Query.cpp +++ b/src/OpenGL/libGLESv2/Query.cpp
@@ -32,7 +32,7 @@ Query::~Query() { - delete mQuery; + mQuery->release(); } void Query::begin() @@ -140,7 +140,7 @@ { if(mQuery != nullptr && mStatus != GL_TRUE) { - if(!mQuery->building && mQuery->reference == 0) + if(!mQuery->building && mQuery->isReady()) { unsigned int resultSum = mQuery->data; mStatus = GL_TRUE;
diff --git a/src/Renderer/Renderer.cpp b/src/Renderer/Renderer.cpp index e7ec20a..27c2194 100644 --- a/src/Renderer/Renderer.cpp +++ b/src/Renderer/Renderer.cpp
@@ -96,6 +96,27 @@ int threadIndex; }; + Query::Query(Type type) : building(false), data(0), type(type), reference(1) + { + } + + void Query::addRef() + { + ++reference; // Atomic + } + + void Query::release() + { + int ref = reference--; // Atomic + + ASSERT(ref >= 0); + + if(ref == 0) + { + delete this; + } + } + DrawCall::DrawCall() { queries = 0; @@ -325,7 +346,7 @@ { if(includePrimitivesWrittenQueries || (query->type != Query::TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN)) { - ++query->reference; // Atomic + query->addRef(); draw->queries->push_back(query); } } @@ -1013,7 +1034,7 @@ break; } - --query->reference; // Atomic + query->release(); } delete draw.queries;
diff --git a/src/Renderer/Renderer.hpp b/src/Renderer/Renderer.hpp index ce22866..0846a27 100644 --- a/src/Renderer/Renderer.hpp +++ b/src/Renderer/Renderer.hpp
@@ -89,26 +89,35 @@ { enum Type { FRAGMENTS_PASSED, TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN }; - Query(Type type) : building(false), reference(0), data(0), type(type) - { - } + Query(Type type); - void begin() + void addRef(); + void release(); + + inline void begin() { building = true; data = 0; } - void end() + inline void end() { building = false; } + inline bool isReady() const + { + return (reference == 1); + } + bool building; - AtomicInt reference; AtomicInt data; const Type type; + private: + ~Query() {} // Only delete a query within the release() function + + AtomicInt reference; }; struct DrawData