Skip to content
This repository was archived by the owner on Oct 3, 2023. It is now read-only.

Commit 446b9f8

Browse files
authored
Add test for memory leaks (#86)
* test against php 7.1 with debug enabled to check for memory leaks * Fix memory leaks in global trace id and parent span id * cleanup trace context constructor * Fixing some memory leaks * Fix segfaults * clean up options hashes * Cleaning up attributes, links, timeEvents returned in trace span object * fix more memory leaks * Fix freeing invalid data * Fix memory leak in opencensus_trace_begin * Fix remaining memory leaks * Fix exceptions for closure errors on 32-bit systems
1 parent 33535f2 commit 446b9f8

9 files changed

Lines changed: 105 additions & 69 deletions

cloudbuild.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,7 @@ steps:
2020
args: ['build', '--build-arg', 'BASE_IMAGE=gcr.io/php-stackdriver/php70-32bit', '.']
2121
waitFor: ['-']
2222
id: php70-32bit
23+
- name: gcr.io/cloud-builders/docker
24+
args: ['build', '--build-arg', 'BASE_IMAGE=gcr.io/php-stackdriver/php71-debug', '.']
25+
waitFor: ['-']
26+
id: php71-debug

ext/opencensus_trace.c

Lines changed: 60 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -313,24 +313,30 @@ static int opencensus_trace_call_user_function_callback(zend_execute_data *execu
313313
int i, num_args = EX_NUM_ARGS(), has_scope = 0;
314314
zval *args = emalloc((num_args + 1) * sizeof(zval));
315315

316-
if (getThis() == NULL) {
317-
ZVAL_NULL(&args[0]);
318-
} else {
316+
if (getThis() != NULL) {
319317
has_scope = 1;
320-
ZVAL_ZVAL(&args[0], getThis(), 0, 1);
318+
ZVAL_COPY(&args[0], getThis());
321319
}
322320

323321
for (i = 0; i < num_args; i++) {
324-
ZVAL_ZVAL(&args[i + has_scope], EX_VAR_NUM(i), 0, 1);
322+
ZVAL_COPY(&args[i + has_scope], EX_VAR_NUM(i));
325323
}
326324

327325
if (call_user_function_ex(EG(function_table), NULL, callback, callback_result, num_args + has_scope, args, 0, NULL) != SUCCESS) {
326+
for (i = 0; i < num_args + has_scope; i++) {
327+
ZVAL_DESTRUCTOR(&args[i]);
328+
}
328329
efree(args);
329330
return FAILURE;
330331
}
332+
for (i = 0; i < num_args + has_scope; i++) {
333+
ZVAL_DESTRUCTOR(&args[i]);
334+
}
331335
efree(args);
332336

333337
if (EG(exception) != NULL) {
338+
php_error_docref(NULL, E_WARNING, "Exception in trace callback");
339+
zend_clear_exception();
334340
return FAILURE;
335341
}
336342

@@ -353,16 +359,18 @@ static int opencensus_trace_call_user_function_callback(zend_execute_data *execu
353359
*/
354360
static void opencensus_trace_execute_callback(opencensus_trace_span_t *span, zend_execute_data *execute_data, zval *span_options TSRMLS_DC)
355361
{
356-
zend_string *callback_name;
362+
zend_string *callback_name = NULL;
357363
if (zend_is_callable(span_options, 0, &callback_name)) {
358364
zval callback_result;
359365
if (opencensus_trace_call_user_function_callback(execute_data, span, span_options, &callback_result TSRMLS_CC) == SUCCESS) {
360366
opencensus_trace_span_apply_span_options(span, &callback_result);
361367
}
368+
ZVAL_DESTRUCTOR(&callback_result);
362369
zend_string_release(callback_name);
363370
} else if (Z_TYPE_P(span_options) == IS_ARRAY) {
364371
opencensus_trace_span_apply_span_options(span, span_options);
365372
}
373+
zend_string_release(callback_name);
366374
}
367375

368376
/**
@@ -388,14 +396,14 @@ static zend_string *generate_span_id()
388396
* Start a new trace span. Inherit the parent span id from the current trace
389397
* context
390398
*/
391-
static opencensus_trace_span_t *opencensus_trace_begin(zend_string *function_name, zend_execute_data *execute_data, zend_string *span_id TSRMLS_DC)
399+
static opencensus_trace_span_t *opencensus_trace_begin(zend_string *name, zend_execute_data *execute_data, zend_string *span_id TSRMLS_DC)
392400
{
393401
opencensus_trace_span_t *span = opencensus_trace_span_alloc();
394402

395403
zend_fetch_debug_backtrace(&span->stackTrace, 1, DEBUG_BACKTRACE_IGNORE_ARGS, 0);
396404

397405
span->start = opencensus_now();
398-
span->name = zend_string_copy(function_name);
406+
span->name = zend_string_copy(name);
399407
if (span_id) {
400408
span->span_id = zend_string_copy(span_id);
401409
} else {
@@ -407,12 +415,9 @@ static opencensus_trace_span_t *opencensus_trace_begin(zend_string *function_nam
407415
}
408416

409417
OPENCENSUS_TRACE_G(current_span) = span;
410-
zval ptr;
411-
ZVAL_PTR(&ptr, span);
412418

413419
/* add the span to the list of spans */
414-
// printf("inserting span with span id: %s\n", ZSTR_VAL(span->span_id));
415-
zend_hash_add(OPENCENSUS_TRACE_G(spans), span->span_id, &ptr);
420+
zend_hash_add_ptr(OPENCENSUS_TRACE_G(spans), span->span_id, span);
416421

417422
return span;
418423
}
@@ -488,12 +493,15 @@ PHP_FUNCTION(opencensus_trace_begin)
488493

489494
if (span_options == NULL) {
490495
array_init(&default_span_options);
491-
span_options = &default_span_options;
496+
span = opencensus_trace_begin(function_name, execute_data, NULL TSRMLS_CC);
497+
opencensus_trace_execute_callback(span, execute_data, &default_span_options TSRMLS_CC);
498+
ZVAL_DESTRUCTOR(&default_span_options);
499+
} else {
500+
span_id = span_id_from_options(Z_ARR_P(span_options));
501+
span = opencensus_trace_begin(function_name, execute_data, span_id TSRMLS_CC);
502+
opencensus_trace_execute_callback(span, execute_data, span_options TSRMLS_CC);
492503
}
493504

494-
span_id = span_id_from_options(Z_ARR_P(span_options));
495-
span = opencensus_trace_begin(function_name, execute_data, span_id TSRMLS_CC);
496-
opencensus_trace_execute_callback(span, execute_data, span_options TSRMLS_CC);
497505
RETURN_TRUE;
498506
}
499507

@@ -510,31 +518,39 @@ PHP_FUNCTION(opencensus_trace_finish)
510518
RETURN_FALSE;
511519
}
512520

521+
static void span_dtor(zval *zv)
522+
{
523+
opencensus_trace_span_t *span = Z_PTR_P(zv);
524+
opencensus_trace_span_free(span);
525+
ZVAL_PTR_DTOR(zv);
526+
}
527+
513528
/**
514529
* Reset the list of spans and free any allocated memory used.
515530
* If reset is set, reallocate request globals so we can start capturing spans.
516531
*/
517532
static void opencensus_trace_clear(int reset TSRMLS_DC)
518533
{
519-
opencensus_trace_span_t *span;
520-
521-
/* free memory for all captured spans */
522-
ZEND_HASH_FOREACH_PTR(OPENCENSUS_TRACE_G(spans), span) {
523-
opencensus_trace_span_free(span);
524-
} ZEND_HASH_FOREACH_END();
525-
526534
/* free the hashtable */
535+
zend_hash_destroy(OPENCENSUS_TRACE_G(spans));
527536
FREE_HASHTABLE(OPENCENSUS_TRACE_G(spans));
528537

529538
/* reallocate and setup the hashtable for captured spans */
530539
if (reset) {
531540
ALLOC_HASHTABLE(OPENCENSUS_TRACE_G(spans));
532-
zend_hash_init(OPENCENSUS_TRACE_G(spans), 16, NULL, ZVAL_PTR_DTOR, 0);
541+
zend_hash_init(OPENCENSUS_TRACE_G(spans), 16, NULL, span_dtor, 0);
533542
}
534543

535544
OPENCENSUS_TRACE_G(current_span) = NULL;
536-
OPENCENSUS_TRACE_G(trace_id) = NULL;
537-
OPENCENSUS_TRACE_G(trace_parent_span_id) = 0;
545+
if (OPENCENSUS_TRACE_G(trace_id)) {
546+
zend_string_release(OPENCENSUS_TRACE_G(trace_id));
547+
OPENCENSUS_TRACE_G(trace_id) = NULL;
548+
}
549+
550+
if (OPENCENSUS_TRACE_G(trace_parent_span_id)) {
551+
zend_string_release(OPENCENSUS_TRACE_G(trace_parent_span_id));
552+
OPENCENSUS_TRACE_G(trace_parent_span_id) = NULL;
553+
}
538554
}
539555

540556
/**
@@ -556,13 +572,15 @@ PHP_FUNCTION(opencensus_trace_clear)
556572
*/
557573
PHP_FUNCTION(opencensus_trace_set_context)
558574
{
559-
zend_string *trace_id, *parent_span_id;
575+
zend_string *trace_id = NULL, *parent_span_id = NULL;
560576
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "S|S", &trace_id, &parent_span_id) == FAILURE) {
561577
RETURN_FALSE;
562578
}
563579

564580
OPENCENSUS_TRACE_G(trace_id) = zend_string_copy(trace_id);
565-
OPENCENSUS_TRACE_G(trace_parent_span_id) = zend_string_copy(parent_span_id);
581+
if (parent_span_id) {
582+
OPENCENSUS_TRACE_G(trace_parent_span_id) = zend_string_copy(parent_span_id);
583+
}
566584

567585
RETURN_TRUE;
568586
}
@@ -654,7 +672,7 @@ void opencensus_trace_execute_internal(INTERNAL_FUNCTION_PARAMETERS)
654672
} else {
655673
resume_execute_internal(INTERNAL_FUNCTION_PARAM_PASSTHRU);
656674
}
657-
/* zend_string_release(function_name); */
675+
zend_string_release(function_name);
658676
} else {
659677
resume_execute_internal(INTERNAL_FUNCTION_PARAM_PASSTHRU);
660678
}
@@ -670,7 +688,7 @@ void opencensus_trace_execute_internal(INTERNAL_FUNCTION_PARAMETERS)
670688
PHP_FUNCTION(opencensus_trace_function)
671689
{
672690
zend_string *function_name;
673-
zval *handler = NULL, *copy;
691+
zval *handler = NULL;
674692
zval h;
675693

676694
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "S|z", &function_name, &handler) == FAILURE) {
@@ -680,13 +698,11 @@ PHP_FUNCTION(opencensus_trace_function)
680698
if (handler == NULL) {
681699
ZVAL_LONG(&h, 1);
682700
handler = &h;
701+
} else {
702+
ZVAL_COPY(&h, handler);
683703
}
684704

685-
/* Note: these is freed in the RSHUTDOWN via opencensus_trace_clear */
686-
PHP_OPENCENSUS_MAKE_STD_ZVAL(copy);
687-
ZVAL_ZVAL(copy, handler, 1, 0);
688-
689-
zend_hash_update(OPENCENSUS_TRACE_G(user_traced_functions), function_name, copy);
705+
zend_hash_update(OPENCENSUS_TRACE_G(user_traced_functions), function_name, &h);
690706
RETURN_TRUE;
691707
}
692708

