php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #58763 APC causes object destruction / session writing timing behavior to change
Submitted: 2009-07-15 02:05 UTC Modified: 2010-02-23 13:13 UTC
From: capps at solareclipse dot net Assigned:
Status: Not a bug Package: APC (PECL)
PHP Version: 5.3.0RC4 OS: CentOS 5.x
Private report: No CVE-ID:
 [2009-07-15 02:05 UTC] capps at solareclipse dot net
Description:
------------
Greetings,

I am using a database-backed session handler.  In 5.3, without APC enabled, the session handler's write function fires properly, and data is written to the database.

When APC is enabled, at least one of the following situations is true:
1) Object destruction for the session handler occurs before session write, causing writes to fail
2) Object destruction for the database handler occurs before session write, causing writes to fail
3) Script shutdown occurs before calling session write

*I am completely aware that PHP changed the order of destruction operations in the 5.x releases so that objects may end up being destroyed before sessions are written.  I want to re-iterate that this problem occurs if and only if APC is enabled.  The code operates normally and correctly when APC is disabled.*

Notes:
- PHP version is 5.3.0, though only RC4 is listed in the drop-down.  The code works properly under 5.2 and 5.1, though I can not test with APC and those versions.
- No other PECL packages are installed
- My session handler is lengthy and application-specific, and contains proprietary code that I can not release due to NDA.
- The DB object is Zend_Db.
- The only changes to the stock 5.3 php.ini are setting the timezone, enabling short open tags, and turning off expose_php.
- My configure line, because it's been asked for above:
'./configure'  '--build=i686-redhat-linux-gnu' '--host=i686-redhat-linux-gnu' '--target=i386-redhat-linux-gnu' '--program-prefix=' '--prefix=/usr' '--exec-prefix=/usr' '--bindir=/usr/bin' '--sbindir=/usr/sbin' '--sysconfdir=/etc' '--datadir=/usr/share' '--includedir=/usr/include' '--libdir=/usr/lib' '--libexecdir=/usr/libexec' '--localstatedir=/var' '--sharedstatedir=/usr/com' '--mandir=/usr/share/man' '--infodir=/usr/share/info' '--cache-file=../config.cache' '--with-libdir=lib' '--with-config-file-path=/etc' '--with-config-file-scan-dir=/etc/php.d' '--disable-debug' '--with-pic' '--disable-rpath' '--without-pear' '--with-bz2' '--with-exec-dir=/usr/bin' '--with-freetype-dir=/usr' '--with-png-dir=/usr' '--with-xpm-dir=/usr' '--enable-gd-native-ttf' '--with-t1lib=/usr' '--without-gdbm' '--with-gettext' '--with-gmp' '--with-iconv' '--with-jpeg-dir=/usr' '--with-openssl' '--with-zlib' '--with-layout=GNU' '--enable-exif' '--enable-ftp' '--enable-magic-quotes' '--enable-sockets' '--enable-sysvsem' '--enable-sysvshm' '--enable-sysvmsg' '--with-kerberos' '--enable-ucd-snmp-hack' '--enable-shmop' '--enable-calendar' '--with-libxml-dir=/usr' '--enable-xml' '--with-system-tzdata' '--with-mime-magic=/usr/share/file/magic' '--with-apxs2=/usr/sbin/apxs' '--without-mysql' '--without-gd' '--disable-dom' '--disable-dba' '--without-unixODBC' '--disable-pdo' '--disable-xmlreader' '--disable-xmlwriter' '--without-sqlite' '--without-sqlite3' '--disable-phar' '--disable-fileinfo' '--disable-json' '--without-pspell' '--disable-wddx' '--without-curl' '--disable-posix' '--disable-sysvmsg' '--disable-sysvshm' '--disable-sysvsem' 


As mentioned, I can't post my session object code due to NDA, but I'm sure that any object-based session handler copied from any tutorial on the matter will show similar behavior.  The code works normally and correctly in PHP 5.1, 5.2, and 5.3, and only malfunctions under 5.3 with APC enabled.

My normal workaround for the PHP-changed-object-destruct-order issue is to add a __destruct function to the database object that calls session_write_close, under the blind assumption that it's being destroyed first and it's time to perform a session save.  Because I'm using third party code (Zend_Db), I can't do that easily.

Another method to work around the madness, and one that works in this case is posted in the Reproduce Code form in this bug submission.

**Again, I am entirely aware of PHP's destruct order fun.  I am not reporting that PHP issue.  The behavior I am seeing here only occurs when APC is switched on, so this is an APC issue.**  This may end up just having to be a documentation issue.

