Fix EGL crash (rfbz#4303)

This commit is contained in:
leigh123linux 2016-10-25 14:33:20 +01:00
parent fa9c878a75
commit 2e09c839ae
2 changed files with 159 additions and 2 deletions

153
egl_crash.patch Normal file
View File

@ -0,0 +1,153 @@
From 61bd107cc64f158d7a3e40877c47aa565651487a 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.
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.
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.
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.
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(-)
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);
}
} 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);
}
+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);
+
#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

View File

@ -3,12 +3,13 @@
Name: libglvnd
Version: 0.2.999
Release: 4%{?commit0:.git%{shortcommit0}}%{?dist}
Release: 5%{?commit0:.git%{shortcommit0}}%{?dist}
Summary: The GL Vendor-Neutral Dispatch library
License: MIT
URL: https://github.com/NVIDIA/libglvnd
Source0: https://github.com/NVIDIA/%{name}/archive/%{commit0}.tar.gz#/%{name}-%{shortcommit0}.tar.gz
Patch0: egl_crash.patch
BuildRequires: libtool
BuildRequires: gcc
@ -43,7 +44,7 @@ developing applications that use %{name}.
%prep
%autosetup -n %{name}-%{?commit0}%{?!commit0:%{version}}
%autosetup -p1 -n %{name}-%{?commit0}%{?!commit0:%{version}}
autoreconf -vif
%build
@ -113,6 +114,9 @@ xvfb-run -a make check V=1 || cat `find . -name test-suite.log`
%changelog
* Tue Oct 25 2016 Leigh Scott <leigh123linux@googlemail.com> - 0.2.999-5.git295e5e5
- Fix EGL crash (rfbz#4303)
* Fri Oct 14 2016 Nicolas Chauvet <kwizart@gmail.com> - 0.2.999-4.git295e5e5
- Update snapshot