@@ -701,7 +717,7 @@ PHP_FUNCTION(opencensus_trace_function)
701717
PHP_FUNCTION(opencensus_trace_method)
702718
{
703719
zend_string *class_name, *function_name, *key;
704-
zval *handler = NULL, *copy;
720+
zval *handler = NULL;
705721
zval h;
706722

707723
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "SS|z", &class_name, &function_name, &handler) == FAILURE) {
@@ -711,14 +727,13 @@ PHP_FUNCTION(opencensus_trace_method)
711727
if (handler == NULL) {
712728
ZVAL_LONG(&h, 1);
713729
handler = &h;
730+
} else {
731+
ZVAL_COPY(&h, handler);
714732
}
715733

716-
/* Note: these is freed in the RSHUTDOWN via opencensus_trace_clear */
717-
PHP_OPENCENSUS_MAKE_STD_ZVAL(copy);
718-
ZVAL_ZVAL(copy, handler, 1, 0);
719-
720734
key = opencensus_trace_generate_class_name(class_name, function_name);
721-
zend_hash_update(OPENCENSUS_TRACE_G(user_traced_functions), key, handler);
735+
zend_hash_update(OPENCENSUS_TRACE_G(user_traced_functions), key, &h);
736+
zend_string_release(key);
722737

723738
RETURN_FALSE;
724739
}
@@ -732,11 +747,11 @@ PHP_FUNCTION(opencensus_trace_method)
732747
PHP_FUNCTION(opencensus_trace_list)
733748
{
734749
opencensus_trace_span_t *trace_span;
735-
zval span;
736750

737751
array_init(return_value);
738752

739753
ZEND_HASH_FOREACH_PTR(OPENCENSUS_TRACE_G(spans), trace_span) {
754+
zval span;
740755
opencensus_trace_span_to_zval(trace_span, &span);
741756
add_next_index_zval(return_value, &span TSRMLS_CC);
742757
} ZEND_HASH_FOREACH_END();
@@ -801,11 +816,11 @@ PHP_RINIT_FUNCTION(opencensus)
801816

802817
/* initialize storage for recorded spans - per request basis */
803818
ALLOC_HASHTABLE(OPENCENSUS_TRACE_G(spans));
804-
zend_hash_init(OPENCENSUS_TRACE_G(spans), 16, NULL, ZVAL_PTR_DTOR, 0);
819+
zend_hash_init(OPENCENSUS_TRACE_G(spans), 16, NULL, span_dtor, 0);
805820

806821
OPENCENSUS_TRACE_G(current_span) = NULL;
807822
OPENCENSUS_TRACE_G(trace_id) = NULL;
808-
OPENCENSUS_TRACE_G(trace_parent_span_id) = 0;
823+
OPENCENSUS_TRACE_G(trace_parent_span_id) = NULL;
809824

810825
return SUCCESS;
811826
}
@@ -814,14 +829,10 @@ PHP_RINIT_FUNCTION(opencensus)
814829
*/
815830
PHP_RSHUTDOWN_FUNCTION(opencensus)
816831
{
817-
zval *handler;
818-
819832
opencensus_trace_clear(0 TSRMLS_CC);
820833

821834
/* cleanup user_traced_functions zvals that we copied when registing */
822-
ZEND_HASH_FOREACH_VAL(OPENCENSUS_TRACE_G(user_traced_functions), handler) {
823-
PHP_OPENCENSUS_FREE_STD_ZVAL(handler);
824-
} ZEND_HASH_FOREACH_END();
835+
zend_hash_destroy(OPENCENSUS_TRACE_G(user_traced_functions));
825836
FREE_HASHTABLE(OPENCENSUS_TRACE_G(user_traced_functions));
826837

827838
return SUCCESS;

ext/opencensus_trace_annotation.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,8 +143,9 @@ void opencensus_trace_annotation_free(opencensus_trace_annotation_t *annotation)
143143
zend_string_release(annotation->description);
144144
}
145145
if (Z_TYPE(annotation->options) != IS_NULL) {
146-
ZVAL_PTR_DTOR(&annotation->options);
146+
ZVAL_DESTRUCTOR(&annotation->options);
147147
}
148+
efree(annotation);
148149
}
149150

