Fix EGL crash for KDE/Plasma (rfbz#4303)

This commit is contained in:
leigh123linux 2016-10-26 01:36:26 +01:00
parent 2e09c839ae
commit 280f7a2910
3 changed files with 73 additions and 142 deletions

View File

@ -1,153 +1,80 @@
From 61bd107cc64f158d7a3e40877c47aa565651487a Mon Sep 17 00:00:00 2001
From 758b525463cd00478bf071d477ab58c92414b852 Mon Sep 17 00:00:00 2001
From: Kyle Brenneman <kbrenneman@nvidia.com>
Date: Mon, 24 Oct 2016 14:52:27 -0600
Subject: [PATCH] Fix a crash in process termination when EGL and GLX are both
loaded.
Date: Tue, 25 Oct 2016 17:32:47 -0600
Subject: [PATCH 1/2] GLdispatch: Don't call into the vendor from
__glDispatchForceUnpatch.
Added a new function to libGLdispatch, __glDispatchForceUnpatch, which forces
it to unpatch the OpenGL entrypoints before libEGL or libGLX can unload the
vendor library that patched them.
In __glDispatchForceUnpatch, don't call the vendor's releasePatch callback,
because the vendor library might have already been unloaded by that point.
---
src/GLdispatch/GLdispatch.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
If a vendor patches the OpenGL entrypoints, libGLdispatch doesn't unpatch them
when that vendor's context is no longer current, because that adds too much
overhead to repeated MakeCurrent+LoseCurrent calls. But, that also means that
the patch callbacks end up being dangling pointers after the vendor library is
unloaded.
diff --git a/src/GLdispatch/GLdispatch.c b/src/GLdispatch/GLdispatch.c
index 8c4c3a7..cf4254e 100644
--- a/src/GLdispatch/GLdispatch.c
+++ b/src/GLdispatch/GLdispatch.c
@@ -570,8 +570,10 @@ static int PatchEntrypoints(
if (stubCurrentPatchCb) {
// Notify the previous vendor that it no longer owns these
- // entrypoints.
- if (stubCurrentPatchCb->releasePatch != NULL) {
+ // entrypoints. If this is being called from a library unload,
+ // though, then skip the callback, because the vendor may have
+ // already been unloaded.
+ if (stubCurrentPatchCb->releasePatch != NULL && !force) {
stubCurrentPatchCb->releasePatch();
}
This mainly shows up at process termination when a process loads both libEGL
and libGLX, because __glxFini and __eglFini will both call the vendor's
threadAttach callback.
From 8146a979d85e975587f3a20f0a6fdc2f04fa478f Mon Sep 17 00:00:00 2001
From: Kyle Brenneman <kbrenneman@nvidia.com>
Date: Tue, 25 Oct 2016 17:34:26 -0600
Subject: [PATCH 2/2] EGL: Don't call into the vendor library from __eglFini.
In __eglFini, check for a fork, but don't call __glDispatchCheckMultithreaded.
If a vendor has patched the OpenGL entrypoints, then
__glDispatchCheckMultithreaded will try to call the vendor's thread attach
callback, but the vendor library may have already been unloaded.
Fixes https://github.com/NVIDIA/libglvnd/issues/103
---
src/EGL/libeglvendor.c | 1 +
src/GLX/libglxmapping.c | 10 ++++++++++
src/GLdispatch/GLdispatch.c | 31 ++++++++++++++++++++++++++++---
src/GLdispatch/GLdispatch.h | 9 +++++++++
src/GLdispatch/export_list.sym | 1 +
5 files changed, 49 insertions(+), 3 deletions(-)
src/EGL/libegl.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/src/EGL/libeglvendor.c b/src/EGL/libeglvendor.c
index 3118cca..6d6961a 100644
--- a/src/EGL/libeglvendor.c
+++ b/src/EGL/libeglvendor.c
@@ -144,6 +144,7 @@ void __eglTeardownVendors(void)
glvnd_list_for_each_entry_safe(vendor, vendorTemp, &__eglVendorList, entry) {
glvnd_list_del(&vendor->entry);
+ __glDispatchForceUnpatch(vendor->vendorID);
TeardownVendor(vendor);
}
}
diff --git a/src/GLX/libglxmapping.c b/src/GLX/libglxmapping.c
index 1e83c0b..2e15065 100644
--- a/src/GLX/libglxmapping.c
+++ b/src/GLX/libglxmapping.c
@@ -1026,9 +1026,19 @@ void __glXMappingTeardown(Bool doReset)
__glvndPthreadFuncs.rwlock_init(&dpyInfoEntry->info.vendorLock, NULL);
diff --git a/src/EGL/libegl.c b/src/EGL/libegl.c
index 65e6605..e0a5488 100644
--- a/src/EGL/libegl.c
+++ b/src/EGL/libegl.c
@@ -1088,7 +1088,7 @@ static void __eglResetOnFork(void);
* Currently, this only detects whether a fork occurred since the last
* entrypoint was called, and performs recovery as needed.
*/
-void __eglThreadInitialize(void)
+void CheckFork(void)
{
volatile static int g_threadsInCheck = 0;
volatile static int g_lastPid = -1;
@@ -1120,7 +1120,11 @@ void __eglThreadInitialize(void)
sched_yield();
}
} else {
+ __GLXvendorNameHash *pEntry, *tmp;
+
/* Tear down all hashtables used in this file */
__glvndWinsysDispatchCleanup();
+ // If a GLX vendor library has patched the OpenGL entrypoints, then
+ // unpatch them before we unload the vendors.
+ LKDHASH_RDLOCK(__glXVendorNameHash);
+ HASH_ITER(hh, _LH(__glXVendorNameHash), pEntry, tmp) {
+ __glDispatchForceUnpatch(pEntry->vendor.vendorID);
+ }
+ LKDHASH_UNLOCK(__glXVendorNameHash);
+
LKDHASH_TEARDOWN(__GLXvendorConfigMappingHash,
fbconfigHashtable, NULL, NULL, False);
diff --git a/src/GLdispatch/GLdispatch.c b/src/GLdispatch/GLdispatch.c
index cd0d776..8c4c3a7 100644
--- a/src/GLdispatch/GLdispatch.c
+++ b/src/GLdispatch/GLdispatch.c
@@ -552,13 +552,14 @@ void UnregisterAllStubCallbacks(void)
*/
static int PatchEntrypoints(
const __GLdispatchPatchCallbacks *patchCb,
- int vendorID
+ int vendorID,
+ GLboolean force
)
{
__GLdispatchStubCallback *stub;
CheckDispatchLocked();
- if (!PatchingIsSafe()) {
+ if (!force && !PatchingIsSafe()) {
return 0;
}
+}
@@ -648,7 +649,7 @@ PUBLIC GLboolean __glDispatchMakeCurrent(__GLdispatchThreadState *threadState,
LockDispatch();
// Patch if necessary
- PatchEntrypoints(patchCb, vendorID);
+ PatchEntrypoints(patchCb, vendorID, GL_FALSE);
// If the current entrypoints are unsafe to use with this vendor, bail out.
if (!CurrentEntrypointsSafeToUse(vendorID)) {
@@ -728,6 +729,30 @@ PUBLIC void __glDispatchLoseCurrent(void)
LoseCurrentInternal(curThreadState, GL_FALSE);
+void __eglThreadInitialize(void)
+{
+ CheckFork();
__glDispatchCheckMultithreaded();
}
+PUBLIC GLboolean __glDispatchForceUnpatch(int vendorID)
+{
+ GLboolean ret = GL_FALSE;
+
+ LockDispatch();
+ if (stubCurrentPatchCb != NULL && stubOwnerVendorID == vendorID) {
+ /*
+ * The vendor library with the patch callbacks is about to be unloaded,
+ * so we need to unpatch the entrypoints even if there's a current
+ * context on another thread.
+ *
+ * If a buggy application is trying to call an OpenGL function on
+ * another thread, then we're going to run into problems, but in that
+ * case, it's just as likely that the other thread would be somewhere
+ * in the vendor library itself.
+ */
+ PatchEntrypoints(NULL, 0, GL_TRUE);
+ ret = GL_TRUE;
+ }
+ UnlockDispatch();
+
+ return ret;
+}
+
__GLdispatchThreadState *__glDispatchGetCurrentThreadState(void)
{
return (__GLdispatchThreadState *) __glvndPthreadFuncs.getspecific(threadContextKey);
diff --git a/src/GLdispatch/GLdispatch.h b/src/GLdispatch/GLdispatch.h
index 3d83215..262a29e 100644
--- a/src/GLdispatch/GLdispatch.h
+++ b/src/GLdispatch/GLdispatch.h
@@ -320,4 +320,13 @@ PUBLIC __GLdispatchThreadState *__glDispatchGetCurrentThreadState(void);
*/
PUBLIC void __glDispatchCheckMultithreaded(void);
+/**
+ * Tells libGLdispatch to unpatch the OpenGL entrypoints, but only if they were
+ * patched by the given vendor.
+ *
+ * This is called when libEGL or libGLX is unloaded, to remove any dangling
+ * pointers to the vendor library's patch callbacks.
+ */
+PUBLIC GLboolean __glDispatchForceUnpatch(int vendorID);
+
@@ -1190,7 +1194,7 @@ void _fini(void)
#endif
diff --git a/src/GLdispatch/export_list.sym b/src/GLdispatch/export_list.sym
index 41be6bf..a8c1f60 100644
--- a/src/GLdispatch/export_list.sym
+++ b/src/GLdispatch/export_list.sym
@@ -15,3 +15,4 @@ __glDispatchNewVendorID
__glDispatchRegisterStubCallbacks
__glDispatchReset
__glDispatchUnregisterStubCallbacks
+__glDispatchForceUnpatch
{
/* Check for a fork before going further. */
- __eglThreadInitialize();
+ CheckFork();
/*
* If libEGL owns the current API state, lose current

View File

@ -1,9 +1,9 @@
%global commit0 295e5e5769d0a1db312a76a57870dc8a11742f48
%global commit0 28867bb6597d1cf879b12c60a4b512a23758d3f6
%global shortcommit0 %(c=%{commit0}; echo ${c:0:7})
Name: libglvnd
Version: 0.2.999
Release: 5%{?commit0:.git%{shortcommit0}}%{?dist}
Release: 6%{?commit0:.git%{shortcommit0}}%{?dist}
Summary: The GL Vendor-Neutral Dispatch library
License: MIT
@ -114,6 +114,10 @@ xvfb-run -a make check V=1 || cat `find . -name test-suite.log`
%changelog
* Wed Oct 26 2016 Leigh Scott <leigh123linux@googlemail.com> - 0.2.999-6.git28867bb
- Update snapshot
- Fix EGL crash for KDE/Plasma (rfbz#4303)
* Tue Oct 25 2016 Leigh Scott <leigh123linux@googlemail.com> - 0.2.999-5.git295e5e5
- Fix EGL crash (rfbz#4303)

View File

@ -1 +1 @@
1443c2891d9a2c3792002f116ea77047 libglvnd-295e5e5.tar.gz
7f361721ca9b1db26ebb40400034c45f libglvnd-28867bb.tar.gz