php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #42416 Apache2 locked imagecreate with imagettftext
Submitted: 2007-08-24 16:17 UTC Modified: 2007-08-27 19:13 UTC
From: baco at infomaniak dot ch Assigned: pajoye (profile)
Status: Closed Package: GD related
PHP Version: 4.4.7 OS: Linux
Private report: No CVE-ID: None
View Add Comment Developer Edit
Anyone can comment on a bug. Have a simpler test case? Does it work for you on a different platform? Let us know!
Just going to say 'Me too!'? Don't clutter the database with that please !
Your email address:
MUST BE VALID
Solve the problem:
18 + 17 = ?
Subscribe to this entry?

 
 [2007-08-24 16:17 UTC] baco at infomaniak dot ch
Description:
------------
Reproductible with PHP 4.4.7 
or with the last Snap 4.4-dev
on Apache2 using MPM worker.

Apache2 process get locked when calling
imagettftext() after calling imagecreate()
every call of such code result of another
dead locked Apache2 processes.

Workarounds :
- Use imagecreatetruecolor() instead of imagecreate()
- Don't use bundled gdlib compile PHP with external gdlib
- Upgrade 5.2.3 who don't have this issue

Reproductible with
configure \
--with-gd \
--with-png-dir=/usr \
--with-freetype-dir=/usr \
--with-ttf \
--enable-gd-native-ttf \
...

Unreproductible with external gd
configure \
--with-gd=/opt/misc/gd \
--with-png-dir=/usr \
--with-jpeg-dir=/usr \
--with-freetype-dir=/usr \
--with-ttf \
--enable-gd-native-ttf \
...



Reproduce code:
---------------
    $crash = 1;
    $text = 'Bug';
    $font = $_SERVER['DOCUMENT_ROOT'] . '/fonts' .'/'. 'arial.ttf';

    if ($crash == 1) {
        $image = imagecreate(64, 32);
    } else {
        $image = imagecreatetruecolor(64, 32);
    }

    $white = imagecolorallocate($image, 255, 255, 255);

    /* LOCK APACHE2 PROCESS AFTER THIS POINT IF crash == 1
     * => if imagecreate() used but not if imagecreatetruecolor()
     */
    imagettftext($image, 20, 0, 8, 24, $white, $font, $text);

    header('Content-type: image/png');
    imagepng($image);

    imagedestroy($image);


Expected result:
----------------
Display "Bug" white text on black background

Actual result:
--------------
Apache2 process get locked and browser wait for the
image forever. 

After it is a matter of time for Apache2 to have 
all processes locked depending on your ServerLimit
and ThreadsPerChild values.

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2007-08-24 17:48 UTC] baco at infomaniak dot ch
see diff in gdImageCreate()

--- php-4.4.7/ext/gd/libgd/gd.c       2007-08-24 19:39:33.999613335 
+0200
+++ php-5.2.3/ext/gd/libgd/gd.c       2007-08-24 19:39:53.052804086 
+0200
@@ -5,8 +5,8 @@
     im = (gdImage *) gdMalloc(sizeof(gdImage));
     memset(im, 0, sizeof(gdImage));
     /* Row-major ever since gd 1.3 */
-    im->pixels = (unsigned char **) safe_emalloc(sizeof(unsigned 
char *), sy, 0);
-    im->AA_opacity = (unsigned char **) safe_emalloc(sizeof(unsigned 
char *), sy, 0);
+    im->pixels = (unsigned char **) gdMalloc(sizeof(unsigned char *) 
* sy);
+    im->AA_opacity = (unsigned char **) gdMalloc(sizeof(unsigned 
char *) * sy);
     im->polyInts = 0;
     im->polyAllocated = 0;
     im->brush = 0;
 [2007-08-24 18:19 UTC] pajoye@php.net
Workarounds :
"- Use imagecreatetruecolor() instead of imagecreate()"

The patch is your next comment is not correct. 

"- Don't use bundled gdlib compile PHP with external gdlib"

Either you use the bundled library or the external version.

