Edit report at https://bugs.php.net/bug.php?id=64722&edit=1
ID: 64722
Comment by: tj dot botha at plista dot com
Reported by: tj dot botha at plista dot com
Summary: PDO extension causes zend_mm_heap corrupted
Status: Feedback
Type: Bug
Package: PDO related
Operating System: Ubuntu Server 12.10
PHP Version: master-Git-2013-04-26 (Git)
Block user comment: N
Private report: N
New Comment:
Even more correct:
ZEND_API void zend_object_std_dtor(zend_object *object TSRMLS_DC)
{
if (object->guards) {
zend_hash_destroy(object->guards);
FREE_HASHTABLE(object->guards);
object->guards = NULL;
}
if (object->properties) {
zend_hash_destroy(object->properties);
FREE_HASHTABLE(object->properties);
object->properties = NULL;
}
if (object->properties_table) {
int i;
for (i = 0; i < object->ce->default_properties_count; i++) {
if (object->properties_table[i]) {
zval_ptr_dtor(&object->properties_table[i]);
object->properties_table[i] = NULL;
}
}
efree(object->properties_table);
object->properties_table = NULL;
}
}
Previous Comments:
------------------------------------------------------------------------
[2013-05-02 14:42:26] tj dot botha at plista dot com
In my mind, the correct function should look like this (without knowing the
exact context in which it runs)
//source_code/Zend/zend_objects.c:
ZEND_API void zend_object_std_dtor(zend_object *object TSRMLS_DC)
{
if (object->guards) {
zend_hash_destroy(object->guards);
FREE_HASHTABLE(object->guards);
}
if (object->properties) {
zend_hash_destroy(object->properties);
FREE_HASHTABLE(object->properties);
}
if (object->properties_table) {
int i;
for (i = 0; i < object->ce->default_properties_count; i++) {
if (object->properties_table[i]) {
zval_ptr_dtor(&object->properties_table[i]);
object->properties_table[i] = NULL;
}
}
efree(object->properties_table);
object->properties_table = NULL;
}
}
However, this appears in my apache logs, only when running in debug mode:
[Thu May 02 16:41:28.476657 2013] [auth_digest:notice] [pid 23396] AH01757:
generating secret for digest authentication ...
[Thu May 02 16:41:29.052276 2013] [ssl:warn] [pid 23396] AH01873: Init: Session
Cache is not configured [hint: SSLSessionCache]
[Thu May 02 16:41:29.052747 2013] [lbmethod_heartbeat:notice] [pid 23396]
AH02282: No slotmem from mod_heartmonitor
[Thu May 02 16:41:29.141345 2013] [core:warn] [pid 23396] AH00098: pid file
/usr/local/apache2/logs/httpd.pid overwritten -- Unclean shutdown of previous
Apache run?
[Thu May 2 16:41:35 2013] Script: '/.../index.php'
/home/tj/php-5.4.14/Zend/zend_API.c(1127) : Freeing 0x7FFFE89B6050 (16 bytes),
script=/usr/local/apache2/htdocs/www/plista/www.2.3.2/app/webroot/index.php
=== Total 1 memory leaks detected ===
But the project loads without problems.
------------------------------------------------------------------------
[2013-05-02 13:51:47] tj dot botha at plista dot com
Hey guys - I have run various tests - using valgrind I did not find anything.
I have debugged the code, and I have narrowed down the problem.
It is not a race condition, the problem is dangling pointers are getting freed:
below is still okay:
//php_source/ext/pdo/pdo_dbh.c
static void pdo_dbh_free_storage(pdo_dbh_t *dbh TSRMLS_DC)
{
...
zend_object_std_dtor(&dbh->std TSRMLS_CC);
dbh->std.properties = NULL;
...
}
The problem arrives here in zend_object_std_dtor, in
php_source/Zend/zend_objects.c
The situation can be recreated when a zend_object has properties AND a
properties_table
Look at the code below:
In my case, the below function gets called TWICE:
ZEND_API void zend_object_std_dtor(zend_object *object TSRMLS_DC)
{
if (object->guards) {
zend_hash_destroy(object->guards);
FREE_HASHTABLE(object->guards);
}
if (object->properties) {
zend_hash_destroy(object->properties);
FREE_HASHTABLE(object->properties);
if (object->properties_table) {
efree(object->properties_table);
}
} else if (object->properties_table) {
int i;
for (i = 0; i < object->ce->default_properties_count; i++) {
if (object->properties_table[i]) {
zval_ptr_dtor(&object->properties_table[i]);
}
}
efree(object->properties_table);
}
}
The important bits are:
...
if (object->properties)
{
...
if (object->properties_table) {
efree(object_properties_table); //this creates dangling
pointers 0x5a5a5a5a5a5a5a5a
//Now, object->properties_table[0, 1, 2, ... n] are all
dangling pointers
}
...
} else if (object->properties_table)
{
...
//now the second time this function gets called, at some point during the
zval_ptr_dtor call on object-
>properties_table[i], a function tries to decrease the ref val on the dangling
>pointer, and this causes SIGSEGV 11
(zend_mm_heap corrupted)
...
}
I do not know what the correct behavior should be.
I have tried removing the "else if" and then setting the properties_table to
NULL after de-allocation and forcing de-
allocation of both, however different modifications to the code have lead to
different problems and I do not seem to
find a 100% correct solution. The solution I had in mind to work perfect lead
to for example:
/home/tj/php-5.4.14/Zend/zend_API.c(1127) : Freeing 0x7FFFE89B6418 (16 bytes),
script=/.../index.php
=== Total 1 memory leaks detected ===
I do not know if the function should indeed be called twice, or whether the
object should only contain properties or
properties_table and not both, and why the properties_table does not get set to
NULL after being de-allocated, as
well as the other properties_table[] pointers.
In either way - it turns out that this situation is created because we are
extending the PDO class in PHP, and adding
custom properties and methods.
I will still investigate further - but I will really appreciate some advice /
help!
------------------------------------------------------------------------
[2013-05-01 13:05:43] [email protected]
if you can reproduce it in a 100% chance, please run it with valgrind, let's
see
what valgrind says about this..
thanks
------------------------------------------------------------------------
[2013-04-30 16:16:29] tj dot botha at plista dot com
Ok - I just recompiled apache with prefork (It was supposed to be the default,
instead it defaulted to event) - and recompiled PHP, and it is no longer
multithreaded - and the problem persists:
Apache information now:
Server version: Apache/2.4.4 (Unix)
Server built: Apr 30 2013 17:41:49
Server's Module Magic Number: 20120211:11
Server loaded: APR 1.4.6, APR-UTIL 1.5.2
Compiled using: APR 1.4.6, APR-UTIL 1.5.2
Architecture: 64-bit
Server MPM: prefork
threaded: no
forked: yes (variable process count)
Server compiled with....
-D APR_HAS_SENDFILE
-D APR_HAS_MMAP
-D APR_HAVE_IPV6 (IPv4-mapped addresses enabled)
-D APR_USE_SYSVSEM_SERIALIZE
-D APR_USE_PTHREAD_SERIALIZE
-D APR_HAS_OTHER_CHILD
-D AP_HAVE_RELIABLE_PIPED_LOGS
-D DYNAMIC_MODULE_LIMIT=256
-D HTTPD_ROOT="/usr/local/apache2"
-D SUEXEC_BIN="/usr/local/apache2/bin/suexec"
-D DEFAULT_PIDLOG="logs/httpd.pid"
-D DEFAULT_SCOREBOARD="logs/apache_runtime_status"
-D DEFAULT_ERRORLOG="logs/error_log"
-D AP_TYPES_CONFIG_FILE="conf/mime.types"
-D SERVER_CONFIG_FILE="conf/httpd.conf"
PHP Information :
System Linux dev 3.5.0-17-generic #28-Ubuntu SMP Tue Oct 9 19:31:23 UTC 2012
x86_64
Build Date Apr 30 2013 17:54:17
Configure Command './configure' '--with-
apxs2=/usr/local/apache2/bin/apxs' '--enable-mbstring' '--with-config-file-
path=/etc/php5/' '--with-gettext=/usr/bin/gettext' '--with-config-file-scan-
dir=/etc/php5/mods-enabled/' '--with-mysql=mysqlnd' '--with-mysqli=mysqlnd' '--
with-pdo-mysql=mysqlnd' '--with-openssl' '--with-libdir=/lib/x86_64-linux-gnu/'
'--enable-debug'
Server API Apache 2.0 Handler
Virtual Directory Support disabled
Configuration File (php.ini) Path /etc/php5/
Loaded Configuration File /etc/php5/php.ini
Scan this dir for additional .ini files /etc/php5/mods-enabled/
Additional .ini files parsed /etc/php5/mods-enabled/xdebug.ini
PHP API 20100412
PHP Extension 20100525
Zend Extension 220100525
Zend Extension Build API220100525,NTS,debug
PHP Extension Build API20100525,NTS,debug
Debug Build yes
Thread Safety disabled
Zend Signal Handling disabled
Zend Memory Manager enabled
Zend Multibyte Support provided by mbstring
IPv6 Support enabled
DTrace Support disabled
Registered PHP Streams https, ftps, php, file, glob, data, http, ftp, phar
Registered Stream Socket Transports tcp, udp, unix, udg, ssl, sslv3, tls
Registered Stream Filters convert.iconv.*, string.rot13, string.toupper,
string.tolower, string.strip_tags, convert.*, consumed, dechunk
Apache PHP Information
Apache Version Apache/2.4.4 (Unix) OpenSSL/1.0.1c PHP/5.4.14
Apache API Version 20120211
Server Administrator [email protected]
Hostname:Port dev:0
User/Group www-data(33)/33
Max Requests Per Child: 0 - Keep Alive: on - Max Per Connection: 100
Timeouts Connection: 60 - Keep-Alive: 5
Virtual Server No
Server Root /usr/local/apache2
Loaded Modules core mod_so http_core prefork mod_authn_file mod_authn_dbm
mod_authn_anon mod_authn_dbd mod_authn_socache mod_authn_core mod_authz_host
mod_authz_groupfile mod_authz_user mod_authz_dbm mod_authz_owner mod_authz_dbd
mod_authz_core mod_access_compat mod_auth_basic mod_auth_form mod_auth_digest
mod_allowmethods mod_file_cache mod_cache mod_cache_disk mod_socache_shmcb
mod_socache_dbm mod_socache_memcache mod_dbd mod_dumpio mod_buffer
mod_ratelimit
mod_reqtimeout mod_ext_filter mod_request mod_include mod_filter mod_substitute
mod_sed mod_deflate mod_mime mod_log_config mod_log_debug mod_logio mod_env
mod_expires mod_headers mod_unique_id mod_setenvif mod_version mod_remoteip
mod_proxy mod_proxy_connect mod_proxy_ftp mod_proxy_http mod_proxy_fcgi
mod_proxy_scgi mod_proxy_ajp mod_proxy_balancer mod_proxy_express mod_session
mod_session_cookie mod_session_dbd mod_slotmem_shm mod_ssl
mod_lbmethod_byrequests mod_lbmethod_bytraffic mod_lbmethod_bybusyness
mod_lbmethod_heartbeat mod_unixd mod_dav mod_status mod_autoindex mod_info
mod_cgid mod_dav_fs mod_vhost_alias mod_negotiation mod_dir mod_actions
mod_speling mod_userdir mod_alias mod_rewrite mod_php5
This is running on a Ubuntu 12.10 virtual server.
Unfortunately I have to go now but I'll check in again on Thursday.
Keep well,
TJ
------------------------------------------------------------------------
[2013-04-30 16:05:40] [email protected]
so, the new backtrace has tsrm symbols, so what environment are you
using?8which web server,sapi, ...) Why threaded context?
And please try using helgrind (valgrind --tool=helgrind) with the server, this
should show details on race conditions.
------------------------------------------------------------------------
The remainder of the comments for this report are too long. To view
the rest of the comments, please view the bug report online at
https://bugs.php.net/bug.php?id=64722
--
Edit this bug report at https://bugs.php.net/bug.php?id=64722&edit=1