php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #53306 php crashes with segfault when DTrace "exception-thrown" probe fires
Submitted: 2010-11-13 23:12 UTC Modified: 2010-11-17 22:41 UTC
From: mike at harschsystems dot com Assigned: dsp (profile)
Status: Closed Package: Reproducible crash
PHP Version: trunk-SVN-2010-11-13 (snap) OS: Mac OS X and Solaris
Private report: No CVE-ID: None
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: mike at harschsystems dot com
New email:
PHP Version: OS:

 

 [2010-11-13 23:12 UTC] mike at harschsystems dot com
Description:
------------
When DTrace is present, and a DTrace consumer has enabled the "php*:::exception-
thrown" probe, php will crash when the probe fires, due to a null reference passed 
to zend_get_object_classname() from within the probe context.  The code within the 
DTrace probe context (inside zend_throw_exception_internal() ) doesn't check that 
the 'exception' argument is non-NULL.  The test described here obviously creates 
an instance where 'exception' is NULL, and when the enabled probe fires - the 
enabled code calls zend_get_object_classname() with a null argument, resulting in 
the segfault.

Test script:
---------------
In order to reproduce this, you must be running on a system that supports DTrace (OS X, Solaris, FreeBSD?), and php must have been built with --enable-dtrace.

The following script will trigger the exception codepath we're interested in:
<html><head><title>Test for PHP Exceptions</title></head><body>
<?php
	function my_func($my_arg) {
		if ($my_arg == 0)
			throw new Exception('You cannot do that.');
	}

	try {
		echo '<p>attempting to call my_func with my_arg == 0';

		my_func(0);

		echo 'this will not be executed';

	} catch (Exception $e) {
		echo "<p>caught exception: " . $e->getMessage();
	} 
?>
</body></html>

This will run fine when DTrace hasn't enabled the exception-thrown probe, but if we run the following command (as root) at the time that the above script is requested, php will crash.

# dtrace -n 'php*:::exception-thrown {}'

The attached patch shows how the problem could be avoided - though I'd like to hear from someone familiar with the Zend framework - to see if there may be an upstream bug that's causing the NULL value to come into zend_throw_exception_internal() in the first place.  If this is expected behavior, we should anticipate it and provide appropriate handling within the DTrace probe.



Expected result:
----------------
PHP shouldn't crash.

Actual result:
--------------
PHP crashes as shown:


Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_INVALID_ADDRESS at address: 0x0000000000000008
0x000000010156818b in zend_get_object_classname (object=0x0, 
class_name=0x7fff5fbfeb60, 
class_name_len=0x7fff5fbfeb6c) at /Users/michaelharsch/Desktop/php-trunk-
201011131530/Zend/zend_API.c:253
253          if (Z_OBJ_HT_P(object)->get_class_name == NULL ||
(gdb) bt
#0  0x000000010156818b in zend_get_object_classname (object=0x0, 
class_name=0x7fff5fbfeb60, 
class_name_len=0x7fff5fbfeb6c) at /Users/michaelharsch/Desktop/php-trunk-
201011131530/Zend/zend_API.c:253
#1  0x0000000101589e2e in zend_throw_exception_internal (exception=0x0) at 
/Users/michaelharsch/Desktop/php-trunk-
201011131530/Zend/zend_exceptions.c:90
#2  0x00000001015a6543 in zend_do_fcall_common_helper_SPEC 
(execute_data=0x10051a0d8) at zend_vm_execute.h:735
#3  0x00000001015acc98 in ZEND_DO_FCALL_SPEC_CONST_HANDLER 
(execute_data=0x10051a0d8) at zend_vm_execute.h:2015
#4  0x00000001015a4075 in execute (op_array=0x10054f030) at 
zend_vm_execute.h:410
#5  0x000000010154e6e5 in dtrace_execute (op_array=0x10054f030) at 
/Users/michaelharsch/Desktop/php-trunk-
201011131530/Zend/zend_dtrace.c:75
#6  0x00000001015674c6 in zend_execute_scripts (type=8, retval=0x0, 
file_count=3) at 
/Users/michaelharsch/Desktop/php-trunk-201011131530/Zend/zend.c:1195
#7  0x00000001014d28e3 in php_execute_script (primary_file=0x7fff5fbff810) at 
/Users/michaelharsch/Desktop/php-trunk-
201011131530/main/main.c:2340
#8  0x00000001016a39c5 in php_handler (r=0x10098a2a8) at 
/Users/michaelharsch/Desktop/php-trunk-
201011131530/sapi/apache2handler/sapi_apache2.c:667
#9  0x00000001000021db in ap_run_handler ()
#10 0x0000000100002aba in ap_invoke_handler ()
#11 0x000000010002f738 in ap_process_request ()
#12 0x000000010002bfa9 in ap_process_http_connection ()
#13 0x0000000100013737 in ap_run_process_connection ()
#14 0x0000000100013bd1 in ap_process_connection ()
#15 0x00000001000363f2 in child_main ()
#16 0x00000001000364dc in make_child ()
#17 0x0000000100036aaf in ap_mpm_run ()
#18 0x000000010000a821 in main ()


Patches

exception_fix2.patch (last revision 2010-11-13 22:23 UTC by mike at harschsystems dot com)

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2010-11-13 23:19 UTC] felipe@php.net
-Status: Open +Status: Feedback
 [2010-11-13 23:19 UTC] felipe@php.net
Where is the patch?
 [2010-11-13 23:25 UTC] mike at harschsystems dot com
sorry, just uploaded patch file "exception_fix2.patch"
 [2010-11-13 23:31 UTC] felipe@php.net
-Status: Feedback +Status: Assigned -Assigned To: +Assigned To: dsp
 [2010-11-14 00:42 UTC] mike at harschsystems dot com
With the patch in place, I can use the following DTrace script to see exceptions 
getting thrown and caught (differentiating those with null input from those with 
valid pointers):


#!/usr/sbin/dtrace -s
#pragma D option quiet

php*:::exception-thrown
/arg0 == NULL/
{
	printf("PHP Exception Thrown. Classname: Unknown\n");
}

php*:::exception-thrown
/arg0 != NULL/
{
	printf("PHP Exception Thrown. ");
	printf("Classname: %s\n", copyinstr(arg0));
}

php*:::exception-caught
{
	printf("PHP Exception Caught. ");
	printf("Classname: %s\n", copyinstr(arg0));
}


Running this script with the trivial exception script mentioned in this bug, 
produces the following output:

# ./php_exception.d 
PHP Exception Thrown. Classname: Exception
PHP Exception Thrown. Classname: Unknown
PHP Exception Caught. Classname: Exception
^C

So, we see that 2 exceptions are being thrown (one with a valid pointer and one 
with a null pointer), and one exception is caught.
 [2010-11-17 22:41 UTC] felipe@php.net
Automatic comment from SVN on behalf of felipe
Revision: http://svn.php.net/viewvc/?view=revision&amp;revision=305472
Log: - Fixed bug #53306 (php crashes with segfault when DTrace &quot;exception-thrown&quot; probe fires)
  patch by: mike at harschsystems dot com
 [2010-11-17 22:41 UTC] felipe@php.net
-Status: Assigned +Status: Closed
 [2010-11-17 22:41 UTC] felipe@php.net
This bug has been fixed in SVN.

Snapshots of the sources are packaged every three hours; this change
will be in the next snapshot. You can grab the snapshot at
http://snaps.php.net/.
 
Thank you for the report, and for helping us make PHP better.

Thanks for the patch!
 
PHP Copyright © 2001-2025 The PHP Group
All rights reserved.
Last updated: Sat Jul 12 05:01:33 2025 UTC