Skip to content

[Debug] Add symfony_debug_backtrace() and use it when dealing with fatal errors #14159

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Apr 3, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ before_install:
- if [[ "$TRAVIS_PHP_VERSION" != *"nightly" ]]; then echo "extension = mongo.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini; fi;
- if [[ "$TRAVIS_PHP_VERSION" != *"nightly" ]] && [ $(php -r "echo PHP_MINOR_VERSION;") -le 4 ]; then echo "extension = apc.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini; fi;
- if [[ "$TRAVIS_PHP_VERSION" != *"nightly" ]]; then (pecl install -f memcached-2.1.0 && echo "extension = memcache.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini) || echo "Let's continue without memcache extension"; fi;
- if [[ "$TRAVIS_PHP_VERSION" != *"nightly" ]]; then (cd src/Symfony/Component/Debug/Resources/ext && phpize && ./configure && make && echo "extension = $(pwd)/modules/symfony_debug.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini); fi;
- if [[ "$TRAVIS_PHP_VERSION" != *"nightly" ]]; then php -i; fi;
- sudo locale-gen fr_FR.UTF-8 && sudo update-locale
# Set the COMPOSER_ROOT_VERSION to the right version according to the branch being built
Expand Down
8 changes: 8 additions & 0 deletions src/Symfony/Component/Debug/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
CHANGELOG
=========

2.7.0
-----

* added deprecations checking for parent interfaces/classes to DebugClassLoader
* added ZTS support to symfony_debug extension
* added symfony_debug_backtrace() to symfony_debug extension
to track the backtrace of fatal errors

2.6.0
-----

Expand Down
5 changes: 5 additions & 0 deletions src/Symfony/Component/Debug/Exception/FatalErrorException.php
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,11 @@ public function __construct($message, $code, $severity, $filename, $lineno, $tra

unset($frame);
$trace = array_reverse($trace);
} elseif (function_exists('symfony_debug_backtrace')) {
$trace = symfony_debug_backtrace();
if (0 < $traceOffset) {
array_splice($trace, 0, $traceOffset);
}
} else {
$trace = array();
}
Expand Down
133 changes: 133 additions & 0 deletions src/Symfony/Component/Debug/Resources/ext/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
Symfony Debug Extension
=======================

This extension publishes several functions to help building powerful debugging tools.

symfony_zval_info()
-------------------

- exposes zval_hash/refcounts, allowing e.g. efficient exploration of arbitrary structures in PHP,
- does work with references, preventing memory copying.

Its behavior is about the same as:

```php
<?php

function symfony_zval_info($key, $array, $options = 0)
{

// $options is currently not used, but could be in future version.

if (!array_key_exists($key, $array)) {
return null;
}

$info = array(
'type' => gettype($array[$key]),
'zval_hash' => /* hashed memory address of $array[$key] */,
'zval_refcount' => /* internal zval refcount of $array[$key] */,
'zval_isref' => /* is_ref status of $array[$key] */,
);

switch ($info['type']) {
case 'object':
$info += array(
'object_class' => get_class($array[$key]),
'object_refcount' => /* internal object refcount of $array[$key] */,
'object_hash' => spl_object_hash($array[$key]),
'object_handle' => /* internal object handle $array[$key] */,
);
break;

case 'resource':
$info += array(
'resource_handle' => (int) $array[$key],
'resource_type' => get_resource_type($array[$key]),
'resource_refcount' => /* internal resource refcount of $array[$key] */,
);
break;

case 'array':
$info += array(
'array_count' => count($array[$key]),
);
break;

case 'string':
$info += array(
'strlen' => strlen($array[$key]),
);
break;
}

return $info;
}
```

symfony_debug_backtrace()
-------------------------

This function works like debug_backtrace(), except that it can fetch the full backtrace in case of fatal errors:

```php
function foo() { fatal(); }
function bar() { foo(); }

function sd() { var_dump(symfony_debug_backtrace()); }

register_shutdown_function('sd');

bar();

/* Will output
Fatal error: Call to undefined function fatal() in foo.php on line 42
array(3) {
[0]=>
array(2) {
["function"]=>
string(2) "sd"
["args"]=>
array(0) {
}
}
[1]=>
array(4) {
["file"]=>
string(7) "foo.php"
["line"]=>
int(1)
["function"]=>
string(3) "foo"
["args"]=>
array(0) {
}
}
[2]=>
array(4) {
["file"]=>
string(102) "foo.php"
["line"]=>
int(2)
["function"]=>
string(3) "bar"
["args"]=>
array(0) {
}
}
}
*/
```

Usage
-----

The extension is compatible with ZTS mode, and should be supported by PHP5.3, 5.4, 5.5 and 5.6.
To enable the extension from source, run:

```
phpize
./configure
make
sudo make install
```
72 changes: 0 additions & 72 deletions src/Symfony/Component/Debug/Resources/ext/README.rst

This file was deleted.

13 changes: 9 additions & 4 deletions src/Symfony/Component/Debug/Resources/ext/php_symfony_debug.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
extern zend_module_entry symfony_debug_module_entry;
#define phpext_symfony_debug_ptr &symfony_debug_module_entry

#define PHP_SYMFONY_DEBUG_VERSION "1.0"
#define PHP_SYMFONY_DEBUG_VERSION "2.7"

#ifdef PHP_WIN32
# define PHP_SYMFONY_DEBUG_API __declspec(dllexport)
Expand All @@ -29,6 +29,8 @@ extern zend_module_entry symfony_debug_module_entry;

ZEND_BEGIN_MODULE_GLOBALS(symfony_debug)
intptr_t req_rand_init;
void (*old_error_cb)(int type, const char *error_filename, const uint error_lineno, const char *format, va_list args);
zval *debug_bt;
ZEND_END_MODULE_GLOBALS(symfony_debug)

PHP_MINIT_FUNCTION(symfony_debug);
Expand All @@ -40,11 +42,14 @@ PHP_GINIT_FUNCTION(symfony_debug);
PHP_GSHUTDOWN_FUNCTION(symfony_debug);

PHP_FUNCTION(symfony_zval_info);
PHP_FUNCTION(symfony_debug_backtrace);

static char *_symfony_debug_memory_address_hash(void *);
static char *_symfony_debug_memory_address_hash(void * TSRMLS_DC);
static const char *_symfony_debug_zval_type(zval *);
static const char* _symfony_debug_get_resource_type(long);
static int _symfony_debug_get_resource_refcount(long);
static const char* _symfony_debug_get_resource_type(long TSRMLS_DC);
static int _symfony_debug_get_resource_refcount(long TSRMLS_DC);

void symfony_debug_error_cb(int type, const char *error_filename, const uint error_lineno, const char *format, va_list args);

#ifdef ZTS
#define SYMFONY_DEBUG_G(v) TSRMG(symfony_debug_globals_id, zend_symfony_debug_globals *, v)
Expand Down
Loading