Opened 2 years ago

Last modified 2 years ago

#358 new defect

XCache causes "Fatal error: Cannot redeclare class X" fatal error or segfault with more complex php sources

Reported by: wladekb Owned by: moo
Priority: major Milestone: undecided
Component: cacher Version: 3.2.0
Keywords: crash Cc:
Application: PHP Version: 5.6.4
Other Exts: SAPI: apache2handler
Probability: Always Blocked By:
Blocking:

Description

XCache causes a Fatal Error about an attempt to redeclare a class or crashes entire php process when you include a file containing at least a subclass and a base class in this specific order eg.:

<?php
class B extends A {}
class A {}

Accessing this file via Apache throws a fatal error:
Fatal error: Cannot redeclare class B in x.php on line 3

A bit more complex code can crash the server instead of causing the Fatal Error eg.:
(this is a lighter version of https://raw.githubusercontent.com/Wikia/app/0d77fca4aea1ac46f21dff8c8f4f27bb5265ec0e/extensions/wikia/SponsorshipDashboard/SDDateProvider.class.php however still crashing 100% of the time on my test machine))

<?php

class SponsorshipDashboardDateProviderHour extends SponsorshipDashboardDateProvider {

	function getStartDate(){
		$startTime = ( !empty( $dateUnits ) ) ? mktime(date("H")-$dateUnits, 0, 0, date( "m" ), date( "d" ), date( "Y" )) : strtotime( SponsorshipDashboardDateProvider::SD_START_DATE );
		return date( "Y-m-d H:00", $startTime );
	}	
} 

class SponsorshipDashboardDateProviderYear extends SponsorshipDashboardDateProvider {

	public function getType(){
		return SponsorshipDashboardDateProvider::SD_FREQUENCY_YEAR;
	}
	
	// Overriding parent to provide a slightly more aesthetic format
	protected function formatDateByTimestamp($timeStamp){
		return date("Y", $timeStamp);
	}

	public function getGapiStartDate( $dateUnits = 0 ){
		$startTime = ( !empty( $dateUnits ) ) ? mktime(0, 0, 0, 0, 0 , date( "Y" ) - $dateUnits ) : strtotime( SponsorshipDashboardDateProvider::SD_START_DATE );
		return date( "Y-m-d", $startTime );
	}

}

class SponsorshipDashboardDateProvider {

	const SD_FREQUENCY_HOUR = 0; // WARNING: EXPERIMENTAL
	const SD_FREQUENCY_DAY = 1;
	const SD_FREQUENCY_WEEK = 2; // WARNING: EXPERIMENTAL
	const SD_FREQUENCY_MONTH = 3;
	const SD_FREQUENCY_YEAR = 4;
	const SD_START_DATE = '2010-04-01 00:00:00';

	/**
	 * Returns a formatted date with as many or as few of the possible time-periods provided.
	 *
	 * Can be overridden by subclasses
	 */
	public function formatDate($year=0, $month=0, $day=0, $hour=0, $minute=0, $second=0){
		$timeStamp = mktime($hour, $minute, $second, $month, $day, $year);
		return $this->formatDateByTimestamp( $timeStamp );
	}
	public function formatDateByString($timeString){
		return $this->formatDateByTimestamp( strtotime( $timeString) );
	}
	protected function formatDateByTimestamp($timeStamp){
		return date("Y-m-d H:i:s", $timeStamp);
	}
}

I'm able to reproduce it only when executing this file under Apache and it doesn't happen when run through CLI.

I kept cutting off methods from the original file. Few more attempts to remove random methods made the segfault not reproducible 100% of the time.

Disabling XCache extension or settings "xcache.cacher" to Off fixes the problem entirely and code executes correctly (no error).

php -v

PHP 5.6.4-1+deb.sury.org~precise+1 (cli) (built: Dec 21 2014 19:26:25) 
Copyright (c) 1997-2014 The PHP Group
Zend Engine v2.6.0, Copyright (c) 1998-2014 Zend Technologies
    with XCache v3.2.0, Copyright (c) 2005-2014, by mOo
    with Zend OPcache v7.0.4-dev, Copyright (c) 1999-2014, by Zend Technologies
    with Xdebug v2.2.5, Copyright (c) 2002-2014, by Derick Rethans
    with test_helpers v1.0.1-dev, Copyright (c) 2009-2013, by Johannes Schlueter, Scott MacVicar, Sebastian Bergmann
    with XCache Optimizer v3.2.0, Copyright (c) 2005-2014, by mOo
    with XCache Cacher v3.2.0, Copyright (c) 2005-2014, by mOo
    with XCache Coverager v3.2.0, Copyright (c) 2005-2014, by mOo

xcache.ini

; configuration for php Xcache module

[xcache-common]
;; non-Windows example:
extension = xcache.so
;; Windows example:
; extension = php_xcache.dll

[xcache.admin]
xcache.admin.enable_auth = On
; Configure this to use admin pages
; xcache.admin.user = "mOo"
; xcache.admin.pass = md5($your_password)
; xcache.admin.pass = ""

[xcache]
; ini only settings, all the values here is default unless explained

; select low level shm implemenation
xcache.shm_scheme =        "mmap"
; to disable: xcache.size=0
; to enable : xcache.size=64M etc (any size > 0) and your system mmap allows
xcache.size  =               60M
; set to cpu count (cat /proc/cpuinfo |grep -c processor)
xcache.count =                 1
; just a hash hints, you can always store count(items) > slots
xcache.slots =                8K
; ttl of the cache item, 0=forever
xcache.ttl   =                 0
; interval of gc scanning expired items, 0=no scan, other values is in seconds
xcache.gc_interval =           0

; same as aboves but for variable cache
xcache.var_size  =            4M
xcache.var_count =             1
xcache.var_slots =            8K
; default value for $ttl parameter of xcache_*() functions
xcache.var_ttl   =             0
; hard limit ttl that cannot be exceed by xcache_*() functions. 0=unlimited
xcache.var_maxttl   =          0
xcache.var_gc_interval =     300

; mode:0, const string specified by xcache.var_namespace
; mode:1, $_SERVER[xcache.var_namespace]
; mode:2, uid or gid (specified by xcache.var_namespace)
xcache.var_namespace_mode =    0
xcache.var_namespace =        ""

; N/A for /dev/zero
xcache.readonly_protection = Off
; for *nix, xcache.mmap_path is a file path, not directory. (auto create/overwrite)
; Use something like "/tmp/xcache" instead of "/dev/*" if you want to turn on ReadonlyProtection
; different process group of php won't share the same /tmp/xcache
; for win32, xcache.mmap_path=anonymous map name, not file path
xcache.mmap_path =    "/dev/zero"

; Useful when XCache crash. leave it blank(disabled) or "/tmp/phpcore/" (writable by php)
xcache.coredump_directory =   "/tmp/phpcore/"
; Windows only. leave it as 0 (default) until you're told by XCache dev
xcache.coredump_type =         0

; disable cache after crash
xcache.disable_on_crash =    Off

; enable experimental documented features for each release if available
xcache.experimental =        Off

; per request settings. can ini_set, .htaccess etc
xcache.cacher =               On
xcache.stat   =               On
xcache.optimizer =           Off

[xcache.coverager]
; enabling this feature will impact performance
; enabled only if xcache.coverager == On && xcache.coveragedump_directory == "non-empty-value"

; per request settings. can ini_set, .htaccess etc
; enable coverage data collecting and xcache_coverager_start/stop/get/clean() functions
xcache.coverager =          Off
xcache.coverager_autostart =  On

; set in php ini file only
; make sure it's readable (open_basedir is checked) by coverage viewer script
xcache.coveragedump_directory = ""

gdb backtrace

Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7ffff7fe6740 (LWP 25160)]
zend_hash_find (ht=0x4145595f59434e6d, arKey=0x7fffd4022960 "formatDateByTimestamp", nKeyLength=22, pData=0x7fffffff9450) at /build/buildd/php5-5.6.4+dfsg/Zend/zend_hash.c:849
849	/build/buildd/php5-5.6.4+dfsg/Zend/zend_hash.c: No such file or directory.
(gdb) bt
#0  zend_hash_find (ht=0x4145595f59434e6d, arKey=0x7fffd4022960 "formatDateByTimestamp", nKeyLength=22, pData=0x7fffffff9450) at /build/buildd/php5-5.6.4+dfsg/Zend/zend_hash.c:849
#1  0x00007fffe295fea7 in xc_restore_zend_op_array () from /usr/lib/php5/20131226/xcache.so
#2  0x00007fffe2960722 in xc_restore_HashTable_zend_function () from /usr/lib/php5/20131226/xcache.so
#3  0x00007fffe296100a in xc_restore_zend_class_entry () from /usr/lib/php5/20131226/xcache.so
#4  0x00007fffe29616bf in xc_restore_xc_entry_data_php_t () from /usr/lib/php5/20131226/xcache.so
#5  0x00007fffe2961765 in xc_processor_restore_xc_entry_data_php_t () from /usr/lib/php5/20131226/xcache.so
#6  0x00007fffe2964e0c in ?? () from /usr/lib/php5/20131226/xcache.so
#7  0x00007fffe2969260 in ?? () from /usr/lib/php5/20131226/xcache.so
#8  0x00007fffe2969b86 in ?? () from /usr/lib/php5/20131226/xcache.so
#9  0x00007fffe296bbfc in ?? () from /usr/lib/php5/20131226/xcache.so
#10 0x00007ffff34a973c in compile_filename (type=8, filename=0x7fffd40209b8) at Zend/zend_language_scanner.l:629
#11 0x00007ffff358384a in ZEND_INCLUDE_OR_EVAL_SPEC_CONST_HANDLER (execute_data=0x7ffff7eaf190) at /build/buildd/php5-5.6.4+dfsg/Zend/zend_vm_execute.h:2981
#12 0x00007ffff354b108 in execute_ex (execute_data=0x7ffff7eaf190) at /build/buildd/php5-5.6.4+dfsg/Zend/zend_vm_execute.h:363
#13 0x00007ffff34d1046 in dtrace_execute_ex (execute_data=0x7ffff7eaf190) at /build/buildd/php5-5.6.4+dfsg/Zend/zend_dtrace.c:73
#14 0x00007fffefa44195 in xdebug_execute_ex (execute_data=0x7ffff7eaf190) at /build/buildd/xdebug-2.2.5/xdebug-2.2.5/xdebug.c:1437
#15 0x00007ffff34d2d29 in zend_call_function (fci=0x7fffffffb6b0, fci_cache=<optimized out>) at /build/buildd/php5-5.6.4+dfsg/Zend/zend_execute_API.c:832
#16 0x00007ffff34f9a67 in zend_call_method (object_pp=0x0, obj_ce=<optimized out>, fn_proxy=0x7ffff7ee4470, function_name=0x7ffff7ee4448 "closure::__invoke\001", function_name_len=<optimized out>, 
    retval_ptr_ptr=0x7fffffffb7e0, param_count=1, arg1=0x7ffff7ee4320, arg2=0x0) at /build/buildd/php5-5.6.4+dfsg/Zend/zend_interfaces.c:97
