php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #56351 APC segfaults while trying to cache a page
Submitted: 2005-03-17 06:57 UTC Modified: 2005-11-22 04:37 UTC
From: boro at fixel dot org Assigned:
Status: Closed Package: APC (PECL)
PHP Version: 4.3.10 OS: Linux 2.6 (Debian Sarge)
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:
47 + 37 = ?
Subscribe to this entry?

 
 [2005-03-17 06:57 UTC] boro at fixel dot org
Description:
------------
I have Debian Sarge installed including Debian packaged Apache2 and PHP4 (4.3.10). I installed APC using Pear (pear install apc). APC was installed fine. I then added

extension=apc.so
apc.enabled = 1
apc.shm_segments = 2
apc.shm_size = 32
apc.gc_ttl = 3600

to my php.ini and restarted Apache. Apache seemed to start fine. I then tried to access a page made with PHP, but the Apache child which takes care of the request segfaults: 

[Thu Mar 17 12:34:18 2005] [notice] child pid 7163 exit signal Segmentation fault (11)

Disabling APC makes it work again. I then used gdb to check one of the childs where it segfaults:

Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread -1213722496 (LWP 7167)]
0xb713ed8d in my_copy_class_entry (dst=0xb5150e48, src=0x82924e8, allocate=0xb7141200 <apc_sma_malloc>)
    at /root/APC-2.0.4/apc_compile.c:369
369             for (n = 0; src->builtin_functions[n].fname != NULL; n++) {}

I downloaded the source code of APC manually, run phpize and ./configure, removed -O2 optimization from Makefile and compiled & installed. Now APC worked.

I decided to try running Apache2 under Valgrind (when compiled with -O2) to check if there's some memory management problem, and got this:

==11930== Conditional jump or move depends on uninitialised value(s)
==11930==    at 0x1CDACD80: my_copy_class_entry (apc_compile.c:366)
==11930==    by 0x1CDAD651: apc_copy_new_classes (apc_compile.c:639)
==11930==    by 0x1CDAE30E: my_compile_file (apc_main.c:185)
==11930==    by 0x1C130BAE: execute (in /usr/lib/apache2/modules/libphp4.so)
==11930==
==11930== Use of uninitialised value of size 4
==11930==    at 0x1CDACD8D: my_copy_class_entry (apc_compile.c:370)
==11930==    by 0x1CDAD651: apc_copy_new_classes (apc_compile.c:639)
==11930==    by 0x1CDAE30E: my_compile_file (apc_main.c:185)
==11930==    by 0x1C130BAE: execute (in /usr/lib/apache2/modules/libphp4.so)
==11930==
==11930== Invalid read of size 4
==11930==    at 0x1CDACD8D: my_copy_class_entry (apc_compile.c:370)
==11930==    by 0x1CDAD651: apc_copy_new_classes (apc_compile.c:639)
==11930==    by 0x1CDAE30E: my_compile_file (apc_main.c:185)
==11930==    by 0x1C130BAE: execute (in /usr/lib/apache2/modules/libphp4.so)
==11930==  Address 0xFFFFFFB8 is not stack'd, malloc'd or (recently) free'd
--11930-- adding signal 11 to pending set

When run under Valgrind without optimizations, I only the next message instead of the previous ones:

==13403== Conditional jump or move depends on uninitialised value(s)
==13403==    at 0x1CDAD1F7: my_copy_class_entry (apc_compile.c:366)
==13403==    by 0x1CDADCCA: apc_copy_new_classes (apc_compile.c:639)
==13403==    by 0x1CDAEB24: my_compile_file (apc_main.c:185)
==13403==    by 0x1C130BAE: execute (in /usr/lib/apache2/modules/libphp4.so)

APC compiled with "-O" doesn't work either. My gcc version is "gcc version 3.3.5 (Debian 1:3.3.5-8)".

Note: In the end I noticed that if using gcc-3.4 on Sarge (gcc version 3.4.4 20041218 (prerelease) (Debian 3.4.3-6)), -O2 didn't make APC segfault. I wonder if this is some kind of compiler problem.

