php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #40858 Thread safety issue in GD
Submitted: 2007-03-19 18:41 UTC Modified: 2009-08-17 08:46 UTC
From: scottmacvicar at ntlworld dot com Assigned: pajoye (profile)
Status: Closed Package: GD related
PHP Version: 5.2.1 OS: RHEL 4
Private report: No CVE-ID: None
 [2007-03-19 18:41 UTC] scottmacvicar at ntlworld dot com
Description:
------------
Appears to be still several more thread safety issues in GD, I've not had time to track these all down yet.

We're running gdft.c from CVS to fix a few identified issues already. Looking at the code there still appears to be a race condition within the code but it appears to be a pretty tight loop since its not happening as often as before.

By looking at gdft.c it looks possible for a fontCache entry to exist during a check, by the time it gets to obtaining the lock the fontCache has been cleared or something similarly evil.

The backtrace we've got is: http://public.vbulletin.com/bugs/php/gdcache-bt.txt

Patch for first issue to deal with the possibility that a cache entry is null: http://public.vbulletin.com/bugs/php/gdcache-patch-1.txt

Potential patch for second issue to deal with gdCacheSetup thread safety: http://public.vbulletin.com/bugs/php/gdcache-patch-2.txt


Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2007-03-19 18:53 UTC] tony2001@php.net
Assigned to the maintainer.
 [2007-03-19 19:13 UTC] scottmacvicar at ntlworld dot com
I should have mentioned, the first patch deals with the segfault so it errors out gracefully. We've got this running on production now.

The second patch is an attempt to deal with the race condition that's still present, would probably be simplier to just to call gdFontCacheSetup() again but I'm unsure what the behaviour is of setting up a mutex thats already initialised and then locking it.
 [2007-03-19 19:22 UTC] pajoye@php.net
Yes, we noticed the cacheSetup problem too. One solution is to initialize it in MINIT and destroy it in MSHUTDOWN. I'm working on patch to implement this solution.

The first problem looks weird. It defeats the whole purpose of the mutex. I do not have the time now to test. I will give it a try later this week.
 [2007-03-19 19:24 UTC] tony2001@php.net
>The first problem looks weird. It defeats the whole purpose of the
mutex.
The !=NULL check is out of the mutex protected block.
 [2007-03-19 19:27 UTC] pajoye@php.net
Did we not put it inside in the latest version of the last patch? I do not have the code at hand but as far as I remember Nuno updated it. I will check again tonight.
 [2007-03-21 00:40 UTC] scottmacvicar at ntlworld dot com
Moving the code to PHP_MINIT fixes the problem for PHP but the threading options of GD doesn't extend itself to this setup since the function to create the mutex can be called more than once in a short period of time.

This small race condition could be fixed by using pthread_once to ensure the mutexes are allocated only once but I'm unsure of the Win32 equivalent.

I've got a patch that implements the PHP solution running on our boxes, I can provide it if interested.
 [2007-03-21 00:48 UTC] pajoye@php.net
"Moving the code to PHP_MINIT fixes the problem for PHP but the threading options of GD doesn't extend itself to this setup since the function to create the mutex can be called more than once in a short period of time."

Do you mean for libGD itself used a library in a random project? If yes, a solution is very similar to this one. We have to do it at load time (like DLLMain on windows). Many other libraries (and many related to FT2, with ft2 cache or their own) rely on this solution. We can give it a try, at least.

"I've got a patch that implements the PHP solution running on our boxes, I can provide it if interested."

You can always post it, I still did not get the time to do it, so any help is welcome.
 [2007-03-21 01:37 UTC] scottmacvicar at ntlworld dot com
Patch is available at http://public.vbulletin.com/bugs/php/gd-mutex-patch.txt

Quick explanation:
* The mutex is created at module startup and destroyed at module shutdown courtesy of two new helper functions within the libGD code base.
* The mutex is no longer destroyed at request shutdown.
* Locking is performed prior to checking fontCache to prevent the race condition we're seeing.

This can't be merged back into libGD at the moment since it breaks backwards compatibility by assuming a mutex has been allocated, the way to fix this for pthread is fairly easy.

#define gdMutexDeclare(x) pthread_mutex_t x
#define gdMutexDeclare(x) pthread_mutex_t x
becomes
#define gdMutexDeclare(x) static pthread_mutex_t x = PTHREAD_MUTEX_INITIALIZER
#define gdMutexSetup(x)

That would just leave the win32 implementation to deal with via DLLMain, a quick patch to add that would only take a few minutes though I don't have VC6 installed yet.
 [2007-03-22 23:15 UTC] nlopess@php.net
yep, having a statically declared mutex would fix the problems we are having. I've a patch identical to yours (http://mega.ist.utl.pt/~ncpl/libgd_mutexes.txt) for a while, but we are still waiting for a win32 implementation to merge the patches (there is another open bug report in the gd bugs db about a similar issue) to definitely fix those nasty TS issues.
 [2007-03-23 00:31 UTC] scottmacvicar at ntlworld dot com
I have some time to spare over the weekend and a copy of VC6 installed now so I'll have a go at the win32 implementation.

Regarding the patch to the bundled GD library and the php wrapper, does it look reasonable? We've been running it for the past 2 days now without issue on a production server. I'd rather see something put into 5.2.2 and then fix libGD.
 [2007-03-23 01:21 UTC] pajoye@php.net
Hi Scott, Nuno,

"Regarding the patch to the bundled GD library and the php wrapper, does it look reasonable? We've been running it for the past 2 days now
without issue on a production server. I'd rather see something put into
5.2.2 "

Yes, the patch for php (and unix) looks good. I will apply it during the weekend as well (or Nuno, you can do it if you have the time before).

For the windows version, that's a good news, thanks to take the time to work on it.
 [2007-03-23 12:39 UTC] scottmacvicar at ntlworld dot com
I don't have access to a Windows machine at the moment but the following patch should fix the issues in libGD, I'll try and do a test when I have access to the machine.

PHP 5.2 Patch: http://public.vbulletin.com/bugs/php/gd-mutex-patch.txt
libGD Patch: http://public.vbulletin.com/bugs/php/libgd-mutex-patch.txt

Explanation:
* pthread now initialises the mutex only once
* win32 can set the mutex within DLLMain
* Race condition fix by locking prior to checking font cache

Problems not fixed:
* calling gdFontCacheSetup before obtaining a lock is going to cause the race condition still, I know the ruby wrappers do this.
* Unusure about behaviour of using the non bundled GD library on windows with PHP since DLLMain and gdFontCacheMutexSetup may setup the critical section twice. Could make gdMutexSetup(x) a no-op for win32 too.
 [2007-04-04 01:59 UTC] pajoye@php.net
Please try using this CVS snapshot:

  http://snaps.php.net/php5.2-latest.tar.gz
 
For Windows:
 
  http://snaps.php.net/win32/php5.2-win32-latest.zip


 [2007-04-12 01:00 UTC] php-bugs at lists dot php dot net
No feedback was provided for this bug for over a week, so it is
being suspended automatically. If you are able to provide the
information that was originally requested, please do so and change
the status of the bug back to "Open".
 [2009-08-17 08:46 UTC] pajoye@php.net
fixed in all branches.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Thu Apr 18 04:01:27 2024 UTC