#17 0x00007ffff33cb4b9 in zif_spl_autoload_call (ht=<optimized out>, return_value=<optimized out>, return_value_ptr=<optimized out>, this_ptr=<optimized out>, return_value_used=<optimized out>)
    at /build/buildd/php5-5.6.4+dfsg/ext/spl/php_spl.c:436
#18 0x00007ffff34d1159 in dtrace_execute_internal (execute_data_ptr=<optimized out>, fci=<optimized out>, return_value_used=<optimized out>) at /build/buildd/php5-5.6.4+dfsg/Zend/zend_dtrace.c:97
#19 0x00007fffefa43262 in xdebug_execute_internal (current_execute_data=0x7fffffffb9d0, fci=0x7fffffffbb30, return_value_used=1) at /build/buildd/xdebug-2.2.5/xdebug-2.2.5/xdebug.c:1551
#20 0x00007ffff34d2e26 in zend_call_function (fci=0x7fffffffbb30, fci_cache=<optimized out>) at /build/buildd/php5-5.6.4+dfsg/Zend/zend_execute_API.c:852
#21 0x00007ffff34d353a in zend_lookup_class_ex (name=0x7fffd40204f0 "SponsorshipDashboardDateProvider", name_length=32, key=0x7fffd40203f8, use_autoload=1, ce=0x7fffffffbc48)
    at /build/buildd/php5-5.6.4+dfsg/Zend/zend_execute_API.c:1008