Expected result:
----------------
APC should not segfault.

Actual result:
--------------
APC segfaults when installed as is.

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2005-03-17 08:22 UTC] boro at fixel dot org
Correction: Using gcc 3.4 wont help afterall. For some odd reason APC 2.0.4 build on one system with gcc 3.4 worked, but on other almost identical system it doesn't help. Removing "-O2" optimization still helps.
 [2005-03-17 12:08 UTC] boro at fixel dot org
Another: Removing -O2 only helps by chance. Results seem very random.
 [2005-04-08 13:22 UTC] xuefer at 21cn dot com
i'll send you one by mail

Index: apc_compile.c
===================================================================
RCS file: /repository/pecl/apc/apc_compile.c,v
retrieving revision 3.14
diff -u -r3.14 apc_compile.c
--- apc_compile.c   6 Nov 2004 18:12:10 -0000   3.14
+++ apc_compile.c   8 Apr 2005 17:20:33 -0000
@@ -16,6 +16,7 @@
 
 /* $Id: apc_compile.c,v 3.14 2004/11/06 18:12:10 rasmus Exp $ */
 
+#include "apc.h"
 #include "apc_compile.h"
 #include "apc_globals.h"
 #include "apc_zend.h"
@@ -371,6 +372,12 @@
 
     /* Start with a bitwise copy */
     memcpy(dst, src, sizeof(src[0]));
+    /* only initized & used for internal class
+     * php failed to initize it for user class, crash if u copy it
+     * see Zend/zend_compile.c
+     *     .handle_function_call = NULL; but no builtin_functions initized
+     * dst->builtin_functions = 0;
+     * */
 
     if (src->name) {
         if(!(dst->name = apc_xstrdup(src->name, allocate))) {
@@ -411,43 +418,6 @@
         if(local_dst_alloc) deallocate(dst);
         return NULL;
     }
-
-    if (src->builtin_functions) {
-        int i, n;
-
-        for (n = 0; src->builtin_functions[n].fname != NULL; n++) {}
-
-        if(!(dst->builtin_functions =
-            (zend_function_entry*)
-                allocate((n + 1) * sizeof(zend_function_entry)))) {
-            if(src->name) deallocate(dst->name);
-            deallocate(dst->refcount);
-            my_destroy_hashtable(&dst->function_table, (ht_free_fun_t)my_free_f                                                              unction, deallocate);
-            my_destroy_hashtable(&dst->default_properties, (ht_free_fun_t)my_fr                                                              ee_zval_ptr, deallocate);
-            if(local_dst_alloc) deallocate(dst);
-            return NULL;
-        }
-
-
-        for (i = 0; i < n; i++) {
-            if(!my_copy_function_entry(&dst->builtin_functions[i],
-                                   &src->builtin_functions[i],
-                                   allocate, deallocate)) {
-                int ii;
-
-                for(ii=i-1; i>=0; i--) my_destroy_function_entry(&dst->builtin_                                                              functions[ii], deallocate);
-                if(src->name) deallocate(dst->name);
-                deallocate(dst->refcount);
-                my_destroy_hashtable(&dst->function_table, (ht_free_fun_t)my_fr                                                              ee_function, deallocate);
-                my_destroy_hashtable(&dst->default_properties, (ht_free_fun_t)m                                                              y_free_zval_ptr, deallocate);
-                if(local_dst_alloc) deallocate(dst);
-                return NULL;
-            }
-        }
-
-        dst->builtin_functions[n].fname = NULL;
-    }
-
     return dst;
 }
 /* }}} */