"- Upgrade 5.2.3 who don't have this issue"

That's definitively the right choice. Read the PHP4 death announcement on www.php.net. And php 5.2+ has thread safety issues fixed that will never be backported to php4.

"--with-ttf --enable-gd-native-ttf "

Are you sure you need freetype support?

As a side note, I seriously doubt that using php4 with apache2 MPM is a good idea.

Anyway, it will not be fixed in 4.x, set status to won't fix.

 [2007-08-27 12:33 UTC] baco at infomaniak dot ch
"The PHP development team hereby announces that support for PHP 4 
will continue until the end of this year only." 

So you need to supported PHP 4 users community until the end of this 
year right ?

I have fixed this bug by backporting mutex changes in gd from 5.2.3 
to 4.4.7. No more Apache2 locks.

Please include my patch in snap 4.4-dev so it can be included the 
next 4.4.8 and change the ticket status to Fixed...

http://www.infomaniak.ch/php4/unix_gd_mutex.patch

Best Regards,
Guy Baconniere

Reproduce code:
---------------

    $crash = 1;
    $text = 'Bug';
    $font = $_SERVER['DOCUMENT_ROOT'] . '/fonts' .'/'. 'arial.ttf';

    if ($crash == 1) {
        $image = imagecreate(64, 32);
    } else {
        $image = imagecreatetruecolor(64, 32);
    }

    $bg = imagecolorallocate($image, 0, 0, 0);
    $fg = imagecolorallocate($image, 255, 255, 255);

    /* LOCK APACHE2 PROCESS AFTER THIS POINT IF crash == 1
     * => if imagecreate() used but not if imagecreatetruecolor()
     */
    imagettftext($image, 20, 0, 8, 24, $fg, $font, $text);

    header('Content-type: image/png');
    imagepng($image);

    imagedestroy($image);

Proposed patch:
---------------
--- ext/gd/config.m4    2007-03-10 14:06:37.000000000 +0100
+++ ext/gd/config.m4    2007-08-27 13:39:51.554453976 +0200
@@ -259,6 +259,7 @@
   PHP_CHECK_LIBRARY(gd, gdCacheCreate,          
[AC_DEFINE(HAVE_GD_CACHE_CREATE,     1, [ ])], [], [ -L$GD_LIB 
$GD_SHARED_LIBADD ])
   PHP_CHECK_LIBRARY(gd, gdFontCacheShutdown,    
[AC_DEFINE(HAVE_GD_FONTCACHESHUTDOWN,1, [ ])], [], [ -L$GD_LIB 
$GD_SHARED_LIBADD ])
   PHP_CHECK_LIBRARY(gd, gdFreeFontCache,        
[AC_DEFINE(HAVE_GD_FREEFONTCACHE,    1, [ ])], [], [ -L$GD_LIB 
$GD_SHARED_LIBADD ])
+  PHP_CHECK_LIBRARY(gd, gdFontCacheMutexSetup,  
[AC_DEFINE(HAVE_GD_FONTMUTEX,        1, [ ])], [], [ -L$GD_LIB 
$GD_SHARED_LIBADD ])
   PHP_CHECK_LIBRARY(gd, gdNewDynamicCtxEx,      
[AC_DEFINE(HAVE_GD_DYNAMIC_CTX_EX,   1, [ ])], [], [ -L$GD_LIB 
$GD_SHARED_LIBADD ])
 ])

--- ext/gd/gd.c 2007-01-01 10:46:42.000000000 +0100
+++ ext/gd/gd.c 2007-08-27 13:42:53.257809726 +0200
@@ -333,6 +328,7 @@
 #if HAVE_LIBT1
        T1_CloseLib();
 #endif
+       gdFontCacheMutexShutdown();
        return SUCCESS;
 }
 /* }}} */
