Package: ghostscript Version: 9.06~dfsg-2+deb8u1 Ghostscript <=9.15 has a bug which manifests itself only on certain machines, causing it to segfault on certain PDF files. This is due to the incorrect assumption that unlocking an already unlocked mutex is a no-op, something which is not guaranteed by Single Unix, and may or may not be true depending on the hardware / kernel / phase of the moon. See <URL: http://bugs.ghostscript.com/show_bug.cgi?id=695862 > for details.
I have been bitten by this bug (changed my processor and suddenly all sorts of PDF files wouldn't print), so it is not theoretical. I believe Debian should backport some fix for this. One possible fix (tested on my machine) is attached: it consists of using error-checking mutexes instead of fast ones (error-checking mutexes are documented to return EPERM when unlocked twice). This fix is called "hacky" by Chris Liddell in the above-mentioned bug report page, but I think it is perfectly sensible. Otherwise, backport the patch made to the ghostscript upstream itself. -- David A. Madore ( http://www.madore.org/~david/ )
Description: fix ghostscript bug #695862 by using error-checking mutexes Author: David Madore <david+b...@madore.org> Last-Update: 2016-09-20 Index: ghostscript-9.06~dfsg/base/gp_psync.c =================================================================== --- ghostscript-9.06~dfsg.orig/base/gp_psync.c +++ ghostscript-9.06~dfsg/base/gp_psync.c @@ -20,6 +20,7 @@ #include <pthread.h> #include "gserrors.h" #include "gpsync.h" +#include <errno.h> /* * Thanks to Larry Jones <larry.jo...@sdrc.com> for this revision of @@ -64,10 +65,21 @@ gp_semaphore_open(gp_semaphore * sema) pt_semaphore_t * const sem = (pt_semaphore_t *)sema; int scode; + /* Idiotic threads API won't let you create an error-checking mutex + * without creating another "mutexattr" object which itself + * has to be initialized. This is _absurdly_ verbose! */ + static pthread_mutexattr_t mutexattr; + static char mutexattr_initialized = 0; + if (!sema) return -1; /* semaphores are not movable */ + if ( ! mutexattr_initialized ) { + mutexattr_initialized = 1; + pthread_mutexattr_init(&mutexattr); + pthread_mutexattr_settype(&mutexattr, PTHREAD_MUTEX_ERRORCHECK); + } sem->count = 0; - scode = pthread_mutex_init(&sem->mutex, NULL); + scode = pthread_mutex_init(&sem->mutex, &mutexattr); if (scode == 0) scode = pthread_cond_init(&sem->cond, NULL); return SEM_ERROR_CODE(scode); @@ -103,6 +115,8 @@ gp_semaphore_wait(gp_semaphore * sema) if (scode == 0) --sem->count; scode2 = pthread_mutex_unlock(&sem->mutex); + if ( scode2 == EPERM ) + scode2 = 0; if (scode == 0) scode = scode2; return SEM_ERROR_CODE(scode); @@ -120,6 +134,8 @@ gp_semaphore_signal(gp_semaphore * sema) if (sem->count++ == 0) scode = pthread_cond_signal(&sem->cond); scode2 = pthread_mutex_unlock(&sem->mutex); + if ( scode2 == EPERM ) + scode2 = 0; if (scode == 0) scode = scode2; return SEM_ERROR_CODE(scode); @@ -149,11 +165,22 @@ gp_monitor_open(gp_monitor * mona) pthread_mutex_t *mon; int scode; + /* Idiotic threads API won't let you create an error-checking mutex + * without creating another "mutexattr" object which itself + * has to be initialized. This is _absurdly_ verbose! */ + static pthread_mutexattr_t mutexattr; + static char mutexattr_initialized = 0; + if (!mona) return -1; /* monitors are not movable */ + if ( ! mutexattr_initialized ) { + mutexattr_initialized = 1; + pthread_mutexattr_init(&mutexattr); + pthread_mutexattr_settype(&mutexattr, PTHREAD_MUTEX_ERRORCHECK); + } mon = &((gp_pthread_recursive_t *)mona)->mutex; ((gp_pthread_recursive_t *)mona)->self_id = 0; /* Not valid unless mutex is locked */ - scode = pthread_mutex_init(mon, NULL); + scode = pthread_mutex_init(mon, &mutexattr); return SEM_ERROR_CODE(scode); } @@ -195,6 +222,8 @@ gp_monitor_leave(gp_monitor * mona) int scode; scode = pthread_mutex_unlock(mon); + if ( scode == EPERM ) + scode = 0; ((gp_pthread_recursive_t *)mona)->self_id = 0; /* Not valid unless mutex is locked */ return SEM_ERROR_CODE(scode); }