Skip to content

Commit 96c4363

Browse files
committed
Aggressively use actual func params in verror
PHP errors used to not show parameter info consistently. Make it so that it uses a backtrace to get function info, similar to how exceptions work. This makes the docref error functions' parameter argument mostly vestigal, being used only if allocation fails basically. Several tests will fail from the fact we include function params. One annoyance is that _build_trace_args truncates strings according to exception_string_param_max_len. See GH-12048
1 parent 659c06d commit 96c4363

File tree

3 files changed

+61
-1
lines changed

3 files changed

+61
-1
lines changed

Zend/zend_exceptions.c

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -587,6 +587,39 @@ static void _build_trace_string(smart_str *str, HashTable *ht, uint32_t num) /*
587587
}
588588
/* }}} */
589589

590+
ZEND_API zend_string *zend_trace_function_args_to_string(HashTable *frame) {
591+
zval *tmp;
592+
smart_str str = {0};
593+
/* init because ASan will complain */
594+
smart_str_appends(&str, "");
595+
596+
tmp = zend_hash_find_known_hash(frame, ZSTR_KNOWN(ZEND_STR_ARGS));
597+
if (tmp) {
598+
if (Z_TYPE_P(tmp) == IS_ARRAY) {
599+
size_t last_len = ZSTR_LEN(str.s);
600+
zend_string *name;
601+
zval *arg;
602+
603+
ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(tmp), name, arg) {
604+
if (name) {
605+
smart_str_append(&str, name);
606+
smart_str_appends(&str, ": ");
607+
}
608+
_build_trace_args(arg, &str);
609+
} ZEND_HASH_FOREACH_END();
610+
611+
if (last_len != ZSTR_LEN(str.s)) {
612+
ZSTR_LEN(str.s) -= 2; /* remove last ', ' */
613+
}
614+
} else {
615+
smart_str_appends(&str, "<<invalid argument array>>");
616+
}
617+
}
618+
619+
smart_str_0(&str);
620+
return str.s ? str.s : ZSTR_EMPTY_ALLOC();
621+
}
622+
590623
ZEND_API zend_string *zend_trace_to_string(HashTable *trace, bool include_main) {
591624
zend_ulong index;
592625
zval *frame;

Zend/zend_exceptions.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ extern ZEND_API void (*zend_throw_exception_hook)(zend_object *ex);
6969
/* show an exception using zend_error(severity,...), severity should be E_ERROR */
7070
ZEND_API ZEND_COLD zend_result zend_exception_error(zend_object *exception, int severity);
7171
ZEND_NORETURN void zend_exception_uncaught_error(const char *prefix, ...) ZEND_ATTRIBUTE_FORMAT(printf, 1, 2);
72+
ZEND_API zend_string *zend_trace_function_args_to_string(HashTable *frame);
7273
ZEND_API zend_string *zend_trace_to_string(HashTable *trace, bool include_main);
7374

7475
ZEND_API ZEND_COLD zend_object *zend_create_unwind_exit(void);

main/main.c

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
#include "ext/standard/flock_compat.h"
5858
#endif
5959
#include "php_syslog.h"
60+
#include "Zend/zend_builtin_functions.h"
6061
#include "Zend/zend_exceptions.h"
6162

6263
#if PHP_SIGCHILD
@@ -936,6 +937,26 @@ static zend_string *escape_html(const char *buffer, size_t buffer_len) {
936937
return result;
937938
}
938939

940+
static zend_string *build_dynamic_parameters(void) {
941+
zend_string *dynamic_params = NULL;
942+
/* get a backtrace to snarf function args */
943+
zval backtrace, *first_frame;
944+
zend_fetch_debug_backtrace(&backtrace, /* skip_last */ 0, /* options */ 0, /* limit */ 1);
945+
/* can fail esp if low memory condition */
946+
if (Z_TYPE(backtrace) != IS_ARRAY) {
947+
return NULL; /* don't need to free */
948+
}
949+
first_frame = zend_hash_index_find(Z_ARRVAL(backtrace), 0);
950+
if (!first_frame) {
951+
goto free_backtrace;
952+
}
953+
dynamic_params = zend_trace_function_args_to_string(Z_ARRVAL_P(first_frame));
954+
free_backtrace:
955+
zval_ptr_dtor(&backtrace);
956+
/* free the string after we use it */
957+
return dynamic_params;
958+
}
959+
939960
/* {{{ php_verror */
940961
/* php_verror is called from php_error_docref<n> functions.
941962
* Its purpose is to unify error messages and automatically generate clickable
@@ -1021,7 +1042,12 @@ PHPAPI ZEND_COLD void php_verror(const char *docref, const char *params, int typ
10211042

10221043
/* if we still have memory then format the origin */
10231044
if (is_function) {
1024-
origin_len = (int)spprintf(&origin, 0, "%s%s%s(%s)", class_name, space, function, params);
1045+
zend_string *dynamic_params = NULL;
1046+
dynamic_params = build_dynamic_parameters();
1047+
origin_len = (int)spprintf(&origin, 0, "%s%s%s(%s)", class_name, space, function, dynamic_params ? ZSTR_VAL(dynamic_params) : params);
1048+
if (dynamic_params) {
1049+
zend_string_release(dynamic_params);
1050+
}
10251051
} else {
10261052
origin_len = (int)spprintf(&origin, 0, "%s", function);
10271053
}

0 commit comments

Comments
 (0)