version 1.1.1.1, 2012/02/21 23:47:58
|
version 1.1.1.2, 2012/05/29 12:34:41
|
Line 24
|
Line 24
|
#include "mysqlnd.h" |
#include "mysqlnd.h" |
#include "mysqlnd_priv.h" |
#include "mysqlnd_priv.h" |
#include "mysqlnd_debug.h" |
#include "mysqlnd_debug.h" |
#include "mysqlnd_wireprotocol.h" |
|
#include "mysqlnd_statistics.h" |
|
#include "zend_builtin_functions.h" |
|
|
|
static const char * const mysqlnd_debug_default_trace_file = "/tmp/mysqlnd.trace"; |
static const char * const mysqlnd_debug_default_trace_file = "/tmp/mysqlnd.trace"; |
|
|
Line 36 static const char * const mysqlnd_debug_default_trace_
|
Line 33 static const char * const mysqlnd_debug_default_trace_
|
#define MYSQLND_ZTS(self) |
#define MYSQLND_ZTS(self) |
#endif |
#endif |
|
|
static const char mysqlnd_emalloc_name[] = "_mysqlnd_emalloc"; |
|
static const char mysqlnd_pemalloc_name[] = "_mysqlnd_pemalloc"; |
|
static const char mysqlnd_ecalloc_name[] = "_mysqlnd_ecalloc"; |
|
static const char mysqlnd_pecalloc_name[] = "_mysqlnd_pecalloc"; |
|
static const char mysqlnd_erealloc_name[] = "_mysqlnd_erealloc"; |
|
static const char mysqlnd_perealloc_name[] = "_mysqlnd_perealloc"; |
|
static const char mysqlnd_efree_name[] = "_mysqlnd_efree"; |
|
static const char mysqlnd_pefree_name[] = "_mysqlnd_pefree"; |
|
static const char mysqlnd_malloc_name[] = "_mysqlnd_malloc"; |
|
static const char mysqlnd_calloc_name[] = "_mysqlnd_calloc"; |
|
static const char mysqlnd_realloc_name[] = "_mysqlnd_realloc"; |
|
static const char mysqlnd_free_name[] = "_mysqlnd_free"; |
|
static const char mysqlnd_pestrndup_name[] = "_mysqlnd_pestrndup"; |
|
static const char mysqlnd_pestrdup_name[] = "_mysqlnd_pestrdup"; |
|
|
|
const char * mysqlnd_debug_std_no_trace_funcs[] = |
|
{ |
|
mysqlnd_emalloc_name, |
|
mysqlnd_ecalloc_name, |
|
mysqlnd_efree_name, |
|
mysqlnd_erealloc_name, |
|
mysqlnd_pemalloc_name, |
|
mysqlnd_pecalloc_name, |
|
mysqlnd_pefree_name, |
|
mysqlnd_perealloc_name, |
|
mysqlnd_malloc_name, |
|
mysqlnd_calloc_name, |
|
mysqlnd_realloc_name, |
|
mysqlnd_free_name, |
|
mysqlnd_pestrndup_name, |
|
mysqlnd_read_header_name, |
|
mysqlnd_read_body_name, |
|
NULL /* must be always last */ |
|
}; |
|
|
|
|
|
/* {{{ mysqlnd_debug::open */ |
/* {{{ mysqlnd_debug::open */ |
static enum_func_status |
static enum_func_status |
MYSQLND_METHOD(mysqlnd_debug, open)(MYSQLND_DEBUG * self, zend_bool reopen) |
MYSQLND_METHOD(mysqlnd_debug, open)(MYSQLND_DEBUG * self, zend_bool reopen) |
Line 167 MYSQLND_METHOD(mysqlnd_debug, log)(MYSQLND_DEBUG * sel
|
Line 129 MYSQLND_METHOD(mysqlnd_debug, log)(MYSQLND_DEBUG * sel
|
level_buffer[sizeof(level_buffer) - 1 ] = '\0'; |
level_buffer[sizeof(level_buffer) - 1 ] = '\0'; |
} |
} |
|
|
message_line_len = spprintf(&message_line, 0, "%s%s%s%s%s%s%s%s\n", | message_line_len = mnd_sprintf(&message_line, 0, "%s%s%s%s%s%s%s%s\n", |
flags & MYSQLND_DEBUG_DUMP_PID? pid_buffer:"", |
flags & MYSQLND_DEBUG_DUMP_PID? pid_buffer:"", |
flags & MYSQLND_DEBUG_DUMP_TIME? time_buffer:"", |
flags & MYSQLND_DEBUG_DUMP_TIME? time_buffer:"", |
flags & MYSQLND_DEBUG_DUMP_FILE? file_buffer:"", |
flags & MYSQLND_DEBUG_DUMP_FILE? file_buffer:"", |
Line 176 MYSQLND_METHOD(mysqlnd_debug, log)(MYSQLND_DEBUG * sel
|
Line 138 MYSQLND_METHOD(mysqlnd_debug, log)(MYSQLND_DEBUG * sel
|
pipe_buffer, type? type:"", message); |
pipe_buffer, type? type:"", message); |
|
|
ret = php_stream_write(self->stream, message_line, message_line_len)? PASS:FAIL; |
ret = php_stream_write(self->stream, message_line, message_line_len)? PASS:FAIL; |
efree(message_line); /* allocated by spprintf */ | mnd_sprintf_free(message_line); |
if (flags & MYSQLND_DEBUG_FLUSH) { |
if (flags & MYSQLND_DEBUG_FLUSH) { |
self->m->close(self); |
self->m->close(self); |
self->m->open(self, TRUE); |
self->m->open(self, TRUE); |
Line 265 MYSQLND_METHOD(mysqlnd_debug, log_va)(MYSQLND_DEBUG *s
|
Line 227 MYSQLND_METHOD(mysqlnd_debug, log_va)(MYSQLND_DEBUG *s
|
level_buffer[sizeof(level_buffer) - 1 ] = '\0'; |
level_buffer[sizeof(level_buffer) - 1 ] = '\0'; |
} |
} |
|
|
|
|
va_start(args, format); |
va_start(args, format); |
vspprintf(&buffer, 0, format, args); | mnd_vsprintf(&buffer, 0, format, args); |
va_end(args); |
va_end(args); |
|
|
message_line_len = spprintf(&message_line, 0, "%s%s%s%s%s%s%s%s\n", | message_line_len = mnd_sprintf(&message_line, 0, "%s%s%s%s%s%s%s%s\n", |
flags & MYSQLND_DEBUG_DUMP_PID? pid_buffer:"", |
flags & MYSQLND_DEBUG_DUMP_PID? pid_buffer:"", |
flags & MYSQLND_DEBUG_DUMP_TIME? time_buffer:"", |
flags & MYSQLND_DEBUG_DUMP_TIME? time_buffer:"", |
flags & MYSQLND_DEBUG_DUMP_FILE? file_buffer:"", |
flags & MYSQLND_DEBUG_DUMP_FILE? file_buffer:"", |
flags & MYSQLND_DEBUG_DUMP_LINE? line_buffer:"", |
flags & MYSQLND_DEBUG_DUMP_LINE? line_buffer:"", |
flags & MYSQLND_DEBUG_DUMP_LEVEL? level_buffer:"", |
flags & MYSQLND_DEBUG_DUMP_LEVEL? level_buffer:"", |
pipe_buffer, type? type:"", buffer); |
pipe_buffer, type? type:"", buffer); |
efree(buffer); | mnd_sprintf_free(buffer); |
ret = php_stream_write(self->stream, message_line, message_line_len)? PASS:FAIL; |
ret = php_stream_write(self->stream, message_line, message_line_len)? PASS:FAIL; |
efree(message_line); /* allocated by spprintf */ | mnd_sprintf_free(message_line); |
|
|
if (flags & MYSQLND_DEBUG_FLUSH) { |
if (flags & MYSQLND_DEBUG_FLUSH) { |
self->m->close(self); |
self->m->close(self); |
Line 538 MYSQLND_METHOD(mysqlnd_debug, free)(MYSQLND_DEBUG * se
|
Line 499 MYSQLND_METHOD(mysqlnd_debug, free)(MYSQLND_DEBUG * se
|
zend_stack_destroy(&self->call_time_stack); |
zend_stack_destroy(&self->call_time_stack); |
zend_hash_destroy(&self->not_filtered_functions); |
zend_hash_destroy(&self->not_filtered_functions); |
zend_hash_destroy(&self->function_profiles); |
zend_hash_destroy(&self->function_profiles); |
efree(self); | free(self); |
return PASS; |
return PASS; |
} |
} |
/* }}} */ |
/* }}} */ |
Line 761 MYSQLND_CLASS_METHODS_END;
|
Line 722 MYSQLND_CLASS_METHODS_END;
|
PHPAPI MYSQLND_DEBUG * |
PHPAPI MYSQLND_DEBUG * |
mysqlnd_debug_init(const char * skip_functions[] TSRMLS_DC) |
mysqlnd_debug_init(const char * skip_functions[] TSRMLS_DC) |
{ |
{ |
MYSQLND_DEBUG *ret = ecalloc(1, sizeof(MYSQLND_DEBUG)); | MYSQLND_DEBUG *ret = calloc(1, sizeof(MYSQLND_DEBUG)); |
#ifdef ZTS |
#ifdef ZTS |
ret->TSRMLS_C = TSRMLS_C; |
ret->TSRMLS_C = TSRMLS_C; |
#endif |
#endif |
Line 783 mysqlnd_debug_init(const char * skip_functions[] TSRML
|
Line 744 mysqlnd_debug_init(const char * skip_functions[] TSRML
|
/* {{{ _mysqlnd_debug */ |
/* {{{ _mysqlnd_debug */ |
PHPAPI void _mysqlnd_debug(const char * mode TSRMLS_DC) |
PHPAPI void _mysqlnd_debug(const char * mode TSRMLS_DC) |
{ |
{ |
#ifdef PHP_DEBUG | #if PHP_DEBUG |
MYSQLND_DEBUG *dbg = MYSQLND_G(dbg); |
MYSQLND_DEBUG *dbg = MYSQLND_G(dbg); |
if (!dbg) { |
if (!dbg) { |
MYSQLND_G(dbg) = dbg = mysqlnd_debug_init(mysqlnd_debug_std_no_trace_funcs TSRMLS_CC); |
MYSQLND_G(dbg) = dbg = mysqlnd_debug_init(mysqlnd_debug_std_no_trace_funcs TSRMLS_CC); |
Line 805 PHPAPI void _mysqlnd_debug(const char * mode TSRMLS_DC
|
Line 766 PHPAPI void _mysqlnd_debug(const char * mode TSRMLS_DC
|
/* }}} */ |
/* }}} */ |
|
|
|
|
#if ZEND_DEBUG | static struct st_mysqlnd_plugin_trace_log mysqlnd_plugin_trace_log_plugin = |
#else | |
#define __zend_filename "/unknown/unknown" | |
#define __zend_lineno 0 | |
#endif | |
| |
#define REAL_SIZE(s) (collect_memory_statistics? (s) + sizeof(size_t) : (s)) | |
#define REAL_PTR(p) (collect_memory_statistics && (p)? (((char *)(p)) - sizeof(size_t)) : (p)) | |
#define FAKE_PTR(p) (collect_memory_statistics && (p)? (((char *)(p)) + sizeof(size_t)) : (p)) | |
| |
/* {{{ _mysqlnd_emalloc */ | |
void * _mysqlnd_emalloc(size_t size MYSQLND_MEM_D) | |
{ |
{ |
void *ret; |
|
zend_bool collect_memory_statistics = MYSQLND_G(collect_memory_statistics); |
|
long * threshold = &MYSQLND_G(debug_emalloc_fail_threshold); |
|
DBG_ENTER(mysqlnd_emalloc_name); |
|
|
|
DBG_INF_FMT("file=%-15s line=%4d", strrchr(__zend_filename, PHP_DIR_SEPARATOR) + 1, __zend_lineno); |
|
|
|
#ifdef PHP_DEBUG |
|
/* -1 is also "true" */ |
|
if (*threshold) { |
|
#endif |
|
ret = emalloc(REAL_SIZE(size)); |
|
#ifdef PHP_DEBUG |
|
--*threshold; |
|
} else if (*threshold == 0) { |
|
ret = NULL; |
|
} |
|
#endif |
|
|
|
DBG_INF_FMT("size=%lu ptr=%p", size, ret); |
|
|
|
if (ret && collect_memory_statistics) { |
|
*(size_t *) ret = size; |
|
MYSQLND_INC_GLOBAL_STATISTIC_W_VALUE2(STAT_MEM_EMALLOC_COUNT, 1, STAT_MEM_EMALLOC_AMOUNT, size); |
|
} |
|
DBG_RETURN(FAKE_PTR(ret)); |
|
} |
|
/* }}} */ |
|
|
|
|
|
/* {{{ _mysqlnd_pemalloc */ |
|
void * _mysqlnd_pemalloc(size_t size, zend_bool persistent MYSQLND_MEM_D) |
|
{ |
|
void *ret; |
|
zend_bool collect_memory_statistics = MYSQLND_G(collect_memory_statistics); |
|
long * threshold = persistent? &MYSQLND_G(debug_malloc_fail_threshold):&MYSQLND_G(debug_emalloc_fail_threshold); |
|
DBG_ENTER(mysqlnd_pemalloc_name); |
|
DBG_INF_FMT("file=%-15s line=%4d", strrchr(__zend_filename, PHP_DIR_SEPARATOR) + 1, __zend_lineno); |
|
|
|
#ifdef PHP_DEBUG |
|
/* -1 is also "true" */ |
|
if (*threshold) { |
|
#endif |
|
ret = pemalloc(REAL_SIZE(size), persistent); |
|
#ifdef PHP_DEBUG |
|
--*threshold; |
|
} else if (*threshold == 0) { |
|
ret = NULL; |
|
} |
|
#endif |
|
|
|
DBG_INF_FMT("size=%lu ptr=%p persistent=%u", size, ret, persistent); |
|
|
|
if (ret && collect_memory_statistics) { |
|
enum mysqlnd_collected_stats s1 = persistent? STAT_MEM_MALLOC_COUNT:STAT_MEM_EMALLOC_COUNT; |
|
enum mysqlnd_collected_stats s2 = persistent? STAT_MEM_MALLOC_AMOUNT:STAT_MEM_EMALLOC_AMOUNT; |
|
*(size_t *) ret = size; |
|
MYSQLND_INC_GLOBAL_STATISTIC_W_VALUE2(s1, 1, s2, size); |
|
} |
|
|
|
DBG_RETURN(FAKE_PTR(ret)); |
|
} |
|
/* }}} */ |
|
|
|
|
|
/* {{{ _mysqlnd_ecalloc */ |
|
void * _mysqlnd_ecalloc(unsigned int nmemb, size_t size MYSQLND_MEM_D) |
|
{ |
|
void *ret; |
|
zend_bool collect_memory_statistics = MYSQLND_G(collect_memory_statistics); |
|
long * threshold = &MYSQLND_G(debug_ecalloc_fail_threshold); |
|
DBG_ENTER(mysqlnd_ecalloc_name); |
|
DBG_INF_FMT("file=%-15s line=%4d", strrchr(__zend_filename, PHP_DIR_SEPARATOR) + 1, __zend_lineno); |
|
DBG_INF_FMT("before: %lu", zend_memory_usage(FALSE TSRMLS_CC)); |
|
|
|
#ifdef PHP_DEBUG |
|
/* -1 is also "true" */ |
|
if (*threshold) { |
|
#endif |
|
ret = ecalloc(nmemb, REAL_SIZE(size)); |
|
#ifdef PHP_DEBUG |
|
--*threshold; |
|
} else if (*threshold == 0) { |
|
ret = NULL; |
|
} |
|
#endif |
|
|
|
DBG_INF_FMT("after : %lu", zend_memory_usage(FALSE TSRMLS_CC)); |
|
DBG_INF_FMT("size=%lu ptr=%p", size, ret); |
|
if (ret && collect_memory_statistics) { |
|
*(size_t *) ret = size; |
|
MYSQLND_INC_GLOBAL_STATISTIC_W_VALUE2(STAT_MEM_ECALLOC_COUNT, 1, STAT_MEM_ECALLOC_AMOUNT, size); |
|
} |
|
DBG_RETURN(FAKE_PTR(ret)); |
|
} |
|
/* }}} */ |
|
|
|
|
|
/* {{{ _mysqlnd_pecalloc */ |
|
void * _mysqlnd_pecalloc(unsigned int nmemb, size_t size, zend_bool persistent MYSQLND_MEM_D) |
|
{ |
|
void *ret; |
|
zend_bool collect_memory_statistics = MYSQLND_G(collect_memory_statistics); |
|
long * threshold = persistent? &MYSQLND_G(debug_calloc_fail_threshold):&MYSQLND_G(debug_ecalloc_fail_threshold); |
|
DBG_ENTER(mysqlnd_pecalloc_name); |
|
DBG_INF_FMT("file=%-15s line=%4d", strrchr(__zend_filename, PHP_DIR_SEPARATOR) + 1, __zend_lineno); |
|
|
|
#ifdef PHP_DEBUG |
|
/* -1 is also "true" */ |
|
if (*threshold) { |
|
#endif |
|
ret = pecalloc(nmemb, REAL_SIZE(size), persistent); |
|
#ifdef PHP_DEBUG |
|
--*threshold; |
|
} else if (*threshold == 0) { |
|
ret = NULL; |
|
} |
|
#endif |
|
|
|
DBG_INF_FMT("size=%lu ptr=%p", size, ret); |
|
|
|
if (ret && collect_memory_statistics) { |
|
enum mysqlnd_collected_stats s1 = persistent? STAT_MEM_CALLOC_COUNT:STAT_MEM_ECALLOC_COUNT; |
|
enum mysqlnd_collected_stats s2 = persistent? STAT_MEM_CALLOC_AMOUNT:STAT_MEM_ECALLOC_AMOUNT; |
|
*(size_t *) ret = size; |
|
MYSQLND_INC_GLOBAL_STATISTIC_W_VALUE2(s1, 1, s2, size); |
|
} |
|
|
|
DBG_RETURN(FAKE_PTR(ret)); |
|
} |
|
/* }}} */ |
|
|
|
|
|
/* {{{ _mysqlnd_erealloc */ |
|
void * _mysqlnd_erealloc(void *ptr, size_t new_size MYSQLND_MEM_D) |
|
{ |
|
void *ret; |
|
zend_bool collect_memory_statistics = MYSQLND_G(collect_memory_statistics); |
|
size_t old_size = collect_memory_statistics && ptr? *(size_t *) (((char*)ptr) - sizeof(size_t)) : 0; |
|
long * threshold = &MYSQLND_G(debug_erealloc_fail_threshold); |
|
DBG_ENTER(mysqlnd_erealloc_name); |
|
DBG_INF_FMT("file=%-15s line=%4d", strrchr(__zend_filename, PHP_DIR_SEPARATOR) + 1, __zend_lineno); |
|
DBG_INF_FMT("ptr=%p old_size=%lu, new_size=%lu", ptr, old_size, new_size); |
|
|
|
#ifdef PHP_DEBUG |
|
/* -1 is also "true" */ |
|
if (*threshold) { |
|
#endif |
|
ret = erealloc(REAL_PTR(ptr), REAL_SIZE(new_size)); |
|
#ifdef PHP_DEBUG |
|
--*threshold; |
|
} else if (*threshold == 0) { |
|
ret = NULL; |
|
} |
|
#endif |
|
|
|
DBG_INF_FMT("new_ptr=%p", (char*)ret); |
|
if (ret && collect_memory_statistics) { |
|
*(size_t *) ret = new_size; |
|
MYSQLND_INC_GLOBAL_STATISTIC_W_VALUE2(STAT_MEM_EREALLOC_COUNT, 1, STAT_MEM_EREALLOC_AMOUNT, new_size); |
|
} |
|
DBG_RETURN(FAKE_PTR(ret)); |
|
} |
|
/* }}} */ |
|
|
|
|
|
/* {{{ _mysqlnd_perealloc */ |
|
void * _mysqlnd_perealloc(void *ptr, size_t new_size, zend_bool persistent MYSQLND_MEM_D) |
|
{ |
|
void *ret; |
|
zend_bool collect_memory_statistics = MYSQLND_G(collect_memory_statistics); |
|
size_t old_size = collect_memory_statistics && ptr? *(size_t *) (((char*)ptr) - sizeof(size_t)) : 0; |
|
long * threshold = persistent? &MYSQLND_G(debug_realloc_fail_threshold):&MYSQLND_G(debug_erealloc_fail_threshold); |
|
DBG_ENTER(mysqlnd_perealloc_name); |
|
DBG_INF_FMT("file=%-15s line=%4d", strrchr(__zend_filename, PHP_DIR_SEPARATOR) + 1, __zend_lineno); |
|
DBG_INF_FMT("ptr=%p old_size=%lu new_size=%lu persistent=%u", ptr, old_size, new_size, persistent); |
|
|
|
#ifdef PHP_DEBUG |
|
/* -1 is also "true" */ |
|
if (*threshold) { |
|
#endif |
|
ret = perealloc(REAL_PTR(ptr), REAL_SIZE(new_size), persistent); |
|
#ifdef PHP_DEBUG |
|
--*threshold; |
|
} else if (*threshold == 0) { |
|
ret = NULL; |
|
} |
|
#endif |
|
|
|
DBG_INF_FMT("new_ptr=%p", (char*)ret); |
|
|
|
if (ret && collect_memory_statistics) { |
|
enum mysqlnd_collected_stats s1 = persistent? STAT_MEM_REALLOC_COUNT:STAT_MEM_EREALLOC_COUNT; |
|
enum mysqlnd_collected_stats s2 = persistent? STAT_MEM_REALLOC_AMOUNT:STAT_MEM_EREALLOC_AMOUNT; |
|
*(size_t *) ret = new_size; |
|
MYSQLND_INC_GLOBAL_STATISTIC_W_VALUE2(s1, 1, s2, new_size); |
|
} |
|
DBG_RETURN(FAKE_PTR(ret)); |
|
} |
|
/* }}} */ |
|
|
|
|
|
/* {{{ _mysqlnd_efree */ |
|
void _mysqlnd_efree(void *ptr MYSQLND_MEM_D) |
|
{ |
|
size_t free_amount = 0; |
|
zend_bool collect_memory_statistics = MYSQLND_G(collect_memory_statistics); |
|
DBG_ENTER(mysqlnd_efree_name); |
|
DBG_INF_FMT("file=%-15s line=%4d", strrchr(__zend_filename, PHP_DIR_SEPARATOR) + 1, __zend_lineno); |
|
DBG_INF_FMT("ptr=%p", ptr); |
|
|
|
if (ptr) { |
|
if (collect_memory_statistics) { |
|
free_amount = *(size_t *)(((char*)ptr) - sizeof(size_t)); |
|
DBG_INF_FMT("ptr=%p size=%u", ((char*)ptr) - sizeof(size_t), (unsigned int) free_amount); |
|
} |
|
efree(REAL_PTR(ptr)); |
|
} |
|
|
|
if (collect_memory_statistics) { |
|
MYSQLND_INC_GLOBAL_STATISTIC_W_VALUE2(STAT_MEM_EFREE_COUNT, 1, STAT_MEM_EFREE_AMOUNT, free_amount); |
|
} |
|
DBG_VOID_RETURN; |
|
} |
|
/* }}} */ |
|
|
|
|
|
/* {{{ _mysqlnd_pefree */ |
|
void _mysqlnd_pefree(void *ptr, zend_bool persistent MYSQLND_MEM_D) |
|
{ |
|
size_t free_amount = 0; |
|
zend_bool collect_memory_statistics = MYSQLND_G(collect_memory_statistics); |
|
DBG_ENTER(mysqlnd_pefree_name); |
|
DBG_INF_FMT("file=%-15s line=%4d", strrchr(__zend_filename, PHP_DIR_SEPARATOR) + 1, __zend_lineno); |
|
DBG_INF_FMT("ptr=%p persistent=%u", ptr, persistent); |
|
|
|
if (ptr) { |
|
if (collect_memory_statistics) { |
|
free_amount = *(size_t *)(((char*)ptr) - sizeof(size_t)); |
|
DBG_INF_FMT("ptr=%p size=%u", ((char*)ptr) - sizeof(size_t), (unsigned int) free_amount); |
|
} |
|
pefree(REAL_PTR(ptr), persistent); |
|
} |
|
|
|
if (collect_memory_statistics) { |
|
MYSQLND_INC_GLOBAL_STATISTIC_W_VALUE2(persistent? STAT_MEM_FREE_COUNT:STAT_MEM_EFREE_COUNT, 1, |
|
persistent? STAT_MEM_FREE_AMOUNT:STAT_MEM_EFREE_AMOUNT, free_amount); |
|
} |
|
DBG_VOID_RETURN; |
|
} |
|
|
|
|
|
/* {{{ _mysqlnd_malloc */ |
|
void * _mysqlnd_malloc(size_t size MYSQLND_MEM_D) |
|
{ |
|
void *ret; |
|
zend_bool collect_memory_statistics = MYSQLND_G(collect_memory_statistics); |
|
long * threshold = &MYSQLND_G(debug_malloc_fail_threshold); |
|
DBG_ENTER(mysqlnd_malloc_name); |
|
DBG_INF_FMT("file=%-15s line=%4d", strrchr(__zend_filename, PHP_DIR_SEPARATOR) + 1, __zend_lineno); |
|
|
|
#ifdef PHP_DEBUG |
|
/* -1 is also "true" */ |
|
if (*threshold) { |
|
#endif |
|
ret = malloc(REAL_SIZE(size)); |
|
#ifdef PHP_DEBUG |
|
--*threshold; |
|
} else if (*threshold == 0) { |
|
ret = NULL; |
|
} |
|
#endif |
|
|
|
DBG_INF_FMT("size=%lu ptr=%p", size, ret); |
|
if (ret && collect_memory_statistics) { |
|
*(size_t *) ret = size; |
|
MYSQLND_INC_GLOBAL_STATISTIC_W_VALUE2(STAT_MEM_MALLOC_COUNT, 1, STAT_MEM_MALLOC_AMOUNT, size); |
|
} |
|
DBG_RETURN(FAKE_PTR(ret)); |
|
} |
|
/* }}} */ |
|
|
|
|
|
/* {{{ _mysqlnd_calloc */ |
|
void * _mysqlnd_calloc(unsigned int nmemb, size_t size MYSQLND_MEM_D) |
|
{ |
|
void *ret; |
|
zend_bool collect_memory_statistics = MYSQLND_G(collect_memory_statistics); |
|
long * threshold = &MYSQLND_G(debug_calloc_fail_threshold); |
|
DBG_ENTER(mysqlnd_calloc_name); |
|
DBG_INF_FMT("file=%-15s line=%4d", strrchr(__zend_filename, PHP_DIR_SEPARATOR) + 1, __zend_lineno); |
|
|
|
#ifdef PHP_DEBUG |
|
/* -1 is also "true" */ |
|
if (*threshold) { |
|
#endif |
|
ret = calloc(nmemb, REAL_SIZE(size)); |
|
#ifdef PHP_DEBUG |
|
--*threshold; |
|
} else if (*threshold == 0) { |
|
ret = NULL; |
|
} |
|
#endif |
|
|
|
DBG_INF_FMT("size=%lu ptr=%p", size, ret); |
|
if (ret && collect_memory_statistics) { |
|
*(size_t *) ret = size; |
|
MYSQLND_INC_GLOBAL_STATISTIC_W_VALUE2(STAT_MEM_CALLOC_COUNT, 1, STAT_MEM_CALLOC_AMOUNT, size); |
|
} |
|
DBG_RETURN(FAKE_PTR(ret)); |
|
} |
|
/* }}} */ |
|
|
|
|
|
/* {{{ _mysqlnd_realloc */ |
|
void * _mysqlnd_realloc(void *ptr, size_t new_size MYSQLND_MEM_D) |
|
{ |
|
void *ret; |
|
zend_bool collect_memory_statistics = MYSQLND_G(collect_memory_statistics); |
|
long * threshold = &MYSQLND_G(debug_realloc_fail_threshold); |
|
DBG_ENTER(mysqlnd_realloc_name); |
|
DBG_INF_FMT("file=%-15s line=%4d", strrchr(__zend_filename, PHP_DIR_SEPARATOR) + 1, __zend_lineno); |
|
DBG_INF_FMT("ptr=%p new_size=%lu ", new_size, ptr); |
|
DBG_INF_FMT("before: %lu", zend_memory_usage(TRUE TSRMLS_CC)); |
|
|
|
#ifdef PHP_DEBUG |
|
/* -1 is also "true" */ |
|
if (*threshold) { |
|
#endif |
|
ret = realloc(REAL_PTR(ptr), REAL_SIZE(new_size)); |
|
#ifdef PHP_DEBUG |
|
--*threshold; |
|
} else if (*threshold == 0) { |
|
ret = NULL; |
|
} |
|
#endif |
|
|
|
DBG_INF_FMT("new_ptr=%p", (char*)ret); |
|
|
|
if (ret && collect_memory_statistics) { |
|
*(size_t *) ret = new_size; |
|
MYSQLND_INC_GLOBAL_STATISTIC_W_VALUE2(STAT_MEM_REALLOC_COUNT, 1, STAT_MEM_REALLOC_AMOUNT, new_size); |
|
} |
|
DBG_RETURN(FAKE_PTR(ret)); |
|
} |
|
/* }}} */ |
|
|
|
|
|
/* {{{ _mysqlnd_free */ |
|
void _mysqlnd_free(void *ptr MYSQLND_MEM_D) |
|
{ |
|
size_t free_amount = 0; |
|
zend_bool collect_memory_statistics = MYSQLND_G(collect_memory_statistics); |
|
DBG_ENTER(mysqlnd_free_name); |
|
DBG_INF_FMT("file=%-15s line=%4d", strrchr(__zend_filename, PHP_DIR_SEPARATOR) + 1, __zend_lineno); |
|
DBG_INF_FMT("ptr=%p", ptr); |
|
|
|
if (ptr) { |
|
if (collect_memory_statistics) { |
|
free_amount = *(size_t *)(((char*)ptr) - sizeof(size_t)); |
|
DBG_INF_FMT("ptr=%p size=%u", ((char*)ptr) - sizeof(size_t), (unsigned int) free_amount); |
|
} |
|
free(REAL_PTR(ptr)); |
|
} |
|
|
|
if (collect_memory_statistics) { |
|
MYSQLND_INC_GLOBAL_STATISTIC_W_VALUE2(STAT_MEM_FREE_COUNT, 1, STAT_MEM_FREE_AMOUNT, free_amount); |
|
} |
|
DBG_VOID_RETURN; |
|
} |
|
/* }}} */ |
|
|
|
#define SMART_STR_START_SIZE 2048 |
|
#define SMART_STR_PREALLOC 512 |
|
#include "ext/standard/php_smart_str.h" |
|
|
|
|
|
/* {{{ _mysqlnd_pestrndup */ |
|
char * _mysqlnd_pestrndup(const char * const ptr, size_t length, zend_bool persistent MYSQLND_MEM_D) |
|
{ |
|
char * ret; |
|
zend_bool collect_memory_statistics = MYSQLND_G(collect_memory_statistics); |
|
DBG_ENTER(mysqlnd_pestrndup_name); |
|
DBG_INF_FMT("file=%-15s line=%4d", strrchr(__zend_filename, PHP_DIR_SEPARATOR) + 1, __zend_lineno); |
|
DBG_INF_FMT("ptr=%p", ptr); |
|
|
|
ret = pemalloc(REAL_SIZE(length) + 1, persistent); |
|
{ |
{ |
size_t l = length; | MYSQLND_PLUGIN_API_VERSION, |
char * p = (char *) ptr; | "debug_trace", |
char * dest = (char *) FAKE_PTR(ret); | MYSQLND_VERSION_ID, |
while (*p && l--) { | MYSQLND_VERSION, |
*dest++ = *p++; | "PHP License 3.01", |
| "Andrey Hristov <andrey@mysql.com>, Ulf Wendel <uwendel@mysql.com>, Georg Richter <georg@mysql.com>", |
| { |
| NULL, /* no statistics , will be filled later if there are some */ |
| NULL, /* no statistics */ |
| }, |
| { |
| NULL /* plugin shutdown */ |
} |
} |
*dest = '\0'; | }, |
| {/* methods */ |
| mysqlnd_debug_init, |
| mysqlnd_get_backtrace |
} |
} |
|
|
if (collect_memory_statistics) { |
|
*(size_t *) ret = length; |
|
MYSQLND_INC_GLOBAL_STATISTIC(persistent? STAT_MEM_STRNDUP_COUNT : STAT_MEM_ESTRNDUP_COUNT); |
|
} |
|
|
|
DBG_RETURN(FAKE_PTR(ret)); |
|
} |
|
/* }}} */ |
|
|
|
|
|
/* {{{ _mysqlnd_pestrdup */ |
|
char * _mysqlnd_pestrdup(const char * const ptr, zend_bool persistent MYSQLND_MEM_D) |
|
{ |
|
char * ret; |
|
smart_str tmp_str = {0, 0, 0}; |
|
const char * p = ptr; |
|
zend_bool collect_memory_statistics = MYSQLND_G(collect_memory_statistics); |
|
DBG_ENTER(mysqlnd_pestrdup_name); |
|
DBG_INF_FMT("file=%-15s line=%4d", strrchr(__zend_filename, PHP_DIR_SEPARATOR) + 1, __zend_lineno); |
|
DBG_INF_FMT("ptr=%p", ptr); |
|
do { |
|
smart_str_appendc(&tmp_str, *p); |
|
} while (*p++); |
|
|
|
ret = pemalloc(tmp_str.len + sizeof(size_t), persistent); |
|
memcpy(FAKE_PTR(ret), tmp_str.c, tmp_str.len); |
|
|
|
if (ret && collect_memory_statistics) { |
|
*(size_t *) ret = tmp_str.len; |
|
MYSQLND_INC_GLOBAL_STATISTIC(persistent? STAT_MEM_STRDUP_COUNT : STAT_MEM_ESTRDUP_COUNT); |
|
} |
|
smart_str_free(&tmp_str); |
|
|
|
DBG_RETURN(FAKE_PTR(ret)); |
|
} |
|
/* }}} */ |
|
|
|
#define MYSQLND_DEBUG_MEMORY 1 |
|
|
|
#if MYSQLND_DEBUG_MEMORY == 0 |
|
|
|
/* {{{ mysqlnd_zend_mm_emalloc */ |
|
static void * mysqlnd_zend_mm_emalloc(size_t size MYSQLND_MEM_D) |
|
{ |
|
return emalloc(size); |
|
} |
|
/* }}} */ |
|
|
|
|
|
/* {{{ mysqlnd_zend_mm_pemalloc */ |
|
static void * mysqlnd_zend_mm_pemalloc(size_t size, zend_bool persistent MYSQLND_MEM_D) |
|
{ |
|
return pemalloc(size, persistent); |
|
} |
|
/* }}} */ |
|
|
|
|
|
/* {{{ mysqlnd_zend_mm_ecalloc */ |
|
static void * mysqlnd_zend_mm_ecalloc(unsigned int nmemb, size_t size MYSQLND_MEM_D) |
|
{ |
|
return ecalloc(nmemb, size); |
|
} |
|
/* }}} */ |
|
|
|
|
|
/* {{{ mysqlnd_zend_mm_pecalloc */ |
|
static void * mysqlnd_zend_mm_pecalloc(unsigned int nmemb, size_t size, zend_bool persistent MYSQLND_MEM_D) |
|
{ |
|
return pecalloc(nmemb, size, persistent); |
|
} |
|
/* }}} */ |
|
|
|
|
|
/* {{{ mysqlnd_zend_mm_erealloc */ |
|
static void * mysqlnd_zend_mm_erealloc(void *ptr, size_t new_size MYSQLND_MEM_D) |
|
{ |
|
return erealloc(ptr, new_size); |
|
} |
|
/* }}} */ |
|
|
|
|
|
/* {{{ mysqlnd_zend_mm_perealloc */ |
|
static void * mysqlnd_zend_mm_perealloc(void *ptr, size_t new_size, zend_bool persistent MYSQLND_MEM_D) |
|
{ |
|
return perealloc(ptr, new_size, persistent); |
|
} |
|
/* }}} */ |
|
|
|
|
|
/* {{{ mysqlnd_zend_mm_efree */ |
|
static void mysqlnd_zend_mm_efree(void * ptr MYSQLND_MEM_D) |
|
{ |
|
efree(ptr); |
|
} |
|
/* }}} */ |
|
|
|
|
|
/* {{{ mysqlnd_zend_mm_pefree */ |
|
static void mysqlnd_zend_mm_pefree(void * ptr, zend_bool persistent MYSQLND_MEM_D) |
|
{ |
|
pefree(ptr, persistent); |
|
} |
|
/* }}} */ |
|
|
|
|
|
/* {{{ mysqlnd_zend_mm_malloc */ |
|
static void * mysqlnd_zend_mm_malloc(size_t size MYSQLND_MEM_D) |
|
{ |
|
return malloc(size); |
|
} |
|
/* }}} */ |
|
|
|
|
|
/* {{{ mysqlnd_zend_mm_calloc */ |
|
static void * mysqlnd_zend_mm_calloc(unsigned int nmemb, size_t size MYSQLND_MEM_D) |
|
{ |
|
return calloc(nmemb, size); |
|
} |
|
/* }}} */ |
|
|
|
|
|
/* {{{ mysqlnd_zend_mm_realloc */ |
|
static void * mysqlnd_zend_mm_realloc(void * ptr, size_t new_size MYSQLND_MEM_D) |
|
{ |
|
return realloc(ptr, new_size); |
|
} |
|
/* }}} */ |
|
|
|
|
|
/* {{{ mysqlnd_zend_mm_free */ |
|
static void mysqlnd_zend_mm_free(void * ptr MYSQLND_MEM_D) |
|
{ |
|
free(ptr); |
|
} |
|
/* }}} */ |
|
|
|
|
|
/* {{{ mysqlnd_zend_mm_pestrndup */ |
|
static char * mysqlnd_zend_mm_pestrndup(const char * const ptr, size_t length, zend_bool persistent MYSQLND_MEM_D) |
|
{ |
|
return pestrndup(ptr, length, persistent); |
|
} |
|
/* }}} */ |
|
|
|
|
|
/* {{{ mysqlnd_zend_mm_pestrdup */ |
|
static char * mysqlnd_zend_mm_pestrdup(const char * const ptr, zend_bool persistent MYSQLND_MEM_D) |
|
{ |
|
return pestrdup(ptr, persistent); |
|
} |
|
/* }}} */ |
|
|
|
#endif |
|
|
|
|
|
PHPAPI struct st_mysqlnd_allocator_methods mysqlnd_allocator = |
|
{ |
|
#if MYSQLND_DEBUG_MEMORY |
|
_mysqlnd_emalloc, |
|
_mysqlnd_pemalloc, |
|
_mysqlnd_ecalloc, |
|
_mysqlnd_pecalloc, |
|
_mysqlnd_erealloc, |
|
_mysqlnd_perealloc, |
|
_mysqlnd_efree, |
|
_mysqlnd_pefree, |
|
_mysqlnd_malloc, |
|
_mysqlnd_calloc, |
|
_mysqlnd_realloc, |
|
_mysqlnd_free, |
|
_mysqlnd_pestrndup, |
|
_mysqlnd_pestrdup |
|
#else |
|
mysqlnd_zend_mm_emalloc, |
|
mysqlnd_zend_mm_pemalloc, |
|
mysqlnd_zend_mm_ecalloc, |
|
mysqlnd_zend_mm_pecalloc, |
|
mysqlnd_zend_mm_erealloc, |
|
mysqlnd_zend_mm_perealloc, |
|
mysqlnd_zend_mm_efree, |
|
mysqlnd_zend_mm_pefree, |
|
mysqlnd_zend_mm_malloc, |
|
mysqlnd_zend_mm_calloc, |
|
mysqlnd_zend_mm_realloc, |
|
mysqlnd_zend_mm_free, |
|
mysqlnd_zend_mm_pestrndup, |
|
mysqlnd_zend_mm_pestrdup |
|
#endif |
|
}; |
}; |
|
|
|
|
| /* {{{ mysqlnd_debug_trace_plugin_register */ |
/* Follows code borrowed from zend_builtin_functions.c because the functions there are static */ | void |
| mysqlnd_debug_trace_plugin_register(TSRMLS_D) |
#if MYSQLND_UNICODE | |
/* {{{ gettraceasstring() macros */ | |
#define TRACE_APPEND_CHR(chr) \ | |
*str = (char*)erealloc(*str, *len + 1 + 1); \ | |
(*str)[(*len)++] = chr | |
| |
#define TRACE_APPEND_STRL(val, vallen) \ | |
{ \ | |
int l = vallen; \ | |
*str = (char*)erealloc(*str, *len + l + 1); \ | |
memcpy((*str) + *len, val, l); \ | |
*len += l; \ | |
} | |
| |
#define TRACE_APPEND_USTRL(val, vallen) \ | |
{ \ | |
zval tmp, copy; \ | |
int use_copy; \ | |
ZVAL_UNICODEL(&tmp, val, vallen, 1); \ | |
zend_make_printable_zval(&tmp, ©, &use_copy); \ | |
TRACE_APPEND_STRL(Z_STRVAL(copy), Z_STRLEN(copy)); \ | |
zval_dtor(©); \ | |
zval_dtor(&tmp); \ | |
} | |
| |
#define TRACE_APPEND_ZVAL(zv) \ | |
if (Z_TYPE_P((zv)) == IS_UNICODE) { \ | |
zval copy; \ | |
int use_copy; \ | |
zend_make_printable_zval((zv), ©, &use_copy); \ | |
TRACE_APPEND_STRL(Z_STRVAL(copy), Z_STRLEN(copy)); \ | |
zval_dtor(©); \ | |
} else { \ | |
TRACE_APPEND_STRL(Z_STRVAL_P((zv)), Z_STRLEN_P((zv))); \ | |
} | |
| |
#define TRACE_APPEND_STR(val) \ | |
TRACE_APPEND_STRL(val, sizeof(val)-1) | |
| |
#define TRACE_APPEND_KEY(key) \ | |
if (zend_ascii_hash_find(ht, key, sizeof(key), (void**)&tmp) == SUCCESS) { \ | |
if (Z_TYPE_PP(tmp) == IS_UNICODE) { \ | |
zval copy; \ | |
int use_copy; \ | |
zend_make_printable_zval(*tmp, ©, &use_copy); \ | |
TRACE_APPEND_STRL(Z_STRVAL(copy), Z_STRLEN(copy)); \ | |
zval_dtor(©); \ | |
} else { \ | |
TRACE_APPEND_STRL(Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp)); \ | |
} \ | |
} | |
/* }}} */ | |
| |
/* {{{ mysqlnd_build_trace_args */ | |
static int mysqlnd_build_trace_args(zval **arg TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) | |
{ |
{ |
char **str; | mysqlnd_plugin_register_ex((struct st_mysqlnd_plugin_header *) &mysqlnd_plugin_trace_log_plugin TSRMLS_CC); |
int *len; | |
| |
str = va_arg(args, char**); | |
len = va_arg(args, int*); | |
| |
/* the trivial way would be to do: | |
* conver_to_string_ex(arg); | |
* append it and kill the now tmp arg. | |
* but that could cause some E_NOTICE and also damn long lines. | |
*/ | |
| |
switch (Z_TYPE_PP(arg)) { | |
case IS_NULL: | |
TRACE_APPEND_STR("NULL, "); | |
break; | |
case IS_STRING: { | |
int l_added; | |
TRACE_APPEND_CHR('\''); | |
if (Z_STRLEN_PP(arg) > 15) { | |
TRACE_APPEND_STRL(Z_STRVAL_PP(arg), 15); | |
TRACE_APPEND_STR("...', "); | |
l_added = 15 + 6 + 1; /* +1 because of while (--l_added) */ | |
} else { | |
l_added = Z_STRLEN_PP(arg); | |
TRACE_APPEND_STRL(Z_STRVAL_PP(arg), l_added); | |
TRACE_APPEND_STR("', "); | |
l_added += 3 + 1; | |
} | |
while (--l_added) { | |
if ((unsigned char)(*str)[*len - l_added] < 32) { | |
(*str)[*len - l_added] = '?'; | |
} | |
} | |
break; | |
} | |
case IS_UNICODE: { | |
int l_added; | |
| |
/* | |
* We do not want to apply current error mode here, since | |
* zend_make_printable_zval() uses output encoding converter. | |
* Temporarily set output encoding converter to escape offending | |
* chars with \uXXXX notation. | |
*/ | |
zend_set_converter_error_mode(ZEND_U_CONVERTER(UG(output_encoding_conv)), ZEND_FROM_UNICODE, ZEND_CONV_ERROR_ESCAPE_JAVA); | |
TRACE_APPEND_CHR('\''); | |
if (Z_USTRLEN_PP(arg) > 15) { | |
TRACE_APPEND_USTRL(Z_USTRVAL_PP(arg), 15); | |
TRACE_APPEND_STR("...', "); | |
l_added = 15 + 6 + 1; /* +1 because of while (--l_added) */ | |
} else { | |
l_added = Z_USTRLEN_PP(arg); | |
TRACE_APPEND_USTRL(Z_USTRVAL_PP(arg), l_added); | |
TRACE_APPEND_STR("', "); | |
l_added += 3 + 1; | |
} | |
/* | |
* Reset output encoding converter error mode. | |
*/ | |
zend_set_converter_error_mode(ZEND_U_CONVERTER(UG(output_encoding_conv)), ZEND_FROM_UNICODE, UG(from_error_mode)); | |
while (--l_added) { | |
if ((unsigned char)(*str)[*len - l_added] < 32) { | |
(*str)[*len - l_added] = '?'; | |
} | |
} | |
break; | |
} | |
case IS_BOOL: | |
if (Z_LVAL_PP(arg)) { | |
TRACE_APPEND_STR("true, "); | |
} else { | |
TRACE_APPEND_STR("false, "); | |
} | |
break; | |
case IS_RESOURCE: | |
TRACE_APPEND_STR("Resource id #"); | |
/* break; */ | |
case IS_LONG: { | |
long lval = Z_LVAL_PP(arg); | |
char s_tmp[MAX_LENGTH_OF_LONG + 1]; | |
int l_tmp = zend_sprintf(s_tmp, "%ld", lval); /* SAFE */ | |
TRACE_APPEND_STRL(s_tmp, l_tmp); | |
TRACE_APPEND_STR(", "); | |
break; | |
} | |
case IS_DOUBLE: { | |
double dval = Z_DVAL_PP(arg); | |
char *s_tmp; | |
int l_tmp; | |
| |
s_tmp = emalloc(MAX_LENGTH_OF_DOUBLE + EG(precision) + 1); | |
l_tmp = zend_sprintf(s_tmp, "%.*G", (int) EG(precision), dval); /* SAFE */ | |
TRACE_APPEND_STRL(s_tmp, l_tmp); | |
/* %G already handles removing trailing zeros from the fractional part, yay */ | |
efree(s_tmp); | |
TRACE_APPEND_STR(", "); | |
break; | |
} | |
case IS_ARRAY: | |
TRACE_APPEND_STR("Array, "); | |
break; | |
case IS_OBJECT: { | |
zval tmp; | |
zstr class_name; | |
zend_uint class_name_len; | |
int dup; | |
| |
TRACE_APPEND_STR("Object("); | |
| |
dup = zend_get_object_classname(*arg, &class_name, &class_name_len TSRMLS_CC); | |
| |
ZVAL_UNICODEL(&tmp, class_name.u, class_name_len, 1); | |
convert_to_string_with_converter(&tmp, ZEND_U_CONVERTER(UG(output_encoding_conv))); | |
TRACE_APPEND_STRL(Z_STRVAL(tmp), Z_STRLEN(tmp)); | |
zval_dtor(&tmp); | |
| |
if(!dup) { | |
efree(class_name.v); | |
} | |
| |
TRACE_APPEND_STR("), "); | |
break; | |
} | |
default: | |
break; | |
} | |
return ZEND_HASH_APPLY_KEEP; | |
} |
} |
/* }}} */ |
/* }}} */ |
|
|
|
|
static int mysqlnd_build_trace_string(zval **frame TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) /* {{{ */ |
|
{ |
|
char *s_tmp, **str; |
|
int *len, *num; |
|
long line; |
|
HashTable *ht = Z_ARRVAL_PP(frame); |
|
zval **file, **tmp; |
|
uint * level; |
|
|
|
level = va_arg(args, uint *); |
|
str = va_arg(args, char**); |
|
len = va_arg(args, int*); |
|
num = va_arg(args, int*); |
|
|
|
if (!*level) { |
|
return ZEND_HASH_APPLY_KEEP; |
|
} |
|
--*level; |
|
|
|
s_tmp = emalloc(1 + MAX_LENGTH_OF_LONG + 1 + 1); |
|
sprintf(s_tmp, "#%d ", (*num)++); |
|
TRACE_APPEND_STRL(s_tmp, strlen(s_tmp)); |
|
efree(s_tmp); |
|
if (zend_ascii_hash_find(ht, "file", sizeof("file"), (void**)&file) == SUCCESS) { |
|
if (zend_ascii_hash_find(ht, "line", sizeof("line"), (void**)&tmp) == SUCCESS) { |
|
line = Z_LVAL_PP(tmp); |
|
} else { |
|
line = 0; |
|
} |
|
TRACE_APPEND_ZVAL(*file); |
|
s_tmp = emalloc(MAX_LENGTH_OF_LONG + 2 + 1); |
|
sprintf(s_tmp, "(%ld): ", line); |
|
TRACE_APPEND_STRL(s_tmp, strlen(s_tmp)); |
|
efree(s_tmp); |
|
} else { |
|
TRACE_APPEND_STR("[internal function]: "); |
|
} |
|
TRACE_APPEND_KEY("class"); |
|
TRACE_APPEND_KEY("type"); |
|
TRACE_APPEND_KEY("function"); |
|
TRACE_APPEND_CHR('('); |
|
if (zend_ascii_hash_find(ht, "args", sizeof("args"), (void**)&tmp) == SUCCESS) { |
|
int last_len = *len; |
|
zend_hash_apply_with_arguments(Z_ARRVAL_PP(tmp) TSRMLS_CC, (apply_func_args_t)mysqlnd_build_trace_args, 2, str, len); |
|
if (last_len != *len) { |
|
*len -= 2; /* remove last ', ' */ |
|
} |
|
} |
|
TRACE_APPEND_STR(")\n"); |
|
return ZEND_HASH_APPLY_KEEP; |
|
} |
|
/* }}} */ |
|
|
|
|
|
#else /* PHP 5*/ |
|
|
|
|
|
/* {{{ gettraceasstring() macros */ |
|
#define TRACE_APPEND_CHR(chr) \ |
|
*str = (char*)erealloc(*str, *len + 1 + 1); \ |
|
(*str)[(*len)++] = chr |
|
|
|
#define TRACE_APPEND_STRL(val, vallen) \ |
|
{ \ |
|
int l = vallen; \ |
|
*str = (char*)erealloc(*str, *len + l + 1); \ |
|
memcpy((*str) + *len, val, l); \ |
|
*len += l; \ |
|
} |
|
|
|
#define TRACE_APPEND_STR(val) \ |
|
TRACE_APPEND_STRL(val, sizeof(val)-1) |
|
|
|
#define TRACE_APPEND_KEY(key) \ |
|
if (zend_hash_find(ht, key, sizeof(key), (void**)&tmp) == SUCCESS) { \ |
|
TRACE_APPEND_STRL(Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp)); \ |
|
} |
|
|
|
/* }}} */ |
|
|
|
|
|
static int mysqlnd_build_trace_args(zval **arg TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) /* {{{ */ |
|
{ |
|
char **str; |
|
int *len; |
|
|
|
str = va_arg(args, char**); |
|
len = va_arg(args, int*); |
|
|
|
/* the trivial way would be to do: |
|
* conver_to_string_ex(arg); |
|
* append it and kill the now tmp arg. |
|
* but that could cause some E_NOTICE and also damn long lines. |
|
*/ |
|
|
|
switch (Z_TYPE_PP(arg)) { |
|
case IS_NULL: |
|
TRACE_APPEND_STR("NULL, "); |
|
break; |
|
case IS_STRING: { |
|
int l_added; |
|
TRACE_APPEND_CHR('\''); |
|
if (Z_STRLEN_PP(arg) > 15) { |
|
TRACE_APPEND_STRL(Z_STRVAL_PP(arg), 15); |
|
TRACE_APPEND_STR("...', "); |
|
l_added = 15 + 6 + 1; /* +1 because of while (--l_added) */ |
|
} else { |
|
l_added = Z_STRLEN_PP(arg); |
|
TRACE_APPEND_STRL(Z_STRVAL_PP(arg), l_added); |
|
TRACE_APPEND_STR("', "); |
|
l_added += 3 + 1; |
|
} |
|
while (--l_added) { |
|
if ((*str)[*len - l_added] < 32) { |
|
(*str)[*len - l_added] = '?'; |
|
} |
|
} |
|
break; |
|
} |
|
case IS_BOOL: |
|
if (Z_LVAL_PP(arg)) { |
|
TRACE_APPEND_STR("true, "); |
|
} else { |
|
TRACE_APPEND_STR("false, "); |
|
} |
|
break; |
|
case IS_RESOURCE: |
|
TRACE_APPEND_STR("Resource id #"); |
|
/* break; */ |
|
case IS_LONG: { |
|
long lval = Z_LVAL_PP(arg); |
|
char s_tmp[MAX_LENGTH_OF_LONG + 1]; |
|
int l_tmp = zend_sprintf(s_tmp, "%ld", lval); /* SAFE */ |
|
TRACE_APPEND_STRL(s_tmp, l_tmp); |
|
TRACE_APPEND_STR(", "); |
|
break; |
|
} |
|
case IS_DOUBLE: { |
|
double dval = Z_DVAL_PP(arg); |
|
char *s_tmp; |
|
int l_tmp; |
|
|
|
s_tmp = emalloc(MAX_LENGTH_OF_DOUBLE + EG(precision) + 1); |
|
l_tmp = zend_sprintf(s_tmp, "%.*G", (int) EG(precision), dval); /* SAFE */ |
|
TRACE_APPEND_STRL(s_tmp, l_tmp); |
|
/* %G already handles removing trailing zeros from the fractional part, yay */ |
|
efree(s_tmp); |
|
TRACE_APPEND_STR(", "); |
|
break; |
|
} |
|
case IS_ARRAY: |
|
TRACE_APPEND_STR("Array, "); |
|
break; |
|
case IS_OBJECT: { |
|
char *class_name; |
|
zend_uint class_name_len; |
|
int dupl; |
|
|
|
TRACE_APPEND_STR("Object("); |
|
|
|
dupl = zend_get_object_classname(*arg, &class_name, &class_name_len TSRMLS_CC); |
|
|
|
TRACE_APPEND_STRL(class_name, class_name_len); |
|
if (!dupl) { |
|
efree(class_name); |
|
} |
|
|
|
TRACE_APPEND_STR("), "); |
|
break; |
|
} |
|
default: |
|
break; |
|
} |
|
return ZEND_HASH_APPLY_KEEP; |
|
} |
|
/* }}} */ |
|
|
|
static int mysqlnd_build_trace_string(zval **frame TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) /* {{{ */ |
|
{ |
|
char *s_tmp, **str; |
|
int *len, *num; |
|
long line; |
|
HashTable *ht = Z_ARRVAL_PP(frame); |
|
zval **file, **tmp; |
|
uint * level; |
|
|
|
level = va_arg(args, uint *); |
|
str = va_arg(args, char**); |
|
len = va_arg(args, int*); |
|
num = va_arg(args, int*); |
|
|
|
if (!*level) { |
|
return ZEND_HASH_APPLY_KEEP; |
|
} |
|
--*level; |
|
|
|
s_tmp = emalloc(1 + MAX_LENGTH_OF_LONG + 1 + 1); |
|
sprintf(s_tmp, "#%d ", (*num)++); |
|
TRACE_APPEND_STRL(s_tmp, strlen(s_tmp)); |
|
efree(s_tmp); |
|
if (zend_hash_find(ht, "file", sizeof("file"), (void**)&file) == SUCCESS) { |
|
if (zend_hash_find(ht, "line", sizeof("line"), (void**)&tmp) == SUCCESS) { |
|
line = Z_LVAL_PP(tmp); |
|
} else { |
|
line = 0; |
|
} |
|
s_tmp = emalloc(Z_STRLEN_PP(file) + MAX_LENGTH_OF_LONG + 4 + 1); |
|
sprintf(s_tmp, "%s(%ld): ", Z_STRVAL_PP(file), line); |
|
TRACE_APPEND_STRL(s_tmp, strlen(s_tmp)); |
|
efree(s_tmp); |
|
} else { |
|
TRACE_APPEND_STR("[internal function]: "); |
|
} |
|
TRACE_APPEND_KEY("class"); |
|
TRACE_APPEND_KEY("type"); |
|
TRACE_APPEND_KEY("function"); |
|
TRACE_APPEND_CHR('('); |
|
if (zend_hash_find(ht, "args", sizeof("args"), (void**)&tmp) == SUCCESS) { |
|
int last_len = *len; |
|
zend_hash_apply_with_arguments(Z_ARRVAL_PP(tmp) TSRMLS_CC, (apply_func_args_t)mysqlnd_build_trace_args, 2, str, len); |
|
if (last_len != *len) { |
|
*len -= 2; /* remove last ', ' */ |
|
} |
|
} |
|
TRACE_APPEND_STR(")\n"); |
|
return ZEND_HASH_APPLY_KEEP; |
|
} |
|
/* }}} */ |
|
#endif |
|
|
|
|
|
PHPAPI char * mysqlnd_get_backtrace(uint max_levels, size_t * length TSRMLS_DC) |
|
{ |
|
zval *trace; |
|
char *res = estrdup(""), **str = &res, *s_tmp; |
|
int res_len = 0, *len = &res_len, num = 0; |
|
if (max_levels == 0) { |
|
max_levels = 99999; |
|
} |
|
|
|
MAKE_STD_ZVAL(trace); |
|
zend_fetch_debug_backtrace(trace, 0, 0 TSRMLS_CC); |
|
|
|
zend_hash_apply_with_arguments(Z_ARRVAL_P(trace) TSRMLS_CC, (apply_func_args_t)mysqlnd_build_trace_string, 4, &max_levels, str, len, &num); |
|
zval_ptr_dtor(&trace); |
|
|
|
if (max_levels) { |
|
s_tmp = emalloc(1 + MAX_LENGTH_OF_LONG + 7 + 1); |
|
sprintf(s_tmp, "#%d {main}", num); |
|
TRACE_APPEND_STRL(s_tmp, strlen(s_tmp)); |
|
efree(s_tmp); |
|
} |
|
|
|
res[res_len] = '\0'; |
|
*length = res_len; |
|
|
|
return res; |
|
} |
|
|
|
/* |
/* |
* Local variables: |
* Local variables: |