150151
int opencensus_trace_annotation_to_zval(opencensus_trace_annotation_t *annotation, zval *zv)

ext/opencensus_trace_context.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,15 +57,15 @@ ZEND_END_ARG_INFO();
5757
* @param array $contextOptions
5858
*/
5959
static PHP_METHOD(OpenCensusTraceContext, __construct) {
60-
zval *zval_context_options, *v;
60+
zval *v;
6161
ulong idx;
6262
zend_string *k;
63+
HashTable *context_options;
6364

64-
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &zval_context_options) == FAILURE) {
65+
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "h", &context_options) == FAILURE) {
6566
return;
6667
}
6768

68-
zend_array *context_options = Z_ARR_P(zval_context_options);
6969
ZEND_HASH_FOREACH_KEY_VAL(context_options, idx, k, v) {
7070
zend_update_property(opencensus_trace_context_ce, getThis(), ZSTR_VAL(k), strlen(ZSTR_VAL(k)), v);
7171
} ZEND_HASH_FOREACH_END();

ext/opencensus_trace_link.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,8 +146,9 @@ void opencensus_trace_link_free(opencensus_trace_link_t *link)
146146
zend_string_release(link->span_id);
147147
}
148148
if (Z_TYPE(link->options) != IS_NULL) {
149-
ZVAL_PTR_DTOR(&link->options);
149+
ZVAL_DESTRUCTOR(&link->options);
150150
}
151+
efree(link);
151152
}
152153

153154
int opencensus_trace_link_to_zval(opencensus_trace_link_t *link, zval *zv)

ext/opencensus_trace_message_event.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,8 +172,9 @@ void opencensus_trace_message_event_free(opencensus_trace_message_event_t *messa
172172
zend_string_release(message_event->id);
173173
}
174174
if (Z_TYPE(message_event->options) != IS_NULL) {
175-
ZVAL_PTR_DTOR(&message_event->options);
175+
ZVAL_DESTRUCTOR(&message_event->options);
176176
}
177+
efree(message_event);
177178
}
178179

179180
int opencensus_trace_message_event_to_zval(opencensus_trace_message_event_t *message_event, zval *zv)

0 commit comments

Comments
 (0)