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> From: Kyle Brenneman <kbrenneman@nvidia.com>
Date: Mon, 24 Oct 2016 14:52:27 -0600 Date: Tue, 25 Oct 2016 17:32:47 -0600
Subject: [PATCH] Fix a crash in process termination when EGL and GLX are both Subject: [PATCH 1/2] GLdispatch: Don't call into the vendor from
loaded. __glDispatchForceUnpatch.
Added a new function to libGLdispatch, __glDispatchForceUnpatch, which forces In __glDispatchForceUnpatch, don't call the vendor's releasePatch callback,
it to unpatch the OpenGL entrypoints before libEGL or libGLX can unload the because the vendor library might have already been unloaded by that point.
vendor library that patched them. ---
src/GLdispatch/GLdispatch.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
If a vendor patches the OpenGL entrypoints, libGLdispatch doesn't unpatch them diff --git a/src/GLdispatch/GLdispatch.c b/src/GLdispatch/GLdispatch.c
when that vendor's context is no longer current, because that adds too much index 8c4c3a7..cf4254e 100644
overhead to repeated MakeCurrent+LoseCurrent calls. But, that also means that --- a/src/GLdispatch/GLdispatch.c
the patch callbacks end up being dangling pointers after the vendor library is +++ b/src/GLdispatch/GLdispatch.c
unloaded. @@ -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 From 8146a979d85e975587f3a20f0a6fdc2f04fa478f Mon Sep 17 00:00:00 2001
and libGLX, because __glxFini and __eglFini will both call the vendor's From: Kyle Brenneman <kbrenneman@nvidia.com>
threadAttach callback. 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 Fixes https://github.com/NVIDIA/libglvnd/issues/103
--- ---
src/EGL/libeglvendor.c | 1 + src/EGL/libegl.c | 8 ++++++--
src/GLX/libglxmapping.c | 10 ++++++++++ 1 file changed, 6 insertions(+), 2 deletions(-)
src/GLdispatch/GLdispatch.c | 31 ++++++++++++++++++++++++++++---
src/GLdispatch/GLdispatch.h | 9 +++++++++
src/GLdispatch/export_list.sym | 1 +
5 files changed, 49 insertions(+), 3 deletions(-)
diff --git a/src/EGL/libeglvendor.c b/src/EGL/libeglvendor.c diff --git a/src/EGL/libegl.c b/src/EGL/libegl.c
index 3118cca..6d6961a 100644 index 65e6605..e0a5488 100644
--- a/src/EGL/libeglvendor.c --- a/src/EGL/libegl.c
+++ b/src/EGL/libeglvendor.c +++ b/src/EGL/libegl.c
@@ -144,6 +144,7 @@ void __eglTeardownVendors(void) @@ -1088,7 +1088,7 @@ static void __eglResetOnFork(void);
* Currently, this only detects whether a fork occurred since the last
glvnd_list_for_each_entry_safe(vendor, vendorTemp, &__eglVendorList, entry) { * entrypoint was called, and performs recovery as needed.
glvnd_list_del(&vendor->entry); */
+ __glDispatchForceUnpatch(vendor->vendorID); -void __eglThreadInitialize(void)
TeardownVendor(vendor); +void CheckFork(void)
} {
} volatile static int g_threadsInCheck = 0;
diff --git a/src/GLX/libglxmapping.c b/src/GLX/libglxmapping.c volatile static int g_lastPid = -1;
index 1e83c0b..2e15065 100644 @@ -1120,7 +1120,11 @@ void __eglThreadInitialize(void)
--- a/src/GLX/libglxmapping.c sched_yield();
+++ b/src/GLX/libglxmapping.c
@@ -1026,9 +1026,19 @@ void __glXMappingTeardown(Bool doReset)
__glvndPthreadFuncs.rwlock_init(&dpyInfoEntry->info.vendorLock, NULL);
} }
} 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, +void __eglThreadInitialize(void)
LockDispatch(); +{
+ CheckFork();
// Patch if necessary __glDispatchCheckMultithreaded();
- 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);
} }
+PUBLIC GLboolean __glDispatchForceUnpatch(int vendorID) @@ -1190,7 +1194,7 @@ void _fini(void)
+{
+ 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);
+
#endif #endif
diff --git a/src/GLdispatch/export_list.sym b/src/GLdispatch/export_list.sym {
index 41be6bf..a8c1f60 100644 /* Check for a fork before going further. */
--- a/src/GLdispatch/export_list.sym - __eglThreadInitialize();
+++ b/src/GLdispatch/export_list.sym + CheckFork();
@@ -15,3 +15,4 @@ __glDispatchNewVendorID
__glDispatchRegisterStubCallbacks /*
__glDispatchReset * If libEGL owns the current API state, lose current
__glDispatchUnregisterStubCallbacks
+__glDispatchForceUnpatch

View File

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

View File

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