@@ -980,8 +950,6 @@
 /* {{{ my_destroy_class_entry */
 static void my_destroy_class_entry(zend_class_entry* src, apc_free_t deallocate                                                              )
 {
-    int i;
-
     assert(src != NULL);
 
     deallocate(src->name);
@@ -994,13 +962,6 @@
     my_destroy_hashtable(&src->default_properties,
                          (ht_free_fun_t) my_free_zval_ptr,
                          deallocate);
-
-    if (src->builtin_functions) {
-        for (i = 0; src->builtin_functions[i].fname != NULL; i++) {
-            my_destroy_function_entry(&src->builtin_functions[i], deallocate);
-        }
-        deallocate(src->builtin_functions);
-    }
 }
 /* }}} */
 [2005-04-08 13:27 UTC] rasmus@php.net
What are you trying to fix with this patch?

Boro, does this happen with the current CVS version as well?
 [2005-04-08 15:43 UTC] boro at fixel dot org
Rasmus, I would love to try the CVS version, but it doesn't compile. My GCC is 3.3.5 and PHP is 4.3.10. I first run phpize for the source from CVS and then ./configure && make. Make fails first when some file is trying to #include httpd.h. I had to add paths of httpd.h and apr.h to Makefile's INCLUDES file so that it works. After that, the compilation stops here:

--- snip snip ---
 gcc -I. -I/root/pecl/apc -DPHP_ATOM_INC -I/root/pecl/apc/include -I/root/pecl/apc/main -I/root/pecl/apc -I/usr/include/php4 -I/usr/in clude/php4/main -I/usr/include/php4/Zend -I/usr/include/php4/TSRM -I/usr/include/apache2 -I/usr/include/apr-0 -DHAVE_CONFIG_H -g -O2 - c /root/pecl/apc/php_apc.c  -fPIC -DPIC -o .libs/php_apc.o
