Skip to content

Commit 22f158d

Browse files
committed
first round of fixes after initial testing
1 parent 97b3c90 commit 22f158d

14 files changed

+150
-52
lines changed

agent/fw_drupal8.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,22 +140,26 @@ static void nr_drupal8_add_method_callback_before_after_clean(
140140
nrspecialfn_t after_callback,
141141
nrspecialfn_t clean_callback) {
142142
zend_function* function = NULL;
143+
char* methodLC = NULL;
143144

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

150-
function = nr_php_find_class_method(ce, method);
151+
methodLC = nr_string_to_lowercase(method);
152+
function = nr_php_find_class_method(ce, methodLC);
151153
if (NULL == function) {
152154
nrl_verbosedebug(NRL_FRAMEWORK,
153155
"Drupal 8+: cannot get zend_function entry for %.*s::%.*s",
154156
NRSAFELEN(nr_php_class_entry_name_length(ce)),
155157
nr_php_class_entry_name(ce), NRSAFELEN(method_len),
156158
method);
159+
nr_free(methodLC);
157160
return;
158161
}
162+
nr_free(methodLC);
159163

160164
if (NULL == nr_php_get_wraprec(function)) {
161165
char* class_method = nr_formatf(
@@ -167,6 +171,8 @@ static void nr_drupal8_add_method_callback_before_after_clean(
167171
clean_callback);
168172

169173
nr_free(class_method);
174+
} else {
175+
nrl_always("%s::%s already has wraprec", nr_php_class_entry_name(ce), method);
170176
}
171177
}
172178
#endif // OAPI
@@ -640,7 +646,7 @@ NR_PHP_WRAPPER(nr_drupal8_module_handler) {
640646
#if ZEND_MODULE_API_NO >= ZEND_8_0_X_API_NO \
641647
&& !defined OVERWRITE_ZEND_EXECUTE_DATA
642648
nr_drupal8_add_method_callback_before_after_clean(
643-
ce, NR_PSTR("invokeallwith"), nr_drupal94_invoke_all_with,
649+
ce, NR_PSTR("invokeAllWith"), nr_drupal94_invoke_all_with,
644650
nr_drupal94_invoke_all_with_after, nr_drupal94_invoke_all_with_clean);
645651
#else
646652
nr_drupal8_add_method_callback(ce, NR_PSTR("invokeallwith"),

agent/php_execute.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -611,11 +611,11 @@ void nr_php_show_exec(const char* context, NR_EXECUTE_PROTO TSRMLS_DC) {
611611
const char* function_name = nr_php_op_array_function_name(NR_OP_ARRAY);
612612
const char* ctx = context ? context : "execute";
613613
#if ZEND_MODULE_API_NO >= ZEND_7_4_X_API_NO
614-
#if ZEND_MODULE_API_NO >= ZEND_8_0_X_API_NO
615-
nruserfn_t* wr = nr_php_get_wraprec_from_op_array_extension(__func__, execute_data->func);
616-
#else
614+
// #if ZEND_MODULE_API_NO >= ZEND_8_0_X_API_NO
615+
// nruserfn_t* wr = nr_php_get_wraprec_from_op_array_extension(__func__, execute_data->func);
616+
// #else
617617
nruserfn_t* wr = nr_php_get_wraprec(execute_data->func);
618-
#endif
618+
// #endif
619619
#endif
620620
argstr[0] = '\0';
621621

@@ -1949,7 +1949,7 @@ static void nr_php_instrument_func_begin(NR_EXECUTE_PROTO) {
19491949
*/
19501950
nr_php_observer_attempt_call_cufa_handler(NR_EXECUTE_ORIG_ARGS);
19511951
}
1952-
wraprec = nr_php_get_wraprec_from_op_array_extension(__func__, execute_data->func);
1952+
wraprec = nr_php_get_wraprec(execute_data->func);
19531953

19541954
segment = nr_segment_start(NRPRG(txn), NULL, NULL);
19551955

agent/php_minit.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -669,6 +669,9 @@ PHP_MINIT_FUNCTION(newrelic) {
669669
NR_ZEND_EXECUTE_HOOK = nr_php_execute;
670670
#else
671671
nr_php_observer_minit();
672+
if (NR_SUCCESS != nr_php_user_instrument_wraprec_hashmap_init()) {
673+
nrl_error(NRL_AGENT, "Failed to initialize user function instrumentation");
674+
}
672675
#endif
673676

674677
if (NR_PHP_PROCESS_GLOBALS(instrument_internal)) {

agent/php_observer.c

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "php_observer.h"
2424
#include "php_samplers.h"
2525
#include "php_user_instrument.h"
26+
#include "php_user_instrument_wraprec_hashmap.h"
2627
#include "php_vm.h"
2728
#include "php_wrapper.h"
2829
#include "fw_laravel.h"
@@ -75,6 +76,7 @@
7576
static zend_observer_fcall_handlers nr_php_fcall_register_handlers(
7677
zend_execute_data* execute_data) {
7778
zend_observer_fcall_handlers handlers = {NULL, NULL};
79+
zend_string *func_name = NULL, *scope_name = NULL;
7880
nruserfn_t* wr;
7981
if (NULL == execute_data) {
8082
return handlers;
@@ -88,9 +90,34 @@ static zend_observer_fcall_handlers nr_php_fcall_register_handlers(
8890
nr_php_show_exec("observe", execute_data, NULL);
8991
}
9092

91-
wr = nr_php_get_wraprec(execute_data->func);
92-
// store the wraprec in the op_array extension for the duration of the request for later lookup
93-
ZEND_OP_ARRAY_EXTENSION(&execute_data->func->op_array, NR_PHP_PROCESS_GLOBALS(op_array_extension_handle)) = wr;
93+
if (OP_ARRAY_IS_A_METHOD(&execute_data->func->op_array)) {
94+
scope_name = execute_data->func->op_array.scope->name;
95+
func_name = execute_data->func->op_array.function_name;
96+
#if 1
97+
zend_long cn_hash = zend_hash_func(ZSTR_VAL(scope_name), ZSTR_LEN(scope_name));
98+
zend_long fn_hash = zend_hash_func(ZSTR_VAL(func_name), ZSTR_LEN(func_name));
99+
nrl_always("class_name=%s, class_name->h=%zu, cn_hash=%zu, function_name=%s, function_name->h=%zu, fn_hash=%zu",
100+
ZSTR_VAL(scope_name), scope_name->h, cn_hash,
101+
ZSTR_VAL(func_name), func_name->h, fn_hash);
102+
#endif
103+
} else if (OP_ARRAY_IS_A_FUNCTION(&execute_data->func->op_array)){
104+
func_name = execute_data->func->op_array.function_name;
105+
#if 1
106+
zend_long fn_hash = zend_hash_func(ZSTR_VAL(func_name), ZSTR_LEN(func_name));
107+
nrl_always("function_name=%s, function_name->h=%zu, fn_hash=%zu", ZSTR_VAL(func_name), func_name->h, fn_hash);
108+
#endif
109+
}
110+
111+
if (!ZEND_OP_ARRAY_EXTENSION(&execute_data->func->op_array, NR_PHP_PROCESS_GLOBALS(op_array_extension_handle))) {
112+
nrl_always("wraprec not installed yet");
113+
wr = nr_php_user_instrument_wraprec_hashmap_get(func_name, scope_name);
114+
nrl_always("found wraprec=%p", wr);
115+
116+
// store the wraprec in the op_array extension for the duration of the request for later lookup
117+
ZEND_OP_ARRAY_EXTENSION(&execute_data->func->op_array, NR_PHP_PROCESS_GLOBALS(op_array_extension_handle)) = wr;
118+
} else {
119+
nrl_always("wraprec already installed");
120+
}
94121

95122
handlers.begin = nr_php_observer_fcall_begin;
96123
handlers.end = nr_php_observer_fcall_end;

agent/php_rinit.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,9 @@ PHP_RINIT_FUNCTION(newrelic) {
5454
NRPRG(sapi_headers) = NULL;
5555
NRPRG(error_group_user_callback).is_set = false;
5656
#if ZEND_MODULE_API_NO >= ZEND_7_4_X_API_NO
57+
#if ZEND_MODULE_API_NO == ZEND_7_4_X_API_NO
5758
nr_php_init_user_instrumentation();
59+
#endif
5860
#if ZEND_MODULE_API_NO >= ZEND_8_0_X_API_NO \
5961
&& !defined OVERWRITE_ZEND_EXECUTE_DATA
6062
NRPRG(drupal_http_request_segment) = NULL;

agent/php_user_instrument.c

Lines changed: 80 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include "php_globals.h"
88
#include "php_user_instrument.h"
99
#include "php_user_instrument_hashmap.h"
10+
#include "php_user_instrument_wraprec_hashmap.h"
1011
#include "php_wrapper.h"
1112
#include "lib_guzzle_common.h"
1213
#include "util_logging.h"
@@ -114,7 +115,32 @@ int nr_zend_call_orig_execute_special(nruserfn_t* wraprec,
114115
return zcaught;
115116
}
116117

117-
#if ZEND_MODULE_API_NO >= ZEND_7_4_X_API_NO
118+
#if ZEND_MODULE_API_NO >= ZEND_8_0_X_API_NO
119+
static inline void nr_php_wraprec_lookup_set(nruserfn_t* wr,
120+
zend_function* zf) {
121+
// for situation when wraprec is added after first execution of the function
122+
// store the wraprec in the op_array extension for the duration of the request for later lookup
123+
// The op_array extension slot for function may not be initialized yet because it is
124+
// initialized only on the first call made to the function in that request. This would
125+
// mean that run_time_cache is NULL and wraprec cannot be stored yet! It will be stored
126+
// on the first call to the function when observer is registered for that function.
127+
if (NULL != RUN_TIME_CACHE(&zf->op_array)) {
128+
ZEND_OP_ARRAY_EXTENSION(&zf->op_array, NR_PHP_PROCESS_GLOBALS(op_array_extension_handle)) = wr;
129+
}
130+
}
131+
132+
static inline nruserfn_t* nr_php_wraprec_lookup_get(zend_function* zf) {
133+
nruserfn_t *wraprec = NULL;
134+
135+
if (NULL != RUN_TIME_CACHE(&zf->op_array)) {
136+
wraprec = ZEND_OP_ARRAY_EXTENSION(&zf->op_array, NR_PHP_PROCESS_GLOBALS(op_array_extension_handle));
137+
}
138+
if (NULL != wraprec && NRPRG(pid) != wraprec->pid) {
139+
wraprec = NULL;
140+
}
141+
return wraprec;
142+
}
143+
#elif ZEND_MODULE_API_NO == ZEND_7_4_X_API_NO
118144
/* Hashmap with pointers to wraprecs. Some, that are re-usable between requests,
119145
* are stored in linked list. These wraprecs are created once per interesting
120146
* function detection, and destroyed at module shutdown. Some, that are
@@ -130,17 +156,6 @@ static nr_php_wraprec_hashmap_t* user_function_wrappers;
130156
static inline void nr_php_wraprec_lookup_set(nruserfn_t* wr,
131157
zend_function* zf) {
132158
nr_php_wraprec_hashmap_update(user_function_wrappers, zf, wr);
133-
#if ZEND_MODULE_API_NO >= ZEND_8_0_X_API_NO /* PHP 8.0+ */
134-
// for situation when wraprec is added after first execution of the function
135-
// store the wraprec in the op_array extension for the duration of the request for later lookup
136-
// The op_array extension slot for function may not be initialized yet because it is
137-
// initialized only on the first call made to the function in that request. This would
138-
// mean that run_time_cache is NULL and wraprec cannot be stored yet! It will be stored
139-
// on the first call to the function when observer is registered for that function.
140-
if (NULL != RUN_TIME_CACHE(&zf->op_array)) {
141-
ZEND_OP_ARRAY_EXTENSION(&zf->op_array, NR_PHP_PROCESS_GLOBALS(op_array_extension_handle)) = wr;
142-
}
143-
#endif
144159
}
145160
static inline nruserfn_t* nr_php_wraprec_lookup_get(zend_function* zf) {
146161
nruserfn_t* wraprec = NULL;
@@ -306,6 +321,7 @@ nruserfn_t* nr_php_user_wraprec_create(void) {
306321
return wr;
307322
}
308323

324+
#if ZEND_MODULE_API_NO < ZEND_8_0_X_API_NO
309325
static nruserfn_t* nr_php_user_wraprec_create_named(const char* full_name,
310326
int full_name_len) {
311327
int i;
@@ -355,6 +371,7 @@ static nruserfn_t* nr_php_user_wraprec_create_named(const char* full_name,
355371

356372
return wraprec;
357373
}
374+
#endif
358375

359376
void nr_php_user_wraprec_destroy(nruserfn_t** wraprec_ptr) {
360377
nruserfn_t* wraprec;
@@ -377,6 +394,7 @@ void nr_php_user_wraprec_destroy(nruserfn_t** wraprec_ptr) {
377394
nr_realfree((void**)wraprec_ptr);
378395
}
379396

397+
#if ZEND_MODULE_API_NO < ZEND_8_0_X_API_NO
380398
static int nr_php_user_wraprec_is_match(const nruserfn_t* w1,
381399
const nruserfn_t* w2) {
382400
if ((0 == w1) && (0 == w2)) {
@@ -393,11 +411,42 @@ static int nr_php_user_wraprec_is_match(const nruserfn_t* w1,
393411
}
394412
return 1;
395413
}
414+
#endif
415+
416+
#if ZEND_MODULE_API_NO > ZEND_7_4_X_API_NO
417+
static nruserfn_t* nr_transient_wraprecs = NULL; /* a singly linked list */
418+
#else
419+
static nruserfn_t* nr_wrapped_user_functions = NULL; /* a singly linked list */
420+
#endif
396421

397422
static void nr_php_add_custom_tracer_common(nruserfn_t* wraprec) {
398423
/* Add the wraprecord to the list. */
424+
#if ZEND_MODULE_API_NO > ZEND_7_4_X_API_NO
425+
if (wraprec->is_transient) {
426+
/* Transient (unnamed) wraprecs are not added to wraprec hashmap which only stores named
427+
* wraprecs. Keep track of all transient wraprecs so that they can be destroyed at the
428+
* end of the request. */
429+
wraprec->next = nr_transient_wraprecs;
430+
nr_transient_wraprecs = wraprec;
431+
return;
432+
}
433+
#endif
434+
#if ZEND_MODULE_API_NO == ZEND_7_4_X_API_NO
435+
if (!wraprec->is_transient) {
436+
/* Non-transient wraprecs are added to both the hashmap and linked list.
437+
* At request shutdown, the hashmap will free transients, but leave
438+
* non-transients to be freed when the linked list is disposed of which is at
439+
* module shutdown */
440+
wraprec->next = nr_wrapped_user_functions;
441+
nr_wrapped_user_functions = wraprec;
442+
return;
443+
}
444+
#endif
445+
#if ZEND_MODULE_API_NO < ZEND_7_4_X_API_NO
399446
wraprec->next = nr_wrapped_user_functions;
400447
nr_wrapped_user_functions = wraprec;
448+
return;
449+
#endif
401450
}
402451

403452
#define NR_PHP_UNKNOWN_FUNCTION_NAME "{unknown}"
@@ -440,16 +489,15 @@ nruserfn_t* nr_php_add_custom_tracer_callable(zend_function* func TSRMLS_DC) {
440489
nr_free(name);
441490

442491
nr_php_wrap_zend_function(func, wraprec TSRMLS_CC);
443-
#if ZEND_MODULE_API_NO < ZEND_7_4_X_API_NO
444492
nr_php_add_custom_tracer_common(wraprec);
445-
#endif
446493

447494
return wraprec;
448495
}
449496

450497
nruserfn_t* nr_php_add_custom_tracer_named(const char* namestr,
451498
size_t namestrlen) {
452499
nruserfn_t* wraprec;
500+
#if ZEND_MODULE_API_NO < ZEND_8_0_X_API_NO
453501
nruserfn_t* p;
454502

455503
wraprec = nr_php_user_wraprec_create_named(namestr, namestrlen);
@@ -474,17 +522,15 @@ nruserfn_t* nr_php_add_custom_tracer_named(const char* namestr,
474522
}
475523
p = p->next;
476524
}
477-
525+
#else
526+
wraprec = nr_php_user_instrument_wraprec_hashmap_add(namestr, namestrlen);
527+
#endif
478528
nrl_verbosedebug(
479529
NRL_INSTRUMENT, "adding custom for '" NRP_FMT_UQ "%.5s" NRP_FMT_UQ "'",
480530
NRP_PHP(wraprec->classname),
481531
(0 == wraprec->classname) ? "" : "::", NRP_PHP(wraprec->funcname));
482532

483533
nr_php_wrap_user_function_internal(wraprec TSRMLS_CC);
484-
/* non-transient wraprecs are added to both the hashmap and linked list.
485-
* At request shutdown, the hashmap will free transients, but leave
486-
* non-transients to be freed when the linked list is disposed of which is at
487-
* module shutdown */
488534
nr_php_add_custom_tracer_common(wraprec);
489535

490536
return wraprec; /* return the new wraprec */
@@ -501,7 +547,13 @@ nruserfn_t* nr_php_add_custom_tracer_named(const char* namestr,
501547
*
502548
*/
503549
void nr_php_reset_user_instrumentation(void) {
504-
#if ZEND_MODULE_API_NO >= ZEND_7_4_X_API_NO
550+
#if ZEND_MODULE_API_NO >= ZEND_8_0_X_API_NO
551+
/* No need to do anything at rshutdown:
552+
* - Observer API takes care of resetting user instrumentation for each request
553+
* - All named wraprecs ever created persist in wraprec hashmap until mshutdown
554+
*/
555+
return;
556+
#elif ZEND_MODULE_API_NO >= ZEND_7_4_X_API_NO
505557
// send a metric with the number of transient wrappers
506558
if (NULL != user_function_wrappers) {
507559
nr_php_wraprec_hashmap_stats_t stats
@@ -554,14 +606,16 @@ void nr_php_remove_transient_user_instrumentation(void) {
554606
* Wrap all the interesting user functions with instrumentation.
555607
*/
556608
void nr_php_add_user_instrumentation(TSRMLS_D) {
557-
nruserfn_t* p = nr_wrapped_user_functions;
609+
#if ZEND_MODULE_API_NO < ZEND_8_0_X_API_NO
610+
nruserfn_t* p = nr_named_wraprecs;
558611

559612
while (0 != p) {
560613
if ((0 == p->is_wrapped) && (0 == p->is_disabled)) {
561614
nr_php_wrap_user_function_internal(p TSRMLS_CC);
562615
}
563616
p = p->next;
564617
}
618+
#endif
565619
}
566620

567621
void nr_php_add_transaction_naming_function(const char* namestr,
@@ -608,6 +662,7 @@ void nr_php_remove_exception_function(zend_function* func TSRMLS_DC) {
608662
}
609663

610664
void nr_php_destroy_user_wrap_records(void) {
665+
#if ZEND_MODULE_API_NO < ZEND_8_0_X_API_NO
611666
nruserfn_t* next_user_wraprec;
612667

613668
next_user_wraprec = nr_wrapped_user_functions;
@@ -618,15 +673,12 @@ void nr_php_destroy_user_wrap_records(void) {
618673
nr_php_user_wraprec_destroy(&wraprec);
619674
}
620675

621-
nr_wrapped_user_functions = NULL;
676+
nr_named_wraprecs = NULL;
677+
#else
678+
nr_php_user_instrument_wraprec_hashmap_destroy();
679+
#endif
622680
}
623681

624-
/*
625-
* This is a similar list, but for the dynamically added user-defined functions
626-
* rather than the statically defined internal/binary functions above.
627-
*/
628-
nruserfn_t* nr_wrapped_user_functions = 0;
629-
630682
void nr_php_user_function_add_declared_callback(const char* namestr,
631683
int namestrlen,
632684
nruserfn_declared_t callback

agent/php_user_instrument.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ typedef void (*nruserfn_declared_t)(TSRMLS_D);
3737
typedef struct _nruserfn_t {
3838
struct _nruserfn_t* next; /* singly linked list next pointer */
3939

40-
#if ZEND_MODULE_API_NO >= ZEND_7_4_X_API_NO
40+
#if ZEND_MODULE_API_NO == ZEND_7_4_X_API_NO
4141
/* wraprec hashmap key */
4242
nr_php_wraprec_hashmap_key_t key;
4343
#endif
@@ -111,9 +111,10 @@ typedef struct _nruserfn_t {
111111
int pid; /* pid of a process that created this wraprec */
112112
} nruserfn_t;
113113

114-
extern nruserfn_t* nr_wrapped_user_functions; /* a singly linked list */
115-
116-
#if ZEND_MODULE_API_NO >= ZEND_7_4_X_API_NO
114+
#if ZEND_MODULE_API_NO >= ZEND_8_0_X_API_NO
115+
/* PHPs 8.0+ use ZEND_OP_ARRAY_EXTENSION to store wraprecs and Observer API to install them */
116+
extern nruserfn_t* nr_php_get_wraprec(zend_function* zf);
117+
#elif ZEND_MODULE_API_NO == ZEND_7_4_X_API_NO
117118

118119
/*
119120
* Purpose : Init user instrumentation. This must only be called on request

0 commit comments

Comments
 (0)