@@ -344,6 +349,7 @@
 {
        le_gd = zend_register_list_destructors_ex(php_free_gd_image, 
NULL, "gd", module_number);
        le_gd_font = 
zend_register_list_destructors_ex(php_free_gd_font, NULL, "gd font", 
module_number);
+       gdFontCacheMutexSetup();
 #if HAVE_LIBT1
        T1_SetBitmapPad(8);
        T1_InitLib(NO_LOGFILE | IGNORE_CONFIGFILE | 
IGNORE_FONTDATABASE);
--- ext/gd/libgd/gd.h   2004-07-23 01:09:24.000000000 +0200
+++ ext/gd/libgd/gd.h   2007-08-27 13:15:04.953547226 +0200
@@ -295,6 +295,14 @@
 void gdImageString16(gdImagePtr im, gdFontPtr f, int x, int y, 
unsigned short *s, int color);
 void gdImageStringUp16(gdImagePtr im, gdFontPtr f, int x, int y, 
unsigned short *s, int color);

+/*
+ * The following functions are required to be called prior to the
+ * use of any sort of threads in a module load / shutdown function
+ * respectively.
+ */
+void gdFontCacheMutexSetup();
+void gdFontCacheMutexShutdown();
+
 /* 2.0.16: for thread-safe use of gdImageStringFT and friends,
  * call this before allowing any thread to call gdImageStringFT.
  * Otherwise it is invoked by the first thread to invoke
--- ext/gd/libgd/gdft.c 2007-03-10 13:51:07.000000000 +0100
+++ ext/gd/libgd/gdft.c 2007-08-27 13:14:35.995737476 +0200
@@ -750,10 +750,8 @@
                  /* find antialised color */

                  tc_key.bgcolor = *pixel;
-                 gdMutexLock(gdFontCacheMutex);
                  tc_elem = (tweencolor_t *) gdCacheGet (tc_cache, 
&tc_key);
                  *pixel = tc_elem->tweencolor;
-                 gdMutexUnlock(gdFontCacheMutex);
                }
            }
        }
@@ -771,30 +769,39 @@

 void gdFontCacheShutdown()
 {
+       gdMutexLock(gdFontCacheMutex);
+
        if (fontCache) {
-               gdMutexLock(gdFontCacheMutex);
                gdCacheDelete(fontCache);
                fontCache = NULL;
-               gdMutexUnlock(gdFontCacheMutex);
-               gdMutexShutdown(gdFontCacheMutex);
                FT_Done_FreeType(library);
        }
+
+       gdMutexUnlock(gdFontCacheMutex);
 }

 void gdFreeFontCache()
 {
        gdFontCacheShutdown();
 }