/root/pecl/apc/php_apc.c:99: error: parse error before "zend_apc_globals"
/root/pecl/apc/php_apc.c:99: error: initializer element is not constant
/root/pecl/apc/php_apc.c:99: error: (near initialization for `ini_entries[0].mh_arg1')
/root/pecl/apc/php_apc.c:99: error: initializer element is not constant
/root/pecl/apc/php_apc.c:99: error: (near initialization for `ini_entries[0]')
/root/pecl/apc/php_apc.c:100: error: parse error before "zend_apc_globals"
/root/pecl/apc/php_apc.c:100: error: initializer element is not constant
/root/pecl/apc/php_apc.c:100: error: (near initialization for `ini_entries[1].mh_arg1')
/root/pecl/apc/php_apc.c:100: error: initializer element is not constant
/root/pecl/apc/php_apc.c:100: error: (near initialization for `ini_entries[1]')
...even more similar errors...
--- snip snip ---
 [2005-04-08 15:45 UTC] rasmus@php.net
Did you read the docs?

The INSTALL file says:

Temporary Apache httpd.h problem
--------------------------------
A better solution is on the way for this, but for now if you get an error
about not being able to find httpd.h, figure out where it is on your system
(if you don't have it, install the apache_dev package for your OS) and do:
  export CPPFLAGS=-I/usr/include/apache-1.3  (for bash on Debian)
  setenv CPPFLAGS -I/usr/include/apache-1.3  (for tsch on Debian)
and then re-run your configure script.

This dependency of APC on httpd.h will disappear in a future version of PHP
 [2005-04-08 15:54 UTC] boro at fixel dot org
Rasmus: Yeah, I have read the INSTALL file, just mentioned that silly thing again 'cos I didn't remember it was mentioned in the INSTALL file. It's couple weeks when I last tried the CVS version and didn't read the docs again for trying if it would work now. :-) But what about the actual compilation problem?

Xuefer: Your patch seems to remove the function caching for classes as far as I can understand. Can you tell if there's any other side effects from this than the speed decrease? Does Zend "recompile" the missing functions when the script is run?
 [2005-04-08 15:59 UTC] rasmus@php.net
Well, I don't know if you built it correctly.  Build it as described in the INSTALL file and I will have a look.  I am assuming non-threaded Apache1 or Apache2-prefork here.  Anything else will likely not work.
 [2005-04-08 16:05 UTC] boro at fixel dot org
Rasmus: Yeah, I'm using Apache2 prefork. I couldn't use the INSTALL file's example because Apache2's httpd.h also needs apr.h and it's in different directory on Debian, so I used:

CPPFLAGS="-I/usr/include/apache2 -I/usr/include/apr-0" ./configure && make

The problem of course stays the same either way I do it, modify the Makefile or define the missing includes on command line.
 [2005-04-08 16:28 UTC] rasmus@php.net
Line 99 of php_apc.c is:

STD_PHP_INI_ENTRY("apc.enabled",        "1",    PHP_INI_SYSTEM, OnUpdateInt,            enabled,        zend_apc_globals, apc_globals)

Should probably be a boolean there instead, but that doesn't change anything.  This should compile fine as long as you are not in ZTS mode.  The Debian PHP port maintainer had an insanity episode where he enabled ZTS for no reason.  He has since reversed that, but perhaps your phpize enables ZTS and thus TSRM?
 [2005-04-08 16:40 UTC] boro at fixel dot org
Ah, that explains. I'm using Debian Sarge (testing) and the reversed package (version 4.3.8-10) is only in unstable's pool at the moment.  I'll upgrade to the reversed version and try compiling again. Thanks.
 [2005-04-08 17:17 UTC] boro at fixel dot org
Ah, I of course meant "4.3.10-10", not "4.3.8-10".

Anyway, I upgraded to PHP to 4.3.10-10 and ZTS is now gone. I tested it by reinstalling previously installed radius PECL module using pear and it works correctly: PHP doesn't complain it being thread-safe version and refuse loading it. The problem is that phpize still enables TSRM even tho' I also upgraded php4-dev package to the same ZTS-reversed version 4.3.10-10. I can see -I/usr/include/php4/TSRM in gcc's line and the compilation fails just like before.

Is there any easy way to disable TSRM? Where does phpize get the disable/enable setting for the TSRM anyway?
 [2005-04-08 17:27 UTC] rasmus@php.net
The easiest would be to just stop using these broken packages and compile your own PHP.  But that include line is fine.  It should be there.  If you look at TSRM.h you will see it only starts messing with your globals if ZTS is defined.  So, make sure you have a clean tree.  "make clean" or fetch a fresh copy from CVS.  Run phpize again and make sure nothing is defining ZTS on you.
 [2005-04-20 22:28 UTC] srouleau at innobec dot com
I went through the same ordeal as boro.  I'm also on Sarge, yada yada yada.

After sprinkling #undef ZTS all over the place and the like, I finally got it to work by commenting out one line out of php_apc.c (from CVS):

#if HAVE_APACHE
// #undef XtOffsetOf
#include "httpd.h"
#endif

It now compiles, phpinfo() lists APC running, and I get get through Horde's IMP without segfaulting.  Before I could load a few pages, but when I'd try to view a message it'd just segfault.  I cannot say I've seen a performance increase (yet).  And I know this is not a fix per-se, it's just a temporary workaround-on-top-of-the-httpd.h-fix.

I hope this helps.
 [2005-04-21 02:50 UTC] boro at fixel dot org
Woah, thanks srouleau. That was all that was needed to get it compile with Debian packaged PHP (version 4.3.10-10, the current ZTS disabled version). It seems that the problem is not with the PHP, but with APC that expects httpd.h to define XtOffsetOf. Quite logical :-) Maybe configure should check this?

Anyway, I'll now try the CVS version with Moodle (http://www.moodle.org) and report back how it worked.
 [2005-04-21 14:25 UTC] boro at fixel dot org
Srouleau, what's your status with CVS version of APC?

I'm having difficulties getting it to cache anything. First I thought it works fine, but later I began to suspect that it's not doing anything. I created apcinfo.php which uses the PHP functions provided by the APC module. It prints out  statistics of APC and all the cached files. The problem is that the list is empty. Also num_hits and num_misses stays zero. I used the same php.ini settings as described in my first submission.
 [2005-04-21 20:17 UTC] rasmus@php.net
You don't need to write your own apcinfo script.  There is one in CVS called apc.php.  Just use that.  If you can put that on your server and send me the URL I can have a look.
 [2005-04-21 20:59 UTC] srouleau at innobec dot com
Boro,

I've noticed a bunch of .php_apc files scattered all over my webserver, but I haven't actually noticed any speedup/slowdown.  

But now that ramus pointed out the apc.php file I'll give that a try -- this is exactly what I wanted to see.  I'll report back when I've had a chance to try it out, later tonight hopefully.
 [2005-04-21 21:05 UTC] srouleau at innobec dot com
Hmm, actually I don't know what I was smoking, I can't seem to find any _apc files now.  

Anyway, I really have something else to do now, after which I'll report back.  :)
 [2005-04-22 03:31 UTC] boro at fixel dot org
Here's the url of the apc.php script which comes with APC (I removed the cache clearing functionality for the server's safety): https://153.1.200.2/apc.php. But that doesn't actually tell much. I guess I'll start to insert some debugging statements to the source code to see what is happening.
 [2005-04-22 03:38 UTC] rasmus@php.net
