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