#22 0x00007ffff34d3c32 in zend_fetch_class_by_name (class_name=0x7fffd40204f0 "SponsorshipDashboardDateProvider", class_name_len=<optimized out>, key=<optimized out>, fetch_type=0)
    at /build/buildd/php5-5.6.4+dfsg/Zend/zend_execute_API.c:1492
#23 0x00007ffff352b943 in ZEND_FETCH_CONSTANT_SPEC_CONST_CONST_HANDLER (execute_data=0x7ffff7eaf0a0) at /build/buildd/php5-5.6.4+dfsg/Zend/zend_vm_execute.h:3998
#24 0x00007ffff354b108 in execute_ex (execute_data=0x7ffff7eaf0a0) at /build/buildd/php5-5.6.4+dfsg/Zend/zend_vm_execute.h:363
#25 0x00007ffff34d1046 in dtrace_execute_ex (execute_data=0x7ffff7eaf0a0) at /build/buildd/php5-5.6.4+dfsg/Zend/zend_dtrace.c:73
#26 0x00007fffefa44195 in xdebug_execute_ex (execute_data=0x7ffff7eaf0a0) at /build/buildd/xdebug-2.2.5/xdebug-2.2.5/xdebug.c:1437
#27 0x00007ffff34e39c4 in zend_execute_scripts (type=8, retval=0x0, file_count=3) at /build/buildd/php5-5.6.4+dfsg/Zend/zend.c:1344
#28 0x00007ffff347f0fc in php_execute_script (primary_file=0x7fffffffe260) at /build/buildd/php5-5.6.4+dfsg/main/main.c:2584
#29 0x00007ffff3584f6d in php_handler (r=0x7ffff7e430a0) at /build/buildd/php5-5.6.4+dfsg/sapi/apache2handler/sapi_apache2.c:667
#30 0x00005555555ad6d8 in ap_run_handler ()
#31 0x00005555555adcce in ap_invoke_handler ()
#32 0x00005555555c44ea in ap_process_async_request ()
#33 0x00005555555c464f in ap_process_request ()
#34 0x00005555555c0b65 in ?? ()
#35 0x00005555555b7318 in ap_run_process_connection ()
#36 0x00007ffff3e88633 in ?? () from /usr/lib/apache2/modules/mod_mpm_prefork.so
#37 0x00007ffff3e8888c in ?? () from /usr/lib/apache2/modules/mod_mpm_prefork.so
#38 0x00007ffff3e888f7 in ?? () from /usr/lib/apache2/modules/mod_mpm_prefork.so
#39 0x00007ffff3e898ce in ?? () from /usr/lib/apache2/modules/mod_mpm_prefork.so
#40 0x0000555555592216 in ap_run_mpm ()
#41 0x000055555558b788 in main ()
(gdb) print ht
$1 = (const HashTable *) 0x4145595f59434e6d
(gdb) print ht->arBuckets
Cannot access memory at address 0x4145595f59434e9d

Change History (2)

comment:1 Changed 2 years ago by moo

You should really turn off Zend OPcache. It seems to work with XCache but it doesn't

comment:2 Changed 2 years ago by wladekb

Hey, it solves the issue.

Do you plan to block Zend OPcache and XCache running simultaneously if they don't play very well together?

Note: See TracTickets for help on using tickets.