extension=apc.so
I compile it like this:

CPPFLAGS=-I/usr/include/apache-1.3 ./configure --enable-apc --enable-mmap

And my config is:

apc.enabled=1
apc.shm_segments=1
apc.optimization=0
apc.shm_size=64
apc.ttl=7200
apc.user_ttl=7200
apc.num_files_hint=2000
apc.mmap_file_mask=/tmp/apc.XXXXXX

Try copying that, especially the --enable-mmap and mmap_file_mask parts.
 [2005-04-22 04:01 UTC] boro at fixel dot org
Okay, here's the procedure I used. First I ran configure:

CPPFLAGS="-I/usr/include/apache2 -I/usr/include/apr-0" ./configure --enable-apc --enable-mmap

Then I commented "#undef XtOffsetOf" out from php_apc.c and compiled with "make".

Here's the current APC configuration:

extension=apc.so
apc.enabled=1
apc.shm_segments=1
apc.shm_size=30
apc.ttl=7200
apc.user_ttl=7200
apc.optimization=0
apc.num_files_hint=2000
apc.mmap_file_mask=/tmp/apc.XXXXXX

It still does nothing. I used lsof to check whether it creates the mmap file. It does:

apache2 15797 DEL   REG    786893 /tmp/apc.oPhall
apache2 15797 11u   REG 0  786890 /tmp/.apc.15788 (deleted)
apache2 15797 12u   REG 0  787121 /tmp/.apc.15788 (deleted)
apache2 15797 13u   REG 0  787124 /tmp/.apc.15788 (deleted)
 [2005-04-22 04:04 UTC] rasmus@php.net
Could be an Apache2 thing I suppose.  I have never tried it with Apache2.
 [2005-04-22 08:57 UTC] srouleau at innobec dot com
I too am running this on apache2, and the apc.php is giving me no files being cached.

Regardin the _apc files that were scattered around, they were in my old Mantis folder, and may have been left over from the 'good old days' when I was running Debian's php4-apc module from Woody.

I'm not running the mmap version though, just the standard version.

Naturally, phpinfo() is showing apc 'enabled'.

Are there any special settings to be set in apache for this, or is it supposed to be strictly a php thing?  

Finally, is there any setting / switch / compile-time flag to enable some sort of logging?  If not, I guess I'll just go ahead and sprinkle some myself in my version and attempt to see what's going on.
 [2005-06-01 23:10 UTC] xuefer at 21cn dot com
the question is: do you really need to copy builtin_functions?
for user defined classes, isn't it just nonsense?
for internal classes, isn't it just point to a place on .TEXT?
 [2005-11-22 04:37 UTC] boro at fixel dot org
This seems to be fixed in some version between 2.0.4 and 3.0.8, so I'm closing this one. 3.0.8 compiled without hasles and Moodle (www.moodle.org) seems to run fine with it.
 
PHP Copyright © 2001-2022 The PHP Group
All rights reserved.
Last updated: Tue May 17 05:05:45 2022 UTC