Reproduce code:
---------------
register_shutdown_function(
    create_function('$db_object,$session_object',
                    'session_write_close();'
    ), 
    $db_object, 
    $session_object
);
// While the database object and session object are passed in, they are not used.
// With any luck, PHP notices this and holds off on their destruction until the shutdown function can run.
// This seems to work in practice, but I don't know if that's the required voodoo.


Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2009-07-15 08:05 UTC] gopalv82 at yahoo dot com
if you feel like building up your own apc install, comment out the code in apc_deactivate() function and try this again?

apc uses a lot of refcount magic to avoid allocating memory while loading data out of cache, this code prevents zend from deallocating memory allocated by apc.

see if that bit of code is causing your problem by commenting it out.
 [2009-07-16 00:08 UTC] capps at solareclipse dot net
Thanks for the feedback.

After removing the body of apc_deactivate in apc_main.c and recompiling, the behavior no longer occurs.
 [2009-07-16 00:10 UTC] capps at solareclipse dot net
Also, I don't intend to run in production with the code commented out -- the above PHP-level workaround works well enough.  I'm more curious as to if this will cause other problems elsewhere and thus should be investigated further.  In other words, should I try to come up with a test case?
 [2009-08-26 09:41 UTC] denis dot gasparin at edistar dot com
I had a similar problem. We are using php file-based sessions but the wakeup order from the session was different from that of non cached php.

Commenting out code in apc_deactive solved the problem.
I tested with 3.0.19 and 3.1.3p1.
Like Capps, i'm curious if this will cause other problems elsewhere.
 [2009-11-20 09:36 UTC] prgarcial at gmail dot com
Same problem here. We are using: 

CentOS 5.4 (fully updated)
php-5.2.11 with the patch provided in http://bugs.php.net/bug.php?id=49098
HTTP_Session2-0.7.2
MDB2-2.5.0b1
MDB2_Driver_mysqli-1.5.0b1
APC 3.1.3p1

This is the code used to reproduce the error.

A.php
------
<?php

/*
CREATE TABLE `_session_data` (
  `id` char(32) NOT NULL,
  `expiry` int(10) unsigned NOT NULL,
  `data` text NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
*/

require_once 'HTTP/Session2.php';

$dsn = 'mysqli://user:pass@localhost/dbname';

$options = array();
$options['dsn']   = $dsn;
$options['table'] = '_session_data';

HTTP_Session2::setContainer('MDB2', $options);
HTTP_Session2::start('mysess');

?>

If apc is enabled and you load A.php more than once, it returns the following error: 
"Fatal error: Class 'PEAR' not found in MDB2/Driver/mysqli.php on line 495"

We have tested it with APC 3.0.19 as well and we got the same result.

If APC is disabled it works fine. It also works fine with php 5.2.9 and APC 3.0.9.

After commenting out the code of apc_deactive() in apc_main.c, it works without problems.
Like Capps and Denis, I wonder if it safe to run APC with this part of the code commented out.
 [2009-12-04 15:02 UTC] joel at purerave dot com
Took me a few hours to track the problem down to it being APC exactly as described in this bug.

Was working fine on PHP 5.2.8 with APC, but a new install on CentOS with PHP 5.3.1 and APC 3.1.3p1 breaks the DB session handler.
 [2009-12-09 14:10 UTC] samm at os2 dot kiev dot ua
Same with APC+PHP 5.2.11 on CentOS. Disabling APC caching for the virtualhost solves the problem
 [2010-02-11 14:18 UTC] sdiebler at qualys dot com
I have the same issue with php-5.2.10 and apc-3.0.19 (RHEL-
4U4).
If it worked fine with php-5.2.8 as Joel mentioned, what 
changed in PHP that lead to the problem and can it be 
reverted?
 [2010-02-18 10:39 UTC] miroslav at ansta dot co dot uk
Same here CentOS 5, PHP 5.2.11, ACP 3.0.19
 [2010-02-23 13:05 UTC] mgenereu at gmail dot com
Confirmed on PHP 5.2.11 and ACP 3.0.19 here.  How can I help 
with this?
 [2010-02-23 13:13 UTC] rasmus@php.net
This really isn't an APC issue.  A call to 
session_write_close() in your PHP code will fix this.
The documentation has had a big warning about this for a 
couple of years now:

http://php.net/manual/en/function.session-set-save-
handler.php

There is also talk about a better implementation at the PHP 
level.  Extensions other than APC suffer from this as well.

You can read more about it here:

http://news.php.net/php.internals/46999
 [2010-02-25 04:53 UTC] pgarcial at gmail dot com
Thanks Rasmus

I've fixed HTTP_Sessions2 and it is working fine again.
 
PHP Copyright © 2001-2014 The PHP Group
All rights reserved.
Last updated: Sat Apr 19 17:01:54 2014 UTC