diff --git a/agent/Makefile.frag b/agent/Makefile.frag index c54a8cb0a..81e909637 100644 --- a/agent/Makefile.frag +++ b/agent/Makefile.frag @@ -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 # diff --git a/agent/fw_laravel.c b/agent/fw_laravel.c index 5777c188d..1251fae8c 100644 --- a/agent/fw_laravel.c +++ b/agent/fw_laravel.c @@ -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 { /* diff --git a/agent/fw_laravel_queue.c b/agent/fw_laravel_queue.c index a0025041c..d038936a6 100644 --- a/agent/fw_laravel_queue.c +++ b/agent/fw_laravel_queue.c @@ -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 @@ -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, @@ -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); } } @@ -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); diff --git a/agent/lib_guzzle6.c b/agent/lib_guzzle6.c index 02216b67b..45cfca5ab 100644 --- a/agent/lib_guzzle6.c +++ b/agent/lib_guzzle6.c @@ -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); } diff --git a/agent/php_agent.c b/agent/php_agent.c index 7ace7c010..0e8882d1d 100644 --- a/agent/php_agent.c +++ b/agent/php_agent.c @@ -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 @@ -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; } @@ -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; } @@ -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, @@ -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; } @@ -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, @@ -260,7 +261,7 @@ 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; } @@ -268,7 +269,7 @@ zend_function* nr_php_zval_to_function(zval* zv TSRMLS_DC) { if (zend_is_callable_ex(zv, NULL, 0, NULL, NULL, &fcc, NULL TSRMLS_CC)) { return fcc.function_handler; } -#endif /* PHP7 */ +#endif /* PHP7+ */ return NULL; } @@ -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; @@ -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. @@ -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! @@ -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)) { @@ -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; @@ -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, @@ -484,7 +485,7 @@ 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; } @@ -492,14 +493,14 @@ zend_execute_data* nr_php_get_caller_execute_data(NR_EXECUTE_PROTO, 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; } @@ -507,7 +508,7 @@ zend_execute_data* nr_php_get_caller_execute_data(NR_EXECUTE_PROTO, if (0 == ced->function_state.function) { return NULL; } -#endif /* PHP7 */ +#endif /* PHP7+ */ return ced; } @@ -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(); /* @@ -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) { @@ -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; @@ -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) { @@ -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); @@ -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) { @@ -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]; @@ -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 @@ -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), diff --git a/agent/php_agent.h b/agent/php_agent.h index ff2130ddd..69bd08039 100644 --- a/agent/php_agent.h +++ b/agent/php_agent.h @@ -330,7 +330,7 @@ extern zend_function* nr_php_zval_to_function(zval* zv TSRMLS_DC); * won't help you! */ static inline zval* nr_php_get_return_value(NR_EXECUTE_PROTO TSRMLS_DC) { -#ifdef PHP7 +#if ZEND_MODULE_API_NO >= ZEND_7_0_X_API_NO /* PHP 7.0+ */ if (NULL == execute_data) { /* * This function shouldn't be called from outside a function context, so @@ -346,7 +346,7 @@ static inline zval* nr_php_get_return_value(NR_EXECUTE_PROTO TSRMLS_DC) { NR_UNUSED_SPECIALFN; return return_value_ptr_ptr ? *return_value_ptr_ptr : NULL; -#endif /* PHP7 */ +#endif /* PHP7+ */ } /* @@ -358,7 +358,7 @@ static inline zval* nr_php_get_return_value(NR_EXECUTE_PROTO TSRMLS_DC) { * other "should not happen" situation. Note that this may be an * IS_REFERENCE zval in PHP 7 if the function expects a reference. * - * Warning : Directly modifying the returned zval in PHP 7 may result in + * Warning : Directly modifying the returned zval in PHP 7 may result in * difficult issues that are difficult to debug. * * IMPORTANT : This should only be called before the call to the current user @@ -389,14 +389,14 @@ static inline zend_function* nr_php_execute_function( } #endif -#ifdef PHP7 +#if ZEND_MODULE_API_NO >= ZEND_7_0_X_API_NO /* PHP 7.0+ */ return execute_data->func; #elif ZEND_MODULE_API_NO >= ZEND_5_5_X_API_NO return execute_data->function_state.function; #else return op_array_arg->prototype ? op_array_arg->prototype : (zend_function*)op_array_arg; -#endif /* PHP7 */ +#endif /* PHP7+ */ } static inline zval* nr_php_execute_scope(zend_execute_data* execute_data) { @@ -404,7 +404,7 @@ static inline zval* nr_php_execute_scope(zend_execute_data* execute_data) { return NULL; } -#ifdef PHP7 +#if ZEND_MODULE_API_NO >= ZEND_7_0_X_API_NO /* PHP 7.0+ */ return &execute_data->This; #else return execute_data->object; @@ -600,26 +600,26 @@ extern const char* nr_php_function_filename(zend_function* func); static inline zend_class_entry* nr_php_zend_register_internal_class_ex( zend_class_entry* ce, zend_class_entry* parent_ce TSRMLS_DC) { -#ifdef PHP7 +#if ZEND_MODULE_API_NO >= ZEND_7_0_X_API_NO /* PHP 7.0+ */ return zend_register_internal_class_ex(ce, parent_ce); #else return zend_register_internal_class_ex(ce, parent_ce, NULL TSRMLS_CC); -#endif /* PHP7 */ +#endif /* PHP7+ */ } static inline char* nr_php_zend_ini_string(char* name, nr_string_len_t name_len, int orig) { -#ifdef PHP7 +#if ZEND_MODULE_API_NO >= ZEND_7_0_X_API_NO /* PHP 7.0+ */ return zend_ini_string(name, name_len, orig); #else return zend_ini_string(name, name_len + 1, orig); -#endif /* PHP7 */ +#endif /* PHP7+ */ } static inline const char* NRPURE nr_php_class_entry_name(const zend_class_entry* ce) { -#ifdef PHP7 +#if ZEND_MODULE_API_NO >= ZEND_7_0_X_API_NO /* PHP 7.0+ */ return (ce->name && ce->name->len) ? ce->name->val : NULL; #else return ce->name; @@ -628,7 +628,7 @@ nr_php_class_entry_name(const zend_class_entry* ce) { static inline nr_string_len_t NRPURE nr_php_class_entry_name_length(const zend_class_entry* ce) { -#ifdef PHP7 +#if ZEND_MODULE_API_NO >= ZEND_7_0_X_API_NO /* PHP 7.0+ */ return ce->name ? ce->name->len : 0; #else return NRSAFELEN(ce->name_length); @@ -637,7 +637,7 @@ nr_php_class_entry_name_length(const zend_class_entry* ce) { static inline const char* NRPURE nr_php_function_name(const zend_function* func) { -#ifdef PHP7 +#if ZEND_MODULE_API_NO >= ZEND_7_0_X_API_NO /* PHP 7.0+ */ return (func->common.function_name && func->common.function_name->len) ? func->common.function_name->val : NULL; @@ -648,7 +648,7 @@ nr_php_function_name(const zend_function* func) { static inline nr_string_len_t NRPURE nr_php_function_name_length(const zend_function* func) { -#ifdef PHP7 +#if ZEND_MODULE_API_NO >= ZEND_7_0_X_API_NO /* PHP 7.0+ */ return func->common.function_name ? func->common.function_name->len : 0; #else /* @@ -661,7 +661,7 @@ nr_php_function_name_length(const zend_function* func) { static inline const char* NRPURE nr_php_op_array_file_name(const zend_op_array* op_array) { -#ifdef PHP7 +#if ZEND_MODULE_API_NO >= ZEND_7_0_X_API_NO /* PHP 7.0+ */ return (op_array->filename && op_array->filename->len) ? op_array->filename->val : NULL; @@ -672,7 +672,7 @@ nr_php_op_array_file_name(const zend_op_array* op_array) { static inline const char* NRPURE nr_php_op_array_function_name(const zend_op_array* op_array) { -#ifdef PHP7 +#if ZEND_MODULE_API_NO >= ZEND_7_0_X_API_NO /* PHP 7.0+ */ return (op_array->function_name && op_array->function_name->len) ? op_array->function_name->val : NULL; @@ -683,7 +683,7 @@ nr_php_op_array_function_name(const zend_op_array* op_array) { static inline const char* NRPURE nr_php_op_array_scope_name(const zend_op_array* op_array) { -#ifdef PHP7 +#if ZEND_MODULE_API_NO >= ZEND_7_0_X_API_NO /* PHP 7.0+ */ if (op_array->scope && op_array->scope->name && op_array->scope->name->len) { return op_array->scope->name->val; } @@ -698,7 +698,7 @@ nr_php_op_array_scope_name(const zend_op_array* op_array) { static inline const char* NRPURE nr_php_ini_entry_name(const zend_ini_entry* entry) { -#ifdef PHP7 +#if ZEND_MODULE_API_NO >= ZEND_7_0_X_API_NO /* PHP 7.0+ */ return (entry->name && entry->name->len) ? entry->name->val : NULL; #else return entry->name; @@ -706,7 +706,7 @@ nr_php_ini_entry_name(const zend_ini_entry* entry) { } static inline nr_string_len_t NRPURE nr_php_ini_entry_name_length(const zend_ini_entry* entry) { -#ifdef PHP7 +#if ZEND_MODULE_API_NO >= ZEND_7_0_X_API_NO /* PHP 7.0+ */ return entry->name ? entry->name->len : 0; #else return NRSAFELEN(entry->name_length - 1); @@ -715,11 +715,18 @@ nr_php_ini_entry_name_length(const zend_ini_entry* entry) { #define NR_PHP_INTERNAL_FN_THIS() getThis() -#ifdef PHP7 +#if ZEND_MODULE_API_NO >= ZEND_7_0_X_API_NO /* PHP 7.0+ */ #define NR_PHP_USER_FN_THIS() getThis() #else #define NR_PHP_USER_FN_THIS() EG(This) -#endif +#endif /* PHP 7.0+ */ + +#if ZEND_MODULE_API_NO >= ZEND_8_0_X_API_NO /* PHP 8.0+ */ +/* PHP 8 expects zend_object not zval */ +#define ZVAL_OR_ZEND_OBJECT(x) Z_OBJ(*x) +#else +#define ZVAL_OR_ZEND_OBJECT(x) x +#endif /* PHP8+ */ /* * Purpose : Wrap the native PHP json_decode function for those times when we diff --git a/agent/php_api_distributed_trace.c b/agent/php_api_distributed_trace.c index 3173d8a9c..27248b33a 100644 --- a/agent/php_api_distributed_trace.c +++ b/agent/php_api_distributed_trace.c @@ -317,10 +317,10 @@ PHP_FUNCTION(newrelic_create_distributed_trace_payload) { NRPRG(txn), nr_txn_get_current_segment(NRPRG(txn), NULL)); if (payload) { - zend_update_property_string(nr_distributed_trace_payload_ce, return_value, - nr_remove_const(payload_text_prop), - sizeof(payload_text_prop) - 1, - payload TSRMLS_CC); + zend_update_property_string( + nr_distributed_trace_payload_ce, ZVAL_OR_ZEND_OBJECT(return_value), + nr_remove_const(payload_text_prop), sizeof(payload_text_prop) - 1, + payload TSRMLS_CC); nr_free(payload); } } @@ -384,7 +384,7 @@ PHP_FUNCTION(newrelic_insert_distributed_trace_headers) { tracestate = nr_txn_create_w3c_tracestate_header( NRPRG(txn), nr_txn_get_current_segment(NRPRG(txn), NULL)); -#ifdef PHP7 +#if ZEND_MODULE_API_NO >= ZEND_7_0_X_API_NO /* PHP 7.0+ */ SEPARATE_ARRAY(header_array); #endif /* PHP7 */ diff --git a/agent/php_call.c b/agent/php_call.c index 2e261bc36..f268fc59a 100644 --- a/agent/php_call.c +++ b/agent/php_call.c @@ -14,13 +14,15 @@ zval* nr_php_call_user_func(zval* object_ptr, const char* function_name, zend_uint param_count, zval* params[] TSRMLS_DC) { -#ifdef PHP7 - int zend_result; +#if ZEND_MODULE_API_NO >= ZEND_7_0_X_API_NO /* PHP 7.0+ */ + int zend_result = FAILURE; zval* fname = NULL; - int no_separation = 0; HashTable* symbol_table = NULL; zval* param_values = NULL; zval* retval = NULL; +#ifndef PHP8 + int no_separation = 0; +#endif /* PHP8 */ /* * Prevent an unused variable warning. PHP 7.1 changed call_user_function_ex @@ -46,9 +48,20 @@ zval* nr_php_call_user_func(zval* object_ptr, fname = nr_php_zval_alloc(); nr_php_zval_str(fname, function_name); +#if ZEND_MODULE_API_NO >= ZEND_8_0_X_API_NO /* PHP 8.0+ */ + + /* + * With PHP8, `call_user_function_ex` was removed and `call_user_function` + * became the recommended function. + */ + zend_result = call_user_function(EG(function_table), object_ptr, fname, + retval, param_count, param_values); + +#else zend_result = call_user_function_ex(EG(function_table), object_ptr, fname, retval, param_count, param_values, no_separation, symbol_table TSRMLS_CC); +#endif /* PHP8+ */ nr_php_zval_free(&fname); nr_free(param_values); @@ -59,7 +72,7 @@ zval* nr_php_call_user_func(zval* object_ptr, nr_php_zval_free(&retval); return NULL; -#else +#else /* PHP < 7 */ int zend_result; zval* fname = NULL; int no_separation = 0; @@ -114,14 +127,14 @@ zval* nr_php_call_user_func_catch(zval* object_ptr, } /* - * The approach for both PHP 5 and 7 is conceptually the same: persist the + * The approach for both PHP 5, 7, and 8 is conceptually the same: persist the * current exception pointer in the executor globals, then compare it after * the call has been made. If the pointer changes, then an exception was - * thrown. The key difference is that PHP 5 uses a zval, whereas PHP 7 uses + * thrown. The key difference is that PHP 5 uses a zval, whereas PHP 7+ uses * a zend_object. */ -#ifdef PHP7 +#if ZEND_MODULE_API_NO >= ZEND_7_0_X_API_NO /* PHP 7.0+ */ { zend_object* exception_obj = EG(exception); @@ -157,7 +170,7 @@ zval* nr_php_call_user_func_catch(zval* object_ptr, zend_clear_exception(TSRMLS_C); } } -#endif /* PHP7 */ +#endif /* PHP7+ */ return retval; } diff --git a/agent/php_compat.h b/agent/php_compat.h index 5916a2b9f..ef727e66a 100644 --- a/agent/php_compat.h +++ b/agent/php_compat.h @@ -6,6 +6,10 @@ #ifndef PHP_COMPAT_HDR #define PHP_COMPAT_HDR +#if ZEND_MODULE_API_NO >= ZEND_8_0_X_API_NO /* PHP 8.0+ */ +#define PHP8 +#endif /* PHP 8.0+ */ + #if ZEND_MODULE_API_NO >= ZEND_7_0_X_API_NO /* PHP 7.0+ */ #define PHP7 @@ -85,10 +89,10 @@ static inline zval* nr_php_zval_direct(zval* zv) { return zv; } - /* - * Reimplement some of the macros that PHP 7 defines to make iteration easier. - * For now, only the macros we actually need are implemented. - */ +/* + * Reimplement some of the macros that PHP 7 defines to make iteration easier. + * For now, only the macros we actually need are implemented. + */ #define ZEND_HASH_FOREACH(ht) \ do { \ diff --git a/agent/php_error.c b/agent/php_error.c index fcb51290c..063f11d38 100644 --- a/agent/php_error.c +++ b/agent/php_error.c @@ -444,25 +444,38 @@ static int nr_php_should_record_error(int type, const char* format TSRMLS_DC) { return 1; } - +#if ZEND_MODULE_API_NO >= ZEND_8_0_X_API_NO +void nr_php_error_cb(int type, + const char* error_filename, + uint error_lineno, + zend_string* message) { +#else void nr_php_error_cb(int type, const char* error_filename, uint error_lineno, const char* format, va_list args) { +#endif /* PHP >= 8.0 */ TSRMLS_FETCH(); + char* stack_json = NULL; + const char* errclass = NULL; + char* msg = NULL; +#if ZEND_MODULE_API_NO < ZEND_8_0_X_API_NO if (nr_php_should_record_error(type, format TSRMLS_CC)) { va_list args2; - char* stack_json = NULL; - const char* errclass = NULL; - char* msg = NULL; int len; va_copy(args2, args); len = vasprintf(&msg, format, args2); msg[len] = '\0'; +#else + if (nr_php_should_record_error(type, ZSTR_VAL(message))) { + msg = nr_strdup(ZSTR_VAL(message)); + +#endif /* PHP < 8.0 */ + stack_json = nr_php_backtrace_to_json(0 TSRMLS_CC); errclass = get_error_type_string(type); @@ -477,8 +490,13 @@ void nr_php_error_cb(int type, * Call through to the actual error handler. */ if (0 != NR_PHP_PROCESS_GLOBALS(orig_error_cb)) { +#if ZEND_MODULE_API_NO < ZEND_8_0_X_API_NO NR_PHP_PROCESS_GLOBALS(orig_error_cb) (type, error_filename, error_lineno, format, args); +#else + NR_PHP_PROCESS_GLOBALS(orig_error_cb) + (type, error_filename, error_lineno, message); +#endif /* PHP < 8.0 */ } } @@ -590,11 +608,10 @@ nr_status_t nr_php_error_record_exception_segment(nrtxn_t* txn, ce = Z_OBJCE_P(exception); klass = nr_strndup(ZEND_STRING_VALUE(ce->name), ZEND_STRING_LEN(ce->name)); - zend_err_file = - nr_php_get_zval_object_property(exception, "file" TSRMLS_CC); + zend_err_file = nr_php_get_zval_object_property(exception, "file" TSRMLS_CC); file = nr_strndup(Z_STRVAL_P(zend_err_file), Z_STRLEN_P(zend_err_file)); - zend_err_message = - nr_php_get_zval_object_property(exception, "message" TSRMLS_CC); + zend_err_message + = nr_php_get_zval_object_property(exception, "message" TSRMLS_CC); message = nr_strndup(Z_STRVAL_P(zend_err_message), Z_STRLEN_P(zend_err_message)); zend_err_line = nr_php_get_zval_object_property(exception, "line" TSRMLS_CC); diff --git a/agent/php_file_get_contents.c b/agent/php_file_get_contents.c index ac35f8600..bc85b0436 100644 --- a/agent/php_file_get_contents.c +++ b/agent/php_file_get_contents.c @@ -469,7 +469,7 @@ nr_status_t nr_php_file_get_contents_recurse_with_context( nr_php_zval_free(&context); if (rval) { ZVAL_ZVAL(return_value, rval, 0, 1); -#ifdef PHP7 +#if ZEND_MODULE_API_NO >= ZEND_7_0_X_API_NO /* PHP 7.0+ */ /* * Calling ZVAL_ZVAL with dtor set to true in PHP 7 won't free the * surrounding wrapper. diff --git a/agent/php_hash.h b/agent/php_hash.h index baceb0aac..f808af370 100644 --- a/agent/php_hash.h +++ b/agent/php_hash.h @@ -122,13 +122,18 @@ nr_php_zend_hash_key_string_value(const zend_hash_key* hash_key) { static inline int nr_php_add_assoc_zval(zval* arr, const char* key, zval* value) { -#ifdef PHP7 +#if ZEND_MODULE_API_NO >= ZEND_7_0_X_API_NO /* PHP 7.0+ */ zval copy; ZVAL_DUP(©, value); - return add_assoc_zval(arr, key, ©); +#ifdef PHP8 + add_assoc_zval(arr, key, ©); + return 0; #else + return add_assoc_zval(arr, key, ©); +#endif /* PHP8 */ +#else /* Less than PHP7 */ zval* copy; ALLOC_ZVAL(copy); diff --git a/agent/php_hooks.h b/agent/php_hooks.h index 0df230f05..d42aa55a7 100644 --- a/agent/php_hooks.h +++ b/agent/php_hooks.h @@ -29,15 +29,38 @@ extern void nr_php_execute(NR_EXECUTE_PROTO TSRMLS_DC); * 3. The line number the error occurred on. * 4. The format type of the error message. * 5. The args that combine to get the error message. + * + * Notes: + * + * PHP8 changed how this is handled. + * Error notifications have a new API. Instead of overwriting zend_error_cb + * extensions with debugging, monitoring use-cases catching Errors/Exceptions + * are strongly encouraged to use the new error notification API instead. + * Error notification callbacks are guaranteed to be called regardless of the + * users error_reporting setting or userland error handler return values. + * Register notification callbacks during MINIT of an extension: +void my_error_notify_cb(int type, + const char *error_filename, + uint32_t error_lineno, + zend_string *message) { + } + zend_register_error_notify_callback(my_error_notify_cb); */ +#if ZEND_MODULE_API_NO >= ZEND_8_0_X_API_NO +extern void nr_php_error_cb(int type, + const char* filename, + uint error_lineno, + zend_string* message); +#else extern void nr_php_error_cb(int type, const char* filename, uint error_lineno, const char* fmt, va_list args) ZEND_ATTRIBUTE_PTR_FORMAT(printf, 4, 0); +#endif /* PHP >= 8.0 */ -#if defined(PHP7) +#if ZEND_MODULE_API_NO >= ZEND_7_0_X_API_NO /* PHP 7.0+ */ extern void nr_php_execute_internal(zend_execute_data* execute_data, zval* return_value); #elif ZEND_MODULE_API_NO >= ZEND_5_5_X_API_NO diff --git a/agent/php_includes.h b/agent/php_includes.h index aec4fcead..209ccfe51 100644 --- a/agent/php_includes.h +++ b/agent/php_includes.h @@ -49,6 +49,7 @@ #define ZEND_7_2_X_API_NO 20170718 #define ZEND_7_3_X_API_NO 20180731 #define ZEND_7_4_X_API_NO 20190902 +#define ZEND_8_0_X_API_NO 20200930 #if ZEND_MODULE_API_NO >= ZEND_5_6_X_API_NO #include "Zend/zend_virtual_cwd.h" @@ -60,4 +61,17 @@ #include "TSRM.h" #endif +/* + * The TSRMLS_* functions included below have actually been voided out since PHP + * 7.0. They were formally removed in PHP 8.0 but we still support in our code, + * so we need to add the voided out macros here. + */ +#if ZEND_MODULE_API_NO >= ZEND_8_0_X_API_NO +#define TSRMLS_D void +#define TSRMLS_DC +#define TSRMLS_C +#define TSRMLS_CC +#define TSRMLS_FETCH() +#endif + #endif /* PHP_INCLUDES_HDR */ diff --git a/agent/php_internal_instrument.c b/agent/php_internal_instrument.c index 382967134..8248934eb 100644 --- a/agent/php_internal_instrument.c +++ b/agent/php_internal_instrument.c @@ -134,7 +134,7 @@ static void nr_php_instrument_delegate(nrinternalfn_t* wraprec, } #else #define NR_OUTER_WRAPPER(RAW) \ - static nrinternalfn_t* NR_OUTER_GLOBAL_NAME(RAW) = NULL; \ + static nrinternalfn_t* NR_OUTER_GLOBAL_NAME(RAW) = NULL; \ static void ZEND_FASTCALL NR_OUTER_WRAPPER_NAME(RAW)( \ INTERNAL_FUNCTION_PARAMETERS) { \ nr_php_instrument_delegate(NR_OUTER_GLOBAL_NAME(RAW), \ @@ -231,11 +231,25 @@ void nr_php_wrap_internal_function(nrinternalfn_t* wraprec TSRMLS_DC) { return; } } + /* + * PHP has a feature to disable certain functions and classes with + * disable_functions and disable_classes INI directives. This is often used + * as a security measure to disable potentially unsafe functions. + * + * This functionality still exists in PHP 8, but the disabled functions + * behave as if they are not declared at all. + * Prior to PHP 8, attempting to use a disabled function resulted in a + * warning. + * In PHP 8 and later, attempting to use a disabled function will throw a + * standard error for an undeclared function as it is indistinguishable + * from a function that does not exist. + */ /* * If the internal function is disabled, don't wrap it; doing so breaks * function_exists(), and it can't be invoked anyway. */ +#ifndef PHP8 if (zif_display_disabled_function == ((zend_internal_function*)orig_func)->handler) { nrl_verbosedebug( @@ -244,6 +258,7 @@ void nr_php_wrap_internal_function(nrinternalfn_t* wraprec TSRMLS_DC) { NRP_PHP(wraprec->full_name)); return; } +#endif /* not PHP8 */ if (wraprec->outer_wrapper_global) { /* @@ -1431,9 +1446,8 @@ NR_INNER_WRAPPER(redis_connect) { == zend_parse_parameters_ex( ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "s|lzzz", &host, &host_len, &port, &ignore1, &ignore2, &ignore3)) { - instance = nr_php_redis_save_datastore_instance( - NR_PHP_INTERNAL_FN_THIS(), host, - port TSRMLS_CC); + instance = nr_php_redis_save_datastore_instance(NR_PHP_INTERNAL_FN_THIS(), + host, port TSRMLS_CC); } nr_php_instrument_datastore_operation_call(nr_wrapper, NR_DATASTORE_REDIS, @@ -2773,7 +2787,7 @@ static inline int nr_php_should_instrument_exception_handler( NR_INNER_WRAPPER(exception_common) { zval* exception_handler = NULL; -#ifdef PHP7 +#if ZEND_MODULE_API_NO >= ZEND_7_0_X_API_NO /* PHP 7.0+ */ exception_handler = &EG(user_exception_handler); #else exception_handler = EG(user_exception_handler); @@ -2795,7 +2809,7 @@ NR_INNER_WRAPPER(exception_common) { */ nr_wrapper->oldhandler(INTERNAL_FUNCTION_PARAM_PASSTHRU); -#ifdef PHP7 +#if ZEND_MODULE_API_NO >= ZEND_7_0_X_API_NO /* PHP 7.0+ */ exception_handler = &EG(user_exception_handler); #else exception_handler = EG(user_exception_handler); @@ -2809,11 +2823,11 @@ NR_INNER_WRAPPER(exception_common) { func = nr_php_zval_to_function(exception_handler TSRMLS_CC); nr_php_add_exception_function(func TSRMLS_CC); -#ifdef PHP7 +#if ZEND_MODULE_API_NO >= ZEND_7_0_X_API_NO /* PHP 7.0+ */ } else if (IS_UNDEF == Z_TYPE_P(exception_handler)) { #else } else if (NULL == exception_handler) { -#endif /* PHP7 */ +#endif /* PHP7+ */ nr_php_error_install_exception_handler(TSRMLS_C); } } @@ -3067,13 +3081,13 @@ void nr_php_generate_internal_wrap_records(void) { NR_INTERNAL_WRAPREC("mysqli_stmt_init", mysqli_stmt_init, mysqli_stmt_init, 0, 0) -#ifdef PHP7 +#if ZEND_MODULE_API_NO >= ZEND_7_0_X_API_NO /* PHP 7.0+ */ NR_INTERNAL_WRAPREC("mysqli::__construct", mysqliC_construct, mysqli_construct, 0, 0) #else NR_INTERNAL_WRAPREC("mysqli::mysqli", mysqliC_construct, mysqli_construct, 0, 0) -#endif /* PHP7 */ +#endif /* PHP7+ */ NR_INTERNAL_WRAPREC("mysqli::multi_query", mysqliC_multi_query, mysqli_general_query, 0, 0) diff --git a/agent/php_minit.c b/agent/php_minit.c index 7d9db57d2..eb80997b4 100644 --- a/agent/php_minit.c +++ b/agent/php_minit.c @@ -356,7 +356,11 @@ PHP_MINIT_FUNCTION(newrelic) { int daemon_connect_succeeded; nr_conn_params_t* conn_params; +#if ZEND_MODULE_API_NO < ZEND_8_0_X_API_NO /* < PHP8 */ zend_extension dummy; +#else + char dummy[] = "newrelic"; +#endif (void)type; @@ -610,8 +614,11 @@ PHP_MINIT_FUNCTION(newrelic) { nr_php_set_opcode_handlers(); nrl_debug(NRL_INIT, "MINIT processing done"); +#if ZEND_MODULE_API_NO >= ZEND_8_0_X_API_NO /* PHP 7.4+ */ + NR_PHP_PROCESS_GLOBALS(zend_offset) = zend_get_resource_handle(dummy); +#else NR_PHP_PROCESS_GLOBALS(zend_offset) = zend_get_resource_handle(&dummy); - +#endif return (SUCCESS); } diff --git a/agent/php_newrelic.c b/agent/php_newrelic.c index 233ab914d..8a55abe0f 100644 --- a/agent/php_newrelic.c +++ b/agent/php_newrelic.c @@ -114,6 +114,12 @@ void nr_print_globals(FILE* fp) { /* * New Relic API function argument descriptors. */ + +#if ZEND_MODULE_API_NO >= ZEND_8_0_X_API_NO /* PHP 8.0+ */ +ZEND_BEGIN_ARG_INFO_EX(newrelic_arginfo_void, 0, 0, 0) +ZEND_END_ARG_INFO() +#endif /* PHP 8.0+ */ + ZEND_BEGIN_ARG_INFO_EX(newrelic_add_custom_parameter_arginfo, 0, 0, 2) ZEND_ARG_INFO(0, parameter) ZEND_ARG_INFO(0, value) @@ -263,13 +269,9 @@ static zend_function_entry newrelic_functions[] = { /* * API Functions */ - PHP_FE(newrelic_ignore_transaction, 0) - PHP_FE(newrelic_ignore_apdex, 0) - PHP_FE(newrelic_end_of_transaction,0) PHP_FE(newrelic_end_transaction,newrelic_end_transaction_arginfo) PHP_FE(newrelic_start_transaction,newrelic_start_transaction_arginfo) PHP_FE(newrelic_background_job, newrelic_background_job_arginfo) - PHP_FE(newrelic_notice_error,0) PHP_FE(newrelic_add_custom_parameter,newrelic_add_custom_parameter_arginfo) PHP_FE(newrelic_name_transaction, newrelic_name_transaction_arginfo) PHP_FE(newrelic_add_custom_tracer,newrelic_add_custom_tracer_arginfo) @@ -278,16 +280,31 @@ static zend_function_entry newrelic_functions[] = { PHP_FE(newrelic_enable_params,newrelic_enable_params_arginfo) PHP_FE(newrelic_get_browser_timing_header,newrelic_browser_timing_arginfo) PHP_FE(newrelic_get_browser_timing_footer,newrelic_browser_timing_arginfo) - PHP_FE(newrelic_disable_autorum, 0) PHP_FE(newrelic_set_appname, newrelic_set_appname_arginfo) PHP_FE(newrelic_set_user_attributes, newrelic_set_user_attributes_arginfo) PHP_FE(newrelic_record_custom_event, newrelic_record_custom_event_arginfo) PHP_FE(newrelic_record_datastore_segment, newrelic_record_datastore_segment_arginfo) PHP_FE(newrelic_create_distributed_trace_payload, newrelic_create_distributed_trace_payload_arginfo) PHP_FE(newrelic_insert_distributed_trace_headers, newrelic_insert_distributed_trace_headers_arginfo) - PHP_FE(newrelic_is_sampled, 0) PHP_FE(newrelic_add_custom_span_parameter, newrelic_add_custom_span_parameter_arginfo) +#if ZEND_MODULE_API_NO >= ZEND_8_0_X_API_NO /* PHP 8.0+ */ + PHP_FE(newrelic_ignore_transaction, newrelic_arginfo_void) + PHP_FE(newrelic_ignore_apdex, newrelic_arginfo_void) + PHP_FE(newrelic_end_of_transaction, newrelic_arginfo_void) + PHP_FE(newrelic_notice_error, newrelic_arginfo_void) + PHP_FE(newrelic_disable_autorum, newrelic_arginfo_void) + PHP_FE(newrelic_is_sampled, newrelic_arginfo_void) +#else + PHP_FE(newrelic_ignore_transaction, 0) + PHP_FE(newrelic_ignore_apdex, 0) + PHP_FE(newrelic_end_of_transaction,0) + PHP_FE(newrelic_notice_error,0) + PHP_FE(newrelic_disable_autorum, 0) + PHP_FE(newrelic_is_sampled, 0) +#endif /* PHP8+ */ + + /* * Other Functions */ @@ -295,23 +312,38 @@ static zend_function_entry newrelic_functions[] = { PHP_FE(newrelic_add_headers_to_context, newrelic_add_headers_to_context_arginfo) PHP_FE(newrelic_remove_headers_from_context, newrelic_remove_headers_from_context_arginfo) PHP_FE(newrelic_exception_handler, newrelic_exception_handler_arginfo) - PHP_FE(newrelic_get_request_metadata, 0) PHP_FE(newrelic_accept_distributed_trace_headers, newrelic_accept_distributed_trace_headers_arginfo) PHP_FE(newrelic_accept_distributed_trace_payload, newrelic_accept_distributed_trace_payload_arginfo) PHP_FE(newrelic_accept_distributed_trace_payload_httpsafe, newrelic_accept_distributed_trace_payload_httpsafe_arginfo) + +#ifdef PHP8 + PHP_FE(newrelic_get_request_metadata, newrelic_arginfo_void) + PHP_FE(newrelic_get_linking_metadata, newrelic_arginfo_void) + PHP_FE(newrelic_get_trace_metadata, newrelic_arginfo_void) +#else + PHP_FE(newrelic_get_request_metadata, 0) PHP_FE(newrelic_get_linking_metadata, 0) PHP_FE(newrelic_get_trace_metadata, 0) +#endif /* PHP 8 */ /* * Integration test helpers */ #ifdef ENABLE_TESTING_API - PHP_FE(newrelic_get_hostname, 0) PHP_FE(newrelic_get_metric_table, newrelic_get_metric_table_arginfo) + PHP_FE(newrelic_is_localhost, newrelic_is_localhost_arginfo) + +#if ZEND_MODULE_API_NO >= ZEND_8_0_X_API_NO /* PHP 8.0+ */ + PHP_FE(newrelic_get_hostname, newrelic_arginfo_void) + PHP_FE(newrelic_get_slowsqls, newrelic_arginfo_void) + PHP_FE(newrelic_get_trace_json, newrelic_arginfo_void) + PHP_FE(newrelic_is_recording, newrelic_arginfo_void) +#else + PHP_FE(newrelic_get_hostname, 0) PHP_FE(newrelic_get_slowsqls, 0) PHP_FE(newrelic_get_trace_json, 0) - PHP_FE(newrelic_is_localhost, newrelic_is_localhost_arginfo) PHP_FE(newrelic_is_recording, 0) +#endif /* PHP 8 */ #endif /* ENABLE_TESTING_API */ diff --git a/agent/php_newrelic.h b/agent/php_newrelic.h index 782330e1e..66f9157f2 100644 --- a/agent/php_newrelic.h +++ b/agent/php_newrelic.h @@ -39,7 +39,7 @@ extern zend_module_entry newrelic_module_entry; * majority of those changes so the rest of the code can simply use the macros * and not have to take the different APIs into account. */ -#ifdef PHP7 +#if ZEND_MODULE_API_NO >= ZEND_7_0_X_API_NO /* PHP 7.0+ */ #define NR_SPECIALFNPTR_PROTO \ struct _nruserfn_t *wraprec, nr_segment_t *auto_segment, \ zend_execute_data *execute_data @@ -74,7 +74,7 @@ extern zend_module_entry newrelic_module_entry; #define NR_ZEND_EXECUTE_HOOK zend_execute #endif -#ifdef PHP7 +#if ZEND_MODULE_API_NO >= ZEND_7_0_X_API_NO /* PHP 7.0+ */ #define NR_UNUSED_EXECUTE_DATA (void)execute_data; #define NR_UNUSED_HT #define NR_UNUSED_RETURN_VALUE (void)return_value; @@ -88,12 +88,12 @@ extern zend_module_entry newrelic_module_entry; #define NR_UNUSED_RETURN_VALUE_PTR (void)return_value_ptr; #define NR_UNUSED_RETURN_VALUE_USED (void)return_value_used; #define NR_UNUSED_THIS_PTR (void)this_ptr; -#endif /* PHP7 */ +#endif /* PHP7+ */ /* * Convenience macro to handle unused TSRM parameters. */ -#if ZTS && !defined(PHP7) +#if ZTS && !defined(PHP7) && !defined(PHP8) #define NR_UNUSED_TSRMLS (void)tsrm_ls; #else #define NR_UNUSED_TSRMLS @@ -181,12 +181,19 @@ typedef void (*nrphpfn_t)(INTERNAL_FUNCTION_PARAMETERS); typedef void(ZEND_FASTCALL* nrphpfn_t)(INTERNAL_FUNCTION_PARAMETERS); #endif /* PHP < 7.3 */ +#if ZEND_MODULE_API_NO >= ZEND_8_0_X_API_NO typedef void (*nrphperrfn_t)(int type, - const char* filenm, - uint lineno, + const char* error_filename, + uint error_lineno, + zend_string* message); +#else +typedef void (*nrphperrfn_t)(int type, + const char* error_filename, + uint error_lineno, const char* fmt, va_list args) ZEND_ATTRIBUTE_PTR_FORMAT(printf, 4, 0); +#endif /* PHP >= 8.0 */ typedef zend_op_array* (*nrphpcfile_t)(zend_file_handle* file_handle, int type TSRMLS_DC); typedef zend_op_array* (*nrphpcstr_t)(zval* source_string, @@ -198,7 +205,7 @@ typedef int (*nrphphdrfn_t)(sapi_header_struct* sapi_header, sapi_header_op_enum op, sapi_headers_struct* sapi_headers TSRMLS_DC); -#if defined(PHP7) +#if ZEND_MODULE_API_NO >= ZEND_7_0_X_API_NO /* PHP 7.0+ */ typedef void (*nr_php_execute_internal_function_t)( zend_execute_data* execute_data, zval* return_value); diff --git a/agent/php_vm.c b/agent/php_vm.c index a9e58c326..2a7f8eee4 100644 --- a/agent/php_vm.c +++ b/agent/php_vm.c @@ -8,7 +8,7 @@ #include "php_call.h" #include "util_logging.h" -#ifdef PHP7 +#if ZEND_MODULE_API_NO >= ZEND_7_0_X_API_NO /* PHP 7.0+ */ /* * An entry in the previous_opcode_handlers table. @@ -134,8 +134,8 @@ static int nr_php_handle_cufa_fcall(zend_execute_data* execute_data) { /* * To actually determine whether this is a call_user_func_array() call we - * have to look at the previous opcode. ZEND_DO_FCALL will never be the first - * opcode in an op array -- minimally, there is always at least a + * have to look at one of the previous opcodes. ZEND_DO_FCALL will never be + * the first opcode in an op array -- minimally, there is always at least a * ZEND_INIT_FCALL before it -- so this is safe. * * When PHP 7 flattens a call_user_func_array() call into direct opcodes, it @@ -146,15 +146,23 @@ static int nr_php_handle_cufa_fcall(zend_execute_data* execute_data) { * https://github.com/php/php-src/blob/php-7.0.19/Zend/zend_compile.c#L3082-L3098 * https://github.com/php/php-src/blob/php-7.1.5/Zend/zend_compile.c#L3564-L3580 * + * In PHP 8, a ZEND_CHECK_UNDEF_ARGS opcode is added after the call to + * ZEND_SEND_ARRAY and before ZEND_DO_FCALL so we need to look back two opcodes + * instead of just one. + * * Note that this heuristic will fail if the Zend Engine ever starts - * compiling flattened call_user_func_array() calls differently. (There is a - * change coming in PHP 7.2, but it only optimizes array_slice() calls, which - * as an internal function won't get this far anyway.) We can disable this - * behaviour by setting the ZEND_COMPILE_NO_BUILTINS compiler flag, but since - * that will cause additional performance overhead, this should be considered - * a last resort. + * compiling flattened call_user_func_array() calls differently. PHP 7.2 made a + * change, but it only optimized array_slice() calls, which as an internal + * function won't get this far anyway.) We can disable this behaviour by setting + * the ZEND_COMPILE_NO_BUILTINS compiler flag, but since that will cause + * additional performance overhead, this should be considered a last resort. */ +#ifdef PHP8 + prev_opline = execute_data->opline - 2; +#else prev_opline = execute_data->opline - 1; +#endif + if (ZEND_SEND_ARRAY == prev_opline->opcode) { if (UNEXPECTED((NULL == execute_data->call) || (NULL == execute_data->call->func))) { @@ -216,4 +224,4 @@ void nr_php_set_opcode_handlers(void) {} void nr_php_remove_opcode_handlers(void) {} -#endif /* PHP7 */ +#endif /* PHP 7.0+ */ diff --git a/agent/php_zval.h b/agent/php_zval.h index 54159cd41..5991c1198 100644 --- a/agent/php_zval.h +++ b/agent/php_zval.h @@ -58,9 +58,9 @@ * nr_php_zval_free() rather than nr_php_zval_dtor(). */ inline static zval* nr_php_zval_alloc(void) { - zval* zv; + zval* zv = NULL; -#ifdef PHP7 +#if ZEND_MODULE_API_NO >= ZEND_7_0_X_API_NO /* PHP 7.0+ */ zv = (zval*)emalloc(sizeof(zval)); ZVAL_UNDEF(zv); #else @@ -343,7 +343,7 @@ static inline void nr_php_zval_bool(zval* zv, int b) { * that function will then set the value). */ static inline void nr_php_zval_prepare_out_arg(zval* zv) { -#ifdef PHP7 +#if ZEND_MODULE_API_NO >= ZEND_7_0_X_API_NO /* PHP 7.0+ */ ZVAL_NEW_REF(zv, &EG(uninitialized_zval)); #else ZVAL_NULL(zv); @@ -363,7 +363,7 @@ static inline void nr_php_zval_prepare_out_arg(zval* zv) { * Note that you will need to use nr_php_zval_real_value() (below) if you don't * want to do this in place. */ -#ifdef PHP7 +#if ZEND_MODULE_API_NO >= ZEND_7_0_X_API_NO /* PHP 7.0+ */ #define nr_php_zval_unwrap(zv) ZVAL_DEREF(zv) /* diff --git a/agent/tests/test_api_internal.c b/agent/tests/test_api_internal.c index b8b0143bb..e859bbf19 100644 --- a/agent/tests/test_api_internal.c +++ b/agent/tests/test_api_internal.c @@ -55,11 +55,26 @@ static void test_invalid_parameters(TSRMLS_D) { tlib_php_request_start(); /* Literally any parameter should cause this to bail. */ +#ifdef PHP8 + tlib_php_request_eval("$exception = false;" + "try {" + " $value = newrelic_get_trace_json('invalid');" + " echo \"No exception, returned \" . $value . \".\\n\";" + "} catch(ArgumentCountError $_e) {" + " $exception = true;" + "}" TSRMLS_CC); + retval = tlib_php_request_eval_expr("$exception;" TSRMLS_CC); + + tlib_pass_if_zval_is_bool_true( + "newrelic_get_trace_json() throws an exception when a parameter is given", + retval); +#else retval = nr_php_call(NULL, "newrelic_get_trace_json", param); tlib_pass_if_zval_is_bool_false( "newrelic_get_trace_json() returns false when a parameter is given", retval); +#endif nr_php_zval_free(¶m); nr_php_zval_free(&retval); diff --git a/agent/tests/test_zval.c b/agent/tests/test_zval.c index 5905a265c..630cdd258 100644 --- a/agent/tests/test_zval.c +++ b/agent/tests/test_zval.c @@ -93,13 +93,18 @@ static void test_is_zval_valid_callable(TSRMLS_D) { test_valid_callable("'date'" TSRMLS_CC); test_valid_callable( "array(new ReflectionFunction('date'), 'isDisabled')" TSRMLS_CC); +#ifdef PHP8 + test_valid_callable("array('ReflectionReference', 'fromArrayElement')" TSRMLS_CC); + test_valid_callable("'ReflectionReference::fromArrayElement'" TSRMLS_CC); +#else test_valid_callable("array('ReflectionFunction', 'export')" TSRMLS_CC); test_valid_callable("'ReflectionFunction::export'" TSRMLS_CC); +#endif test_valid_callable("function () {}" TSRMLS_CC); -#ifdef PHP7 +#if ZEND_MODULE_API_NO >= ZEND_7_0_X_API_NO /* PHP 7.0+ */ test_valid_callable("new class { function __invoke() {} }" TSRMLS_CC); -#endif /* PHP7 */ +#endif /* PHP 7.0+ */ tlib_php_request_end(); } diff --git a/agent/tests/tlib_php.c b/agent/tests/tlib_php.c index 853f2145c..daadf32da 100644 --- a/agent/tests/tlib_php.c +++ b/agent/tests/tlib_php.c @@ -125,7 +125,12 @@ static const char* tlib_php_new_interned_string(const char* key, } #endif -#if ZEND_MODULE_API_NO >= ZEND_7_3_X_API_NO +#if ZEND_MODULE_API_NO >= ZEND_8_0_X_API_NO +static zend_string* ZEND_FASTCALL +tlib_php_init_interned_string(const char* str, size_t size, bool permanent) { + return zend_string_init(str, size, permanent); +} +#elif ZEND_MODULE_API_NO >= ZEND_7_3_X_API_NO static zend_string* ZEND_FASTCALL tlib_php_init_interned_string(const char* str, size_t size, int permanent) { @@ -429,7 +434,14 @@ zval* tlib_php_request_eval_expr(const char* code TSRMLS_DC) { return rv; } -#if ZEND_MODULE_API_NO >= ZEND_7_3_X_API_NO +#if ZEND_MODULE_API_NO >= ZEND_8_0_X_API_NO +static void tlib_php_error_silence_cb(int type NRUNUSED, + const char* error_filename NRUNUSED, + const uint32_t error_lineno NRUNUSED, + zend_string* message NRUNUSED) { + /* Squash the error by doing absolutely nothing. */ +} +#elif ZEND_MODULE_API_NO >= ZEND_7_3_X_API_NO static void tlib_php_error_silence_cb(int type NRUNUSED, const char* error_filename NRUNUSED, const uint32_t error_lineno NRUNUSED, @@ -442,7 +454,9 @@ static void tlib_php_error_silence_cb(int type NRUNUSED, int tlib_php_require_extension(const char* extension TSRMLS_DC) { char* file = NULL; int loaded = 0; -#if ZEND_MODULE_API_NO >= ZEND_7_3_X_API_NO +#if ZEND_MODULE_API_NO >= ZEND_8_0_X_API_NO + void (*prev_error_cb)(int, const char*, const uint32_t, zend_string*); +#elif ZEND_MODULE_API_NO >= ZEND_7_3_X_API_NO void (*prev_error_cb)(int, const char*, const uint32_t, const char*, va_list); #else zend_error_handling_t prev_error;