-
+
+void gdFontCacheMutexSetup()
+{
+       gdMutexSetup(gdFontCacheMutex);
+}
+
+void gdFontCacheMutexShutdown()
+{
+       gdMutexShutdown(gdFontCacheMutex);
+}
+
 int gdFontCacheSetup(void)
 {
        if (fontCache) {
                /* Already set up */
                return 0;
        }
-       gdMutexSetup(gdFontCacheMutex);
        if (FT_Init_FreeType(&library)) {
-               gdMutexShutdown(gdFontCacheMutex);
                return -1;
        }
        fontCache = gdCacheCreate (FONTCACHESIZE, fontTest, 
fontFetch, fontRelease);
@@ -856,15 +863,16 @@

        /***** initialize font library and font cache on first call 
******/

+       gdMutexLock(gdFontCacheMutex);
        if (!fontCache) {
                if (gdFontCacheSetup() != 0) {
                        gdCacheDelete(tc_cache);
+                       gdMutexUnlock(gdFontCacheMutex);
                        return "Failure to initialize font library";
                }
        }
        /*****/

-       gdMutexLock(gdFontCacheMutex);
        /* get the font (via font cache) */
        fontkey.fontlist = fontlist;
        fontkey.library = &library;
 [2007-08-27 16:52 UTC] pajoye@php.net
"--with-ttf --enable-gd-native-ttf "
"Are you sure you need freetype support?"

I meant: do you really need freetype 1.x support?

About your patch, as I said the TS fix will not be back ported to 4.x

There is many other issues to be fixed in php4 to get somehow thread safe. I'll ask our release master about this patch but you should really think about upgrading to php5. Using php4 with apache2 (in threaded mode) is really not a good idea.
 [2007-08-27 17:49 UTC] baco at infomaniak dot ch
Yes, our customers are using both freetype 
1.x and 2.x calls. We can't stop support
old calls.

If you disable both "--with-ttf" and 
"--enable-gd-native-ttf" apache2 are also
locked by calling imagefttext() when
imagecreate() is used.

We are a web hosting provider and some of our 
customers are using PHP scripts who are not 
(yet) compatible with PHP 5 so we need to 
provide both PHP5 or PHP4 web servers until 
the end of this year.

Apache2 MPM use less memory. We want to use
it on all PHP5 and PHP4 servers to handle more
simultaneous web connections.

For info, the bug is not present when 
tpixels/TrueColor is used in gdImageCreate
another patch (for testing purpose only) 
make my sample script avoid locking Apache2 
but the bug is related to proper mutex in 
font calls so the best patch is my previous
unix_gd_mutex.patch.

--- ext/gd/libgd/gd.c   2007-04-14 19:38:38.000000000 +0200
+++ ext/gd/libgd/gd.c   2007-08-27 11:46:21.648861476 +0200
@@ -120,12 +120,13 @@

 gdImagePtr gdImageCreate (int sx, int sy)
 {
+       int x, y, white;
        int i;
        gdImagePtr im;
        im = (gdImage *) gdMalloc(sizeof(gdImage));
        memset(im, 0, sizeof(gdImage));
        /* Row-major ever since gd 1.3 */
-       im->pixels = (unsigned char **) safe_emalloc(sizeof(unsigned 
char *), sy, 0);
+       im->tpixels = (int **) safe_emalloc(sizeof(int *), sy, 0);
        im->AA_opacity = (unsigned char **) 
safe_emalloc(sizeof(unsigned char *), sy, 0);
        im->polyInts = 0;
        im->polyAllocated = 0;
@@ -134,29 +135,27 @@
        im->style = 0;
        for (i = 0; i < sy; i++) {
                /* Row-major ever since gd 1.3 */
-               im->pixels[i] = (unsigned char *) gdCalloc(sx, 
sizeof(unsigned char));
+               im->tpixels[i] = (int *) gdCalloc(sx, sizeof(int));
                im->AA_opacity[i] = (unsigned char *) gdCalloc(sx, 
sizeof(unsigned char));
        }
        im->sx = sx;
        im->sy = sy;
-       im->colorsTotal = 0;
        im->transparent = (-1);
        im->interlace = 0;
        im->thick = 1;
        im->AA = 0;
        im->AA_polygon = 0;
-       for (i = 0; i < gdMaxColors; i++) {
-               im->open[i] = 1;
-               im->red[i] = 0;
-               im->green[i] = 0;
-               im->blue[i] = 0;
-       }
-       im->trueColor = 0;
-       im->tpixels = 0;
+       im->trueColor = 1;
        im->cx1 = 0;
        im->cy1 = 0;
        im->cx2 = im->sx - 1;
        im->cy2 = im->sy - 1;
+       white = gdImageColorAllocate (im, 255, 255, 255);
+       for (x = 0; x < sx; x++) {
+               for (y = 0; y < sy; y++) {
+                       gdImageSetPixel(im, x, y, white);
+               }
+       }
        return im;
 }
 [2007-08-27 18:32 UTC] pajoye@php.net
I appreciate your effort to provide patches but the problem is _not_ in gdImageCreate or gdImageCreateTrueColor.

About php4, we are not going to apply these patches. It is now a sure thing.

Freetype1 is not supported anymore since years, it is a dead project and have hundred of issues. Mixing both mpm and freetype1 is a call for troubles.

I think I have you all infos you need to take the right choices. I suggest you to do not apply the gdImageCreate patch, it is not the source of the problem and it breaks so many things.

I'm sorry but there is no need to reply to this post or to add comments. The status won't change.
 [2007-08-27 19:13 UTC] baco at infomaniak dot ch
...
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Tue Apr 23 08:01:30 2024 UTC