From: Xinchen Hui <laruence@gmail.com>
Date: Sat, 24 Mar 2012 07:13:10 +0000 (+0800)
Subject: Implemented FR #60738 (Allow 'set_error_handler' to handle NULL)
X-Git-Tag: php-5.4.1RC1~33^2
X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=fcae164ea63979d7814d7aa114fe8351033e7400;p=php

Implemented FR #60738 (Allow 'set_error_handler' to handle NULL)
---

diff --git a/NEWS b/NEWS
index fa36358231..2e1dd7c438 100644
--- a/NEWS
+++ b/NEWS
@@ -23,6 +23,8 @@ PHP                                                                        NEWS
   . Fixed bug #60825 (Segfault when running symfony 2 tests).
     (Dmitry, Laruence)
   . Fixed bug #60801 (strpbrk() mishandles NUL byte). (Adam)
+  . Implemented FR #60738 (Allow 'set_error_handler' to handle NULL).
+    (Laruence, Nikita Popov)
   . Fixed bug #60569 (Nullbyte truncates Exception $message). (Ilia)
   . Fixed bug #60227 (header() cannot detect the multi-line header with CR).
     (rui, Gustavo)
diff --git a/Zend/tests/bug60738.phpt b/Zend/tests/bug60738.phpt
new file mode 100644
index 0000000000..e0c9793fed
--- /dev/null
+++ b/Zend/tests/bug60738.phpt
@@ -0,0 +1,17 @@
+--TEST--
+Bug #60738 Allow 'set_error_handler' to handle NULL
+--FILE--
+<?php
+
+set_error_handler(function() { echo 'Intercepted error!', "\n"; });
+
+trigger_error('Error!');
+
+set_error_handler(null);
+
+trigger_error('Error!');
+?>
+--EXPECTF--
+Intercepted error!
+
+Notice: Error! in %s on line %d
diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c
index 57a9e3a7bc..c4a10fde37 100644
--- a/Zend/zend_builtin_functions.c
+++ b/Zend/zend_builtin_functions.c
@@ -1413,7 +1413,6 @@ ZEND_FUNCTION(trigger_error)
 ZEND_FUNCTION(set_error_handler)
 {
 	zval *error_handler;
-	zend_bool had_orig_error_handler=0;
 	char *error_handler_name = NULL;
 	long error_type = E_ALL | E_STRICT;
 
@@ -1421,37 +1420,40 @@ ZEND_FUNCTION(set_error_handler)
 		return;
 	}
 
-	if (!zend_is_callable(error_handler, 0, &error_handler_name TSRMLS_CC)) {
-		zend_error(E_WARNING, "%s() expects the argument (%s) to be a valid callback",
-				   get_active_function_name(TSRMLS_C), error_handler_name?error_handler_name:"unknown");
+	if (IS_NULL != Z_TYPE_P(error_handler)) {
+	    zend_bool had_orig_error_handler = 0;
+		if (!zend_is_callable(error_handler, 0, &error_handler_name TSRMLS_CC)) {
+			zend_error(E_WARNING, "%s() expects the argument (%s) to be a valid callback",
+					get_active_function_name(TSRMLS_C), error_handler_name?error_handler_name:"unknown");
+			efree(error_handler_name);
+			return;
+		}
 		efree(error_handler_name);
-		return;
-	}
-	efree(error_handler_name);
 
-	if (EG(user_error_handler)) {
-		had_orig_error_handler = 1;
-		*return_value = *EG(user_error_handler);
-		zval_copy_ctor(return_value);
-		INIT_PZVAL(return_value);
-		zend_stack_push(&EG(user_error_handlers_error_reporting), &EG(user_error_handler_error_reporting), sizeof(EG(user_error_handler_error_reporting)));
-		zend_ptr_stack_push(&EG(user_error_handlers), EG(user_error_handler));
-	}
-	ALLOC_ZVAL(EG(user_error_handler));
+		if (EG(user_error_handler)) {
+			had_orig_error_handler = 1;
+			*return_value = *EG(user_error_handler);
+			zval_copy_ctor(return_value);
+			INIT_PZVAL(return_value);
+			zend_stack_push(&EG(user_error_handlers_error_reporting), &EG(user_error_handler_error_reporting), sizeof(EG(user_error_handler_error_reporting)));
+			zend_ptr_stack_push(&EG(user_error_handlers), EG(user_error_handler));
+		}
 
-	if (!zend_is_true(error_handler)) { /* unset user-defined handler */
-		FREE_ZVAL(EG(user_error_handler));
-		EG(user_error_handler) = NULL;
-		RETURN_TRUE;
-	}
+		ALLOC_ZVAL(EG(user_error_handler));
+		EG(user_error_handler_error_reporting) = (int)error_type;
+		MAKE_COPY_ZVAL(&error_handler, EG(user_error_handler));
 
-	EG(user_error_handler_error_reporting) = (int)error_type;
-	*EG(user_error_handler) = *error_handler;
-	zval_copy_ctor(EG(user_error_handler));
-	INIT_PZVAL(EG(user_error_handler));
+		if (!had_orig_error_handler) {
+			RETURN_NULL();
+		}
+	} else { /* unset user-defined handler */
+		if (EG(user_error_handler)) {
+			zend_stack_push(&EG(user_error_handlers_error_reporting), &EG(user_error_handler_error_reporting), sizeof(EG(user_error_handler_error_reporting)));
+			zend_ptr_stack_push(&EG(user_error_handlers), EG(user_error_handler));
+		}
 
-	if (!had_orig_error_handler) {
-		RETURN_NULL();
+		EG(user_error_handler) = NULL;
+		RETURN_TRUE;
 	}
 }
 /* }}} */