Skip to content

Commit

Permalink
Modify agent to conform with new PHP 8.0 internal API changes (newrel…
Browse files Browse the repository at this point in the history
…ic#49)

Fixes newrelic#46 

* Added defines for PHP8.
* Added `TSRMLS` macros.
* The Object Handlers API was changed to receive zend_object* instead of zval* and zend_string* instead of zval* for property names.  Modified agent to toggle between zval and zend_object depending on PHP8 or not.
* The zend_fcall_info no_separation flag has been removed, and separation is never allowed. If you wish to pass (or allow passing) arguments by reference, explicitly create those arguments as references using ZEND_MAKE_REF. This function is passed as a pointer in the agent here. This removal also affects call_user_function_ex() (example in agent), which should be replaced by call_user_function().
* Error notifications have a new API and the callback signature has changed. The current changes do not register a callback.
* `display_disabled_function` (and therefore also `zif_display_disabled_function`) has been removed `zend_API.c.`. In PHP 8, a disabled function is indistinguishable from a function that does not exist.
* Added `newrelic_arginfo_void` as `PHP_FE` no longer allows `0` as an argument.
* Modified unit tests to work with PHP8.
* `call_user_function_ex` was removed and `call_user_function` became the recommended function; however, it no longer gracefully handled the case of the 2nd parameter  being passed in as NULL. We no longer assume graceful handling, and now we check for NULL before calling the function.
* Take into account new `libphp.so` and `libphp.a` naming scheme.
* `zend_get_resource_handle` now takes a different type parameter.
* Added `#if ZEND_MODULE_API_NO >= ZEND_8_0_X_API_NO /* PHP 8.0+ */` around definition of `newrelic_arginfo_void` since all usages of this were also wrapped in PHP 8 `if` statements which would then result in an used arg error/warning on some builds.
* Update opcode inspection to properly detect calls to `call_user_func_array`. On PHP 8.0, there's an additional opcode added when the function is compiled.

Co-authored-by: Joshua Benuck <[email protected]>
  • Loading branch information
zsistla and Joshua Benuck committed Feb 16, 2021
1 parent 2a4ab07 commit 93c8c0b
Show file tree
Hide file tree
Showing 23 changed files with 340 additions and 140 deletions.
17 changes: 14 additions & 3 deletions agent/Makefile.frag
Original file line number Diff line number Diff line change
Expand Up @@ -202,10 +202,21 @@ endif
# prefer the static version if it's available, but depending on how PHP was
# installed, we may only have the shared version.
#
ifneq (,$(wildcard $(libdir)/libphp$(shell $(PHP_CONFIG) --version | cut -d . -f 1).a))
PHP_EMBED_LIBRARY := $(libdir)/libphp$(shell $(PHP_CONFIG) --version | cut -d . -f 1).a


# Update for PHP8:
# They no longer adhere to their prior versioning system. The library is now
# simply $prefix/lib/libphp.{a,so}

major = $(shell $(PHP_CONFIG) --version | cut -d . -f 1)
ifeq ($(major), 8)
major =
endif

ifneq (,$(wildcard $(libdir)/libphp$(major).a))
PHP_EMBED_LIBRARY := $(libdir)/libphp$(major).a
else
PHP_EMBED_LIBRARY := $(libdir)/libphp$(shell $(PHP_CONFIG) --version | cut -d . -f 1).so
PHP_EMBED_LIBRARY := $(libdir)/libphp$(major).so
endif

#
Expand Down
3 changes: 2 additions & 1 deletion agent/fw_laravel.c
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,8 @@ static PHP_NAMED_FUNCTION(nr_laravel_afterfilter_construct) {
/*
* It's a valid app object. Set $this->app to contain it.
*/
zend_update_property(nr_laravel_afterfilter_ce, this_obj, NR_PSTR("app"),
zend_update_property(nr_laravel_afterfilter_ce,
ZVAL_OR_ZEND_OBJECT(this_obj), NR_PSTR("app"),
app TSRMLS_CC);
} else {
/*
Expand Down
11 changes: 6 additions & 5 deletions agent/fw_laravel_queue.c
Original file line number Diff line number Diff line change
Expand Up @@ -558,7 +558,7 @@ NR_PHP_WRAPPER(nr_laravel_queue_worker_process) {
if (EG(exception)) {
zval* exception_zval = NULL;

#ifdef PHP7
#if ZEND_MODULE_API_NO >= ZEND_7_0_X_API_NO /* PHP 7.0+ */
/*
* On PHP 7, EG(exception) is stored as a zend_object, and is only wrapped
* in a zval when it actually needs to be. Unfortunately, our error handling
Expand All @@ -583,7 +583,7 @@ NR_PHP_WRAPPER(nr_laravel_queue_worker_process) {
* On PHP 5, the exception is just a regular old zval.
*/
exception_zval = EG(exception);
#endif /* PHP7 */
#endif /* PHP7+ */

nr_php_error_record_exception(
NRPRG(txn), exception_zval, NR_PHP_ERROR_PRIORITY_UNCAUGHT_EXCEPTION,
Expand Down Expand Up @@ -748,7 +748,8 @@ NR_PHP_WRAPPER(nr_laravel_queue_queue_createpayload) {
header_mq = nr_laravel_get_payload_header_mq(header);

if (header_mq) {
zend_update_property_string(Z_OBJCE_P(payload), payload, header_mq,
zend_update_property_string(Z_OBJCE_P(payload),
ZVAL_OR_ZEND_OBJECT(payload), header_mq,
nr_strlen(header_mq), value TSRMLS_CC);
}
}
Expand All @@ -761,13 +762,13 @@ NR_PHP_WRAPPER(nr_laravel_queue_queue_createpayload) {
/*
* Finally, we change the string in the return value to our new JSON.
*/
#ifdef PHP7
#if ZEND_MODULE_API_NO >= ZEND_7_0_X_API_NO /* PHP 7.0+ */
zend_string_free(Z_STR_P(*retval_ptr));
Z_STR_P(*retval_ptr) = zend_string_copy(Z_STR_P(json));
#else
efree(Z_STRVAL_PP(retval_ptr));
nr_php_zval_str_len(*retval_ptr, Z_STRVAL_P(json), Z_STRLEN_P(json));
#endif /* PHP7 */
#endif /* PHP7+ */

end:
nr_php_zval_free(&payload);
Expand Down
4 changes: 2 additions & 2 deletions agent/lib_guzzle6.c
Original file line number Diff line number Diff line change
Expand Up @@ -203,8 +203,8 @@ static PHP_NAMED_FUNCTION(nr_guzzle6_requesthandler_construct) {
return;
}

zend_update_property(Z_OBJCE_P(this_obj), this_obj, NR_PSTR("request"),
request TSRMLS_CC);
zend_update_property(Z_OBJCE_P(this_obj), ZVAL_OR_ZEND_OBJECT(this_obj),
NR_PSTR("request"), request TSRMLS_CC);

nr_guzzle_obj_add(this_obj, "Guzzle 6" TSRMLS_CC);
}
Expand Down
75 changes: 38 additions & 37 deletions agent/php_agent.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ static zval* nr_php_get_zval_object_property_with_class_internal(
zval* object,
zend_class_entry* ce,
const char* cname TSRMLS_DC) {
#ifdef PHP7
#if ZEND_MODULE_API_NO >= ZEND_7_0_X_API_NO /* PHP 7.0+ */
/*
* Although the below notes still apply in principle, PHP 7 additionally broke
* the API for zend_read_property by adding an rv parameter, which is used to
Expand All @@ -33,7 +33,8 @@ static zval* nr_php_get_zval_object_property_with_class_internal(
zval rv;
zend_bool silent = 1;

data = zend_read_property(ce, object, cname, nr_strlen(cname), silent, &rv);
data = zend_read_property(ce, ZVAL_OR_ZEND_OBJECT(object), cname,
nr_strlen(cname), silent, &rv);
if (&EG(uninitialized_zval) != data) {
return data;
}
Expand All @@ -55,7 +56,7 @@ static zval* nr_php_get_zval_object_property_with_class_internal(
if (EG(uninitialized_zval_ptr) != data) {
return data;
}
#endif /* PHP7 */
#endif /* PHP7+ */

return NULL;
}
Expand Down Expand Up @@ -124,7 +125,7 @@ int nr_php_object_has_method(zval* object, const char* lcname TSRMLS_DC) {
} else {
void* func;

#ifdef PHP7
#if ZEND_MODULE_API_NO >= ZEND_7_0_X_API_NO /* PHP 7.0+ */
zend_string* name_str = zend_string_init(vname, namelen, 0);

func = (void*)Z_OBJ_HT_P(object)->get_method(&Z_OBJ_P(object), name_str,
Expand Down Expand Up @@ -188,7 +189,7 @@ zend_function* nr_php_find_function(const char* name TSRMLS_DC) {
* whereas PHP 7 only uses a single level of indirection.
*/
zend_class_entry* nr_php_find_class(const char* name TSRMLS_DC) {
#ifdef PHP7
#if ZEND_MODULE_API_NO >= ZEND_7_0_X_API_NO /* PHP 7.0+ */
if (NULL == name) {
return NULL;
}
Expand All @@ -204,7 +205,7 @@ zend_class_entry* nr_php_find_class(const char* name TSRMLS_DC) {
ce_ptr = (zend_class_entry**)nr_php_zend_hash_find_ptr(EG(class_table), name);

return ce_ptr ? *ce_ptr : NULL;
#endif /* PHP7 */
#endif /* PHP7+ */
}

zend_function* nr_php_find_class_method(const zend_class_entry* klass,
Expand Down Expand Up @@ -260,15 +261,15 @@ zend_function* nr_php_zval_to_function(zval* zv TSRMLS_DC) {
return NULL;
}

#ifdef PHP7
#if ZEND_MODULE_API_NO >= ZEND_7_0_X_API_NO /* PHP 7.0+ */
if (zend_is_callable_ex(zv, NULL, 0, NULL, &fcc, NULL)) {
return fcc.function_handler;
}
#else
if (zend_is_callable_ex(zv, NULL, 0, NULL, NULL, &fcc, NULL TSRMLS_CC)) {
return fcc.function_handler;
}
#endif /* PHP7 */
#endif /* PHP7+ */

return NULL;
}
Expand Down Expand Up @@ -319,8 +320,8 @@ zend_execute_data* nr_get_zend_execute_data(NR_EXECUTE_PROTO TSRMLS_DC) {
*
* See the picture near line 1525 of PHP 5.5.3 zend_execute.c
*/
#if ZEND_MODULE_API_NO >= ZEND_5_5_X_API_NO \
&& !defined(PHP7) /* PHP 5.5 and 5.6 */
#if ZEND_MODULE_API_NO >= ZEND_5_5_X_API_NO && !defined(PHP7) \
&& !defined(PHP8) /* PHP 5.5 and 5.6 */
static void** nr_php_get_php55_stack_arguments(int legitimate_frame_delta,
NR_EXECUTE_PROTO TSRMLS_DC) {
zend_execute_data* ex;
Expand Down Expand Up @@ -358,7 +359,7 @@ static void** nr_php_get_php55_stack_arguments(int legitimate_frame_delta,
}
#endif

#ifndef PHP7
#if !defined(PHP7) && !defined(PHP8) /* PHP 5.5 and 5.6 */
/*
* Use detailed zend specific knowledge of the interpreter stack
* to read the argument vector.
Expand Down Expand Up @@ -408,7 +409,7 @@ static zval* nr_php_get_user_func_arg_via_h(int requested_arg_index,
arg = *argp;
return arg;
}
#endif /* !PHP7 */
#endif /* !PHP7 && !PHP8*/

/*
* NOTICE: requested_arg_index is a 1-based value, not a 0-based value!
Expand All @@ -422,7 +423,7 @@ zval* nr_php_get_user_func_arg(size_t requested_arg_index,
return NULL;
}

#ifdef PHP7
#if ZEND_MODULE_API_NO >= ZEND_7_0_X_API_NO /* PHP 7.0+ */
(void)arg_count_via_h;

if (requested_arg_index > ZEND_CALL_NUM_ARGS(execute_data)) {
Expand All @@ -433,13 +434,13 @@ zval* nr_php_get_user_func_arg(size_t requested_arg_index,
#else
arg_via_h = nr_php_get_user_func_arg_via_h(
requested_arg_index, &arg_count_via_h, NR_EXECUTE_ORIG_ARGS TSRMLS_CC);
#endif /* PHP7 */
#endif /* PHP7+ */

return arg_via_h;
}

size_t nr_php_get_user_func_arg_count(NR_EXECUTE_PROTO TSRMLS_DC) {
#ifdef PHP7
#if ZEND_MODULE_API_NO >= ZEND_7_0_X_API_NO /* PHP 7.0+ */
return (size_t)ZEND_CALL_NUM_ARGS(execute_data);
#else
int arg_count_via_h = -1;
Expand All @@ -455,7 +456,7 @@ size_t nr_php_get_user_func_arg_count(NR_EXECUTE_PROTO TSRMLS_DC) {
}

return (size_t)arg_count_via_h;
#endif /* PHP7 */
#endif /* PHP7+ */
}

zend_execute_data* nr_php_get_caller_execute_data(NR_EXECUTE_PROTO,
Expand Down Expand Up @@ -484,30 +485,30 @@ zend_execute_data* nr_php_get_caller_execute_data(NR_EXECUTE_PROTO,
ced = ced->prev_execute_data;
}

#ifdef PHP7
#if ZEND_MODULE_API_NO >= ZEND_7_0_X_API_NO /* PHP 7.0+ */
if ((NULL == ced) || (NULL == ced->opline)) {
return NULL;
}
#else
if ((NULL == ced) || (NULL == ced->op_array)) {
return NULL;
}
#endif /* PHP7 */
#endif /* PHP7+ */

if ((ZEND_DO_FCALL != ced->opline->opcode)
&& (ZEND_DO_FCALL_BY_NAME != ced->opline->opcode)) {
return NULL;
}

#ifdef PHP7
#if ZEND_MODULE_API_NO >= ZEND_7_0_X_API_NO /* PHP 7.0+ */
if (NULL == ced->func) {
return NULL;
}
#else
if (0 == ced->function_state.function) {
return NULL;
}
#endif /* PHP7 */
#endif /* PHP7+ */

return ced;
}
Expand All @@ -521,17 +522,17 @@ const zend_function* nr_php_get_caller(NR_EXECUTE_PROTO,
return NULL;
}

#ifdef PHP7
#if ZEND_MODULE_API_NO >= ZEND_7_0_X_API_NO /* PHP 7.0+ */
return ped->func;
#else
return ped->function_state.function;
#endif /* PHP7 */
#endif /* PHP7+ */
}

zval* nr_php_get_active_php_variable(const char* name TSRMLS_DC) {
HashTable* table;

#ifdef PHP7
#if ZEND_MODULE_API_NO >= ZEND_7_0_X_API_NO /* PHP 7.0+ */
table = zend_rebuild_symbol_table();

/*
Expand All @@ -548,7 +549,7 @@ zval* nr_php_get_active_php_variable(const char* name TSRMLS_DC) {
#else
table = EG(active_symbol_table);
return nr_php_zend_hash_find(table, name);
#endif /* PHP7 */
#endif /* PHP7+ */
}

int nr_php_silence_errors(TSRMLS_D) {
Expand All @@ -564,7 +565,7 @@ void nr_php_restore_errors(int error_reporting TSRMLS_DC) {
}

zval* nr_php_get_constant(const char* name TSRMLS_DC) {
#ifdef PHP7
#if ZEND_MODULE_API_NO >= ZEND_7_0_X_API_NO /* PHP 7.0+ */
zval* constant;
zval* copy = NULL;
zend_string* name_str;
Expand Down Expand Up @@ -608,7 +609,7 @@ zval* nr_php_get_constant(const char* name TSRMLS_DC) {
}

return constant;
#endif /* PHP7 */
#endif /* PHP7+ */
}

zval* nr_php_get_class_constant(const zend_class_entry* ce, const char* name) {
Expand Down Expand Up @@ -674,7 +675,7 @@ int nr_php_is_zval_named_constant(const zval* zv, const char* name TSRMLS_DC) {
}

int nr_php_zend_is_auto_global(const char* name, size_t name_len TSRMLS_DC) {
#ifdef PHP7
#if ZEND_MODULE_API_NO >= ZEND_7_0_X_API_NO /* PHP 7.0+ */
zend_bool rv;
zend_string* zs = zend_string_init(name, name_len, 0);

Expand All @@ -684,7 +685,7 @@ int nr_php_zend_is_auto_global(const char* name, size_t name_len TSRMLS_DC) {
return rv;
#else
return (int)zend_is_auto_global(name, (int)name_len TSRMLS_CC);
#endif /* PHP7 */
#endif /* PHP7+ */
}

const char* nr_php_use_license(const char* api_license TSRMLS_DC) {
Expand Down Expand Up @@ -712,7 +713,7 @@ char* nr_php_get_server_global(const char* name TSRMLS_DC) {
return NULL;
}

#ifdef PHP7
#if ZEND_MODULE_API_NO >= ZEND_7_0_X_API_NO /* PHP 7.0+ */
global = &(PG(http_globals)[TRACK_VARS_SERVER]);
#else
global = PG(http_globals)[TRACK_VARS_SERVER];
Expand Down Expand Up @@ -942,12 +943,12 @@ void nr_php_remove_interface_from_class(zend_class_entry* class_ce,
}
}

/*
* We have to discard the const qualifier on the interface class entry to
* pass it through to nr_php_zend_hash_ptr_apply, even though the apply
* callback itself takes a const zend_class_entry *. Since this generates a
* warning in gcc, we'll squash it.
*/
/*
* We have to discard the const qualifier on the interface class entry to
* pass it through to nr_php_zend_hash_ptr_apply, even though the apply
* callback itself takes a const zend_class_entry *. Since this generates a
* warning in gcc, we'll squash it.
*/
#if defined(__clang__) || (__GNUC__ > 4) \
|| ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5))
#pragma GCC diagnostic push
Expand Down Expand Up @@ -1039,11 +1040,11 @@ char* nr_php_function_debug_name(const zend_function* func) {

if ((ZEND_USER_FUNCTION == func->type)
&& (func->common.fn_flags & ZEND_ACC_CLOSURE)) {
#ifdef PHP7
#if ZEND_MODULE_API_NO >= ZEND_7_0_X_API_NO /* PHP 7.0+ */
const char* filename = ZSTR_VAL(func->op_array.filename);
#else
const char* filename = func->op_array.filename;
#endif /* PHP7 */
#endif /* PHP7+ */
char* orig_name = name;

name = nr_formatf("%s declared at %s:%d", orig_name, NRSAFESTR(filename),
Expand Down
Loading

0 comments on commit 93c8c0b

Please sign in to comment.