Skip to content
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
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
11.8.0
11.9.0
1 change: 1 addition & 0 deletions agent/Makefile.frag
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ TEST_BINARIES = \
tests/test_txn_private \
tests/test_user_instrument \
tests/test_user_instrument_hashmap \
tests/test_user_instrument_wraprec_hashmap \
tests/test_zval

.PHONY: unit-tests
Expand Down
1 change: 1 addition & 0 deletions agent/config.m4
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,7 @@ if test "$PHP_NEWRELIC" = "yes"; then
php_pdo_mysql.c php_pdo_pgsql.c php_pgsql.c php_psr7.c php_redis.c \
php_rinit.c php_rshutdown.c php_samplers.c php_stack.c \
php_stacked_segment.c php_txn.c php_user_instrument.c \
php_user_instrument_wraprec_hashmap.c \
php_user_instrument_hashmap.c php_vm.c php_wrapper.c"
FRAMEWORKS="fw_cakephp.c fw_codeigniter.c fw_drupal8.c \
fw_drupal.c fw_drupal_common.c fw_joomla.c fw_kohana.c \
Expand Down
99 changes: 97 additions & 2 deletions agent/fw_drupal8.c
Original file line number Diff line number Diff line change
Expand Up @@ -140,14 +140,17 @@ static void nr_drupal8_add_method_callback_before_after_clean(
nrspecialfn_t after_callback,
nrspecialfn_t clean_callback) {
zend_function* function = NULL;
char* methodLC = NULL;

if (NULL == ce) {
nrl_verbosedebug(NRL_FRAMEWORK, "Drupal 8: got NULL class entry in %s",
__func__);
return;
}

function = nr_php_find_class_method(ce, method);
methodLC = nr_string_to_lowercase(method);
function = nr_php_find_class_method(ce, methodLC);
nr_free(methodLC);
if (NULL == function) {
nrl_verbosedebug(NRL_FRAMEWORK,
"Drupal 8+: cannot get zend_function entry for %.*s::%.*s",
Expand Down Expand Up @@ -605,6 +608,95 @@ NR_PHP_WRAPPER(nr_drupal94_invoke_all_with_clean) {
NR_PHP_WRAPPER_END
#endif // OAPI

static bool nr_is_invalid_key_val_arr(nr_php_string_hash_key_t* key,
zval* val) {
if (NULL == key || 0 == ZEND_STRING_LEN(key)
|| 0 == nr_php_is_zval_valid_array(val)
|| 0 == zend_hash_num_elements(Z_ARRVAL_P(val))) {
return true;
} else {
return false;
}
}

/*
* Purpose: Instrument Drupal Attribute Hooks for Drupal 11.1+
*
* Params: 1. A zval pointer to the moduleHandler instance in use by Drupal.
*
* Return: bool
*
*/
static bool nr_drupal_hook_attribute_instrument(zval* module_handler) {
zval* hook_implementation_map = NULL;

nr_php_string_hash_key_t* hook_key = NULL;
zval* hook_val = NULL;
nr_php_string_hash_key_t* class_key = NULL;
zval* class_val = NULL;
nr_php_string_hash_key_t* method_key = NULL;
zval* module_val = NULL;

char* hookpath = NULL;

hook_implementation_map = nr_php_get_zval_object_property(
module_handler, "hookImplementationsMap");

if (!nr_php_is_zval_valid_array(hook_implementation_map)) {
nrl_verbosedebug(NRL_FRAMEWORK,
"hookImplementationsMap property not a valid array");
return false;
}

ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(hook_implementation_map), hook_key,
hook_val) {
if (nr_is_invalid_key_val_arr(hook_key, hook_val)) {
nrl_warning(NRL_FRAMEWORK,
"hookImplementationsMap[hook]: invalid key or value");
return false;
}

ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(hook_val), class_key, class_val) {
if (nr_is_invalid_key_val_arr(class_key, class_val)) {
nrl_warning(NRL_FRAMEWORK,
"hookImplementationsMap[class]: invalid key or value");
return false;
}

ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(class_val), method_key,
module_val) {
if (NULL == method_key
|| 0 == nr_php_is_zval_valid_string(module_val)) {
nrl_warning(NRL_FRAMEWORK,
"hookImplementationsMap[method]: invalid key or value");
return false;
}

if (nr_striendswith(
ZEND_STRING_VALUE(class_key), ZEND_STRING_LEN(class_key),
NR_PSTR("Drupal\\Core\\Extension\\ProceduralCall"))) {
hookpath = nr_formatf("%s", ZEND_STRING_VALUE(method_key));
} else {
hookpath = nr_formatf("%s::%s", ZEND_STRING_VALUE(class_key),
ZEND_STRING_VALUE(method_key));
}

nr_php_wrap_user_function_drupal(
hookpath, nr_strlen(hookpath), Z_STRVAL_P(module_val),
Z_STRLEN_P(module_val), ZEND_STRING_VALUE(hook_key),
ZEND_STRING_LEN(hook_key));

nr_free(hookpath);
}
ZEND_HASH_FOREACH_END();
}
ZEND_HASH_FOREACH_END();
}
ZEND_HASH_FOREACH_END();

return true;
}

/*
* Purpose : Wrap the invoke() method of the module handler instance in use.
*/
Expand Down Expand Up @@ -632,6 +724,9 @@ NR_PHP_WRAPPER(nr_drupal8_module_handler) {

ce = Z_OBJCE_P(*retval_ptr);

if (nr_drupal_hook_attribute_instrument(*retval_ptr)) {
NR_PHP_WRAPPER_LEAVE;
}
nr_drupal8_add_method_callback(ce, NR_PSTR("getimplementations"),
nr_drupal8_post_get_implementations TSRMLS_CC);
nr_drupal8_add_method_callback(ce, NR_PSTR("implementshook"),
Expand All @@ -640,7 +735,7 @@ NR_PHP_WRAPPER(nr_drupal8_module_handler) {
#if ZEND_MODULE_API_NO >= ZEND_8_0_X_API_NO \
&& !defined OVERWRITE_ZEND_EXECUTE_DATA
nr_drupal8_add_method_callback_before_after_clean(
ce, NR_PSTR("invokeallwith"), nr_drupal94_invoke_all_with,
ce, NR_PSTR("invokeAllWith"), nr_drupal94_invoke_all_with,
nr_drupal94_invoke_all_with_after, nr_drupal94_invoke_all_with_clean);
#else
nr_drupal8_add_method_callback(ce, NR_PSTR("invokeallwith"),
Expand Down
2 changes: 1 addition & 1 deletion agent/fw_laminas3.c
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ void nr_laminas3_enable(TSRMLS_D) {
*/

nr_php_wrap_user_function(
NR_PSTR("Laminas\\Router\\HTTP\\RouteMatch::setMatchedRouteName"),
NR_PSTR("Laminas\\Router\\Http\\RouteMatch::setMatchedRouteName"),
nr_laminas3_name_the_wt TSRMLS_CC);
nr_php_wrap_user_function(
NR_PSTR("Laminas\\Router\\RouteMatch::setMatchedRouteName"),
Expand Down
4 changes: 2 additions & 2 deletions agent/fw_laravel.c
Original file line number Diff line number Diff line change
Expand Up @@ -1232,10 +1232,10 @@ void nr_laravel_enable(TSRMLS_D) {
#if ZEND_MODULE_API_NO >= ZEND_8_0_X_API_NO \
&& !defined OVERWRITE_ZEND_EXECUTE_DATA
nr_php_wrap_user_function_before_after_clean(
NR_PSTR("Illuminate\\Console\\Application::doRun"),
NR_PSTR("Symfony\\Component\\Console\\Application::doRun"),
nr_laravel_console_application_dorun, NULL, NULL);
#else
nr_php_wrap_user_function(NR_PSTR("Illuminate\\Console\\Application::doRun"),
nr_php_wrap_user_function(NR_PSTR("Symfony\\Component\\Console\\Application::doRun"),
nr_laravel_console_application_dorun TSRMLS_CC);
#endif
/*
Expand Down
24 changes: 0 additions & 24 deletions agent/lib_php_amqplib.c
Original file line number Diff line number Diff line change
Expand Up @@ -81,29 +81,6 @@
* needed to work with MQ_BROKER.
*/

/*
* Purpose : Ensures the php-amqplib instrumentation gets wrapped.
*
* Params : None
*
* Returns : None
*/
static void nr_php_amqplib_ensure_class() {
int result = FAILURE;
zend_class_entry* class_entry = NULL;

class_entry = nr_php_find_class("phpamqplib\\channel\\amqpchannel");
if (NULL == class_entry) {
result = zend_eval_stringl(
NR_PSTR("class_exists('PhpAmqpLib\\Channel\\AMQPChannel');"), NULL,
"nr_php_amqplib_class_exists_channel_amqpchannel");
}
/*
* We don't need to check anything else at this point. If this fails, there's
* nothing else we can do anyway.
*/
}

/*
* Version information will be pulled from PhpAmqpLib\\Package::VERSION
* nr_php_amqplib_handle_version will automatically load the class if it isn't
Expand Down Expand Up @@ -810,7 +787,6 @@ void nr_php_amqplib_enable() {

/* Extract the version */
nr_php_amqplib_handle_version();
nr_php_amqplib_ensure_class();

#if ZEND_MODULE_API_NO >= ZEND_8_0_X_API_NO /* less than PHP8.0 */
nr_php_wrap_user_function_before_after_clean(
Expand Down
47 changes: 17 additions & 30 deletions agent/php_execute.c
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,6 @@

static void nr_php_show_exec_return(NR_EXECUTE_PROTO TSRMLS_DC);
static int nr_php_show_exec_indentation(TSRMLS_D);
static void nr_php_show_exec(NR_EXECUTE_PROTO TSRMLS_DC);

/*
* Purpose: Enable monitoring on specific functions in the framework.
Expand Down Expand Up @@ -594,11 +593,11 @@ static int nr_php_show_exec_indentation(TSRMLS_D) {
* Note that this function doesn't handle internal functions, and will crash if
* you give it one.
*/
static void nr_php_show_exec(NR_EXECUTE_PROTO TSRMLS_DC) {
void nr_php_show_exec(const char* context, NR_EXECUTE_PROTO TSRMLS_DC) {
char argstr[NR_EXECUTE_DEBUG_STRBUFSZ];
const char* filename = nr_php_op_array_file_name(NR_OP_ARRAY);
const char* function_name = nr_php_op_array_function_name(NR_OP_ARRAY);

const char* ctx = context ? context : "execute";
argstr[0] = '\0';

if (NR_OP_ARRAY->scope) {
Expand All @@ -608,12 +607,13 @@ static void nr_php_show_exec(NR_EXECUTE_PROTO TSRMLS_DC) {
nr_show_execute_params(NR_EXECUTE_ORIG_ARGS, argstr TSRMLS_CC);
nrl_verbosedebug(
NRL_AGENT,
"execute: %.*s scope={%.*s} function={" NRP_FMT_UQ
NRP_FMT_UQ ": %.*s scope={%.*s} function={" NRP_FMT_UQ
"}"
" params={" NRP_FMT_UQ
"}"
" %.5s"
"@ " NRP_FMT_UQ ":%d",
NRP_SHOW_EXEC_CONTEXT(ctx),
nr_php_show_exec_indentation(TSRMLS_C), nr_php_indentation_spaces,
NRSAFELEN(nr_php_class_entry_name_length(NR_OP_ARRAY->scope)),
nr_php_class_entry_name(NR_OP_ARRAY->scope),
Expand All @@ -631,12 +631,13 @@ static void nr_php_show_exec(NR_EXECUTE_PROTO TSRMLS_DC) {
nr_show_execute_params(NR_EXECUTE_ORIG_ARGS, argstr TSRMLS_CC);
nrl_verbosedebug(
NRL_AGENT,
"execute: %.*s function={" NRP_FMT_UQ
NRP_FMT_UQ ": %.*s function={" NRP_FMT_UQ
"}"
" params={" NRP_FMT_UQ
"}"
" %.5s"
"@ " NRP_FMT_UQ ":%d",
NRP_SHOW_EXEC_CONTEXT(ctx),
nr_php_show_exec_indentation(TSRMLS_C), nr_php_indentation_spaces,
NRP_PHP(function_name), NRP_ARGSTR(argstr),
#if ZEND_MODULE_API_NO < ZEND_7_4_X_API_NO
Expand All @@ -649,16 +650,17 @@ static void nr_php_show_exec(NR_EXECUTE_PROTO TSRMLS_DC) {
/*
* file
*/
nrl_verbosedebug(NRL_AGENT, "execute: %.*s file={" NRP_FMT "}",
nrl_verbosedebug(NRL_AGENT, NRP_FMT_UQ ": %.*s file={" NRP_FMT "}",
NRP_SHOW_EXEC_CONTEXT(ctx),
nr_php_show_exec_indentation(TSRMLS_C),
nr_php_indentation_spaces, NRP_FILENAME(filename));
} else {
/*
* unknown
*/
nrl_verbosedebug(NRL_AGENT, "execute: %.*s ?",
nr_php_show_exec_indentation(TSRMLS_C),
nr_php_indentation_spaces);
nrl_verbosedebug(NRL_AGENT, NRP_FMT_UQ ": %.*s ?",
NRP_SHOW_EXEC_CONTEXT(ctx),
nr_php_show_exec_indentation(TSRMLS_C), nr_php_indentation_spaces);
}
}

Expand Down Expand Up @@ -982,7 +984,7 @@ static void nr_php_user_instrumentation_from_file(const char* filename,
*/
#define METRIC_NAME_MAX_LEN 512

static void nr_php_execute_file(const zend_op_array* op_array,
void nr_php_execute_file(const zend_op_array* op_array,
NR_EXECUTE_PROTO TSRMLS_DC) {
const char* filename = nr_php_op_array_file_name(op_array);
size_t filename_len = nr_php_op_array_file_name_len(op_array);
Expand All @@ -1007,7 +1009,9 @@ static void nr_php_execute_file(const zend_op_array* op_array,
return;
}

#if ZEND_MODULE_API_NO < ZEND_8_0_X_API_NO
nr_php_add_user_instrumentation(TSRMLS_C);
#endif
}

/*
Expand Down Expand Up @@ -1519,7 +1523,7 @@ static void nr_php_execute_enabled(NR_EXECUTE_PROTO TSRMLS_DC) {

static void nr_php_execute_show(NR_EXECUTE_PROTO TSRMLS_DC) {
if (nrunlikely(NR_PHP_PROCESS_GLOBALS(special_flags).show_executes)) {
nr_php_show_exec(NR_EXECUTE_ORIG_ARGS TSRMLS_CC);
nr_php_show_exec("execute", NR_EXECUTE_ORIG_ARGS TSRMLS_CC);
}

nr_php_execute_enabled(NR_EXECUTE_ORIG_ARGS TSRMLS_CC);
Expand Down Expand Up @@ -1905,16 +1909,7 @@ static void nr_php_instrument_func_begin(NR_EXECUTE_PROTO) {

NRTXNGLOBAL(execute_count) += 1;
txn_start_time = nr_txn_start_time(NRPRG(txn));
/*
* Handle here, but be aware the classes might not be loaded yet.
*/
if (nrunlikely(OP_ARRAY_IS_A_FILE(NR_OP_ARRAY))) {
const char* filename = nr_php_op_array_file_name(NR_OP_ARRAY);
size_t filename_len = nr_php_op_array_file_name_len(NR_OP_ARRAY);
nr_execute_handle_framework(all_frameworks, num_all_frameworks,
filename, filename_len TSRMLS_CC);
return;
}

if (NULL != NRPRG(cufa_callback) && NRPRG(check_cufa)) {
/*
* For PHP 7+, call_user_func_array() is flattened into an inline by
Expand Down Expand Up @@ -2000,14 +1995,6 @@ static void nr_php_instrument_func_end(NR_EXECUTE_PROTO) {
}
txn_start_time = nr_txn_start_time(NRPRG(txn));

/*
* Let's get the framework info.
*/
if (nrunlikely(OP_ARRAY_IS_A_FILE(NR_OP_ARRAY))) {
nr_php_execute_file(NR_OP_ARRAY, NR_EXECUTE_ORIG_ARGS TSRMLS_CC);
return;
}

/*
* Get the current segment and return if null.
*/
Expand Down Expand Up @@ -2157,7 +2144,7 @@ void nr_php_observer_fcall_begin(zend_execute_data* execute_data) {
int show_executes = NR_PHP_PROCESS_GLOBALS(special_flags).show_executes;

if (nrunlikely(show_executes)) {
nr_php_show_exec(NR_EXECUTE_ORIG_ARGS);
nr_php_show_exec("execute", NR_EXECUTE_ORIG_ARGS);
}
nr_php_instrument_func_begin(NR_EXECUTE_ORIG_ARGS);

Expand Down
15 changes: 15 additions & 0 deletions agent/php_execute.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,21 @@
#define OP_ARRAY_IS_METHOD(OP, FNAME) \
(0 == nr_strcmp(nr_php_op_array_function_name(OP), (FNAME)))

extern void nr_php_execute_file(const zend_op_array* op_array,
NR_EXECUTE_PROTO TSRMLS_DC);

/*
* Purpose: Log information about the execute data in a given execution
* context - either 'execute' (zend_execute) or 'observe' (fcall_init).
* Only first 8 characters of the context are printed.
*
* Caveat: This function doesn't handle internal functions, and will crash if
* you give it one.
*/
extern void nr_php_show_exec(const char*, NR_EXECUTE_PROTO TSRMLS_DC);
/* Limit length of execution context printed in the log file to 8 characters */
#define NRP_SHOW_EXEC_CONTEXT(C) 8, NRSAFESTR(C)

/*
* Purpose: Look through the PHP symbol table for special names or symbols
* that provide additional hints that a specific framework has been loaded.
Expand Down
6 changes: 3 additions & 3 deletions agent/php_globals.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,11 @@ typedef struct _nrphpglobals_t {
* variable with the key `NEW_RELIC_LABELS` */
#if ZEND_MODULE_API_NO >= ZEND_8_1_X_API_NO /* PHP 8.1+ */
zend_long zend_offset; /* Zend extension offset */
zend_long
zend_op_array_offset; /* Zend extension op_array to modify reserved */
#else
int zend_offset; /* Zend extension offset */
int zend_op_array_offset; /* Zend extension op_array to modify reserved */
#endif
#if ZEND_MODULE_API_NO >= ZEND_8_0_X_API_NO /* PHP 8.0+ */
int op_array_extension_handle; /* Zend op_array extension handle to attach agent's data to function */
#endif
int done_instrumentation; /* Set to true if we have installed instrumentation
handlers */
Expand Down
Loading
Loading