PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LCOV - code coverage report
Current view: top level - ext/mysqlnd - mysqlnd_debug.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 228 662 34.4 %
Date: 2014-04-08 Functions: 16 27 59.3 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :   +----------------------------------------------------------------------+
       3             :   | PHP Version 5                                                        |
       4             :   +----------------------------------------------------------------------+
       5             :   | Copyright (c) 2006-2013 The PHP Group                                |
       6             :   +----------------------------------------------------------------------+
       7             :   | This source file is subject to version 3.01 of the PHP license,      |
       8             :   | that is bundled with this package in the file LICENSE, and is        |
       9             :   | available through the world-wide-web at the following url:           |
      10             :   | http://www.php.net/license/3_01.txt                                  |
      11             :   | If you did not receive a copy of the PHP license and are unable to   |
      12             :   | obtain it through the world-wide-web, please send a note to          |
      13             :   | license@php.net so we can mail you a copy immediately.               |
      14             :   +----------------------------------------------------------------------+
      15             :   | Authors: Georg Richter <georg@mysql.com>                             |
      16             :   |          Andrey Hristov <andrey@mysql.com>                           |
      17             :   |          Ulf Wendel <uwendel@mysql.com>                              |
      18             :   +----------------------------------------------------------------------+
      19             : */
      20             : 
      21             : /* $Id$ */
      22             : 
      23             : #include "php.h"
      24             : #include "mysqlnd.h"
      25             : #include "mysqlnd_priv.h"
      26             : #include "mysqlnd_debug.h"
      27             : #include "mysqlnd_wireprotocol.h"
      28             : #include "mysqlnd_statistics.h"
      29             : #include "zend_builtin_functions.h"
      30             : 
      31             : static const char * const mysqlnd_debug_default_trace_file = "/tmp/mysqlnd.trace";
      32             : 
      33             : #ifdef ZTS 
      34             : #define MYSQLND_ZTS(self) TSRMLS_D = (self)->TSRMLS_C
      35             : #else
      36             : #define MYSQLND_ZTS(self)
      37             : #endif
      38             : 
      39             : static const char mysqlnd_emalloc_name[]        = "_mysqlnd_emalloc";
      40             : static const char mysqlnd_pemalloc_name[]       = "_mysqlnd_pemalloc";
      41             : static const char mysqlnd_ecalloc_name[]        = "_mysqlnd_ecalloc";
      42             : static const char mysqlnd_pecalloc_name[]       = "_mysqlnd_pecalloc";
      43             : static const char mysqlnd_erealloc_name[]       = "_mysqlnd_erealloc";
      44             : static const char mysqlnd_perealloc_name[]      = "_mysqlnd_perealloc";
      45             : static const char mysqlnd_efree_name[]          = "_mysqlnd_efree";
      46             : static const char mysqlnd_pefree_name[]         = "_mysqlnd_pefree";
      47             : static const char mysqlnd_malloc_name[]         = "_mysqlnd_malloc";
      48             : static const char mysqlnd_calloc_name[]         = "_mysqlnd_calloc";
      49             : static const char mysqlnd_realloc_name[]        = "_mysqlnd_realloc";
      50             : static const char mysqlnd_free_name[]           = "_mysqlnd_free";
      51             : static const char mysqlnd_pestrndup_name[]      = "_mysqlnd_pestrndup";
      52             : static const char mysqlnd_pestrdup_name[]       = "_mysqlnd_pestrdup";
      53             : 
      54             : const char * mysqlnd_debug_std_no_trace_funcs[] =
      55             : {
      56             :         mysqlnd_emalloc_name,
      57             :         mysqlnd_ecalloc_name,
      58             :         mysqlnd_efree_name,
      59             :         mysqlnd_erealloc_name,
      60             :         mysqlnd_pemalloc_name,
      61             :         mysqlnd_pecalloc_name,
      62             :         mysqlnd_pefree_name,
      63             :         mysqlnd_perealloc_name,
      64             :         mysqlnd_malloc_name,
      65             :         mysqlnd_calloc_name,
      66             :         mysqlnd_realloc_name,
      67             :         mysqlnd_free_name,
      68             :         mysqlnd_pestrndup_name,
      69             :         mysqlnd_read_header_name,
      70             :         mysqlnd_read_body_name,
      71             :         NULL /* must be always last */
      72             : };
      73             : 
      74             : 
      75             : /* {{{ mysqlnd_debug::open */
      76             : static enum_func_status
      77           0 : MYSQLND_METHOD(mysqlnd_debug, open)(MYSQLND_DEBUG * self, zend_bool reopen)
      78             : {
      79             :         MYSQLND_ZTS(self);
      80             : 
      81           0 :         if (!self->file_name) {
      82           0 :                 return FAIL;
      83             :         }
      84             : 
      85           0 :         self->stream = php_stream_open_wrapper(self->file_name,
      86             :                                                                                    reopen == TRUE || self->flags & MYSQLND_DEBUG_APPEND? "ab":"wb",
      87             :                                                                                    REPORT_ERRORS, NULL);
      88           0 :         return self->stream? PASS:FAIL;
      89             : }
      90             : /* }}} */
      91             : 
      92             : 
      93             : /* {{{ mysqlnd_debug::log */
      94             : static enum_func_status
      95           0 : MYSQLND_METHOD(mysqlnd_debug, log)(MYSQLND_DEBUG * self,
      96             :                                                                    unsigned int line, const char * const file,
      97             :                                                                    unsigned int level, const char * type, const char * message)
      98             : {
      99             :         char pipe_buffer[512];
     100             :         enum_func_status ret;
     101             :         int i;
     102             :         char * message_line;
     103             :         unsigned int message_line_len;
     104           0 :         unsigned int flags = self->flags;
     105             :         char pid_buffer[10], time_buffer[30], file_buffer[200],
     106             :                  line_buffer[6], level_buffer[7];
     107             :         MYSQLND_ZTS(self);
     108             : 
     109           0 :         if (!self->stream && FAIL == self->m->open(self, FALSE)) {
     110           0 :                 return FAIL;
     111             :         }
     112             : 
     113           0 :         if (level == -1) {
     114           0 :                 level = zend_stack_count(&self->call_stack);
     115             :         }
     116           0 :         i = MIN(level, sizeof(pipe_buffer) / 2  - 1);
     117           0 :         pipe_buffer[i*2] = '\0';
     118           0 :         for (;i > 0;i--) {
     119           0 :                 pipe_buffer[i*2 - 1] = ' ';
     120           0 :                 pipe_buffer[i*2 - 2] = '|';
     121             :         }
     122             : 
     123             : 
     124           0 :         if (flags & MYSQLND_DEBUG_DUMP_PID) {
     125           0 :                 snprintf(pid_buffer, sizeof(pid_buffer) - 1, "%5u: ", self->pid);
     126           0 :                 pid_buffer[sizeof(pid_buffer) - 1 ] = '\0';
     127             :         }
     128           0 :         if (flags & MYSQLND_DEBUG_DUMP_TIME) {
     129             :                 /* The following from FF's DBUG library, which is in the public domain */
     130             : #if defined(PHP_WIN32)
     131             :                 /* FIXME This doesn't give microseconds as in Unix case, and the resolution is
     132             :                 in system ticks, 10 ms intervals. See my_getsystime.c for high res */
     133             :                 SYSTEMTIME loc_t;
     134             :                 GetLocalTime(&loc_t);
     135             :                 snprintf(time_buffer, sizeof(time_buffer) - 1,
     136             :                                  /* "%04d-%02d-%02d " */
     137             :                                  "%02d:%02d:%02d.%06d ",
     138             :                                  /*tm_p->tm_year + 1900, tm_p->tm_mon + 1, tm_p->tm_mday,*/
     139             :                                  loc_t.wHour, loc_t.wMinute, loc_t.wSecond, loc_t.wMilliseconds);
     140             :                 time_buffer[sizeof(time_buffer) - 1 ] = '\0';
     141             : #else
     142             :                 struct timeval tv;
     143             :                 struct tm *tm_p;
     144           0 :                 if (gettimeofday(&tv, NULL) != -1) {
     145           0 :                         if ((tm_p= localtime((const time_t *)&tv.tv_sec))) {
     146           0 :                                 snprintf(time_buffer, sizeof(time_buffer) - 1,
     147             :                                                  /* "%04d-%02d-%02d " */
     148             :                                                  "%02d:%02d:%02d.%06d ",
     149             :                                                  /*tm_p->tm_year + 1900, tm_p->tm_mon + 1, tm_p->tm_mday,*/
     150             :                                                  tm_p->tm_hour, tm_p->tm_min, tm_p->tm_sec,
     151           0 :                                                  (int) (tv.tv_usec));
     152           0 :                                 time_buffer[sizeof(time_buffer) - 1 ] = '\0';
     153             :                         }
     154             :                 }
     155             : #endif
     156             :         }
     157           0 :         if (flags & MYSQLND_DEBUG_DUMP_FILE) {
     158           0 :                 snprintf(file_buffer, sizeof(file_buffer) - 1, "%14s: ", file);
     159           0 :                 file_buffer[sizeof(file_buffer) - 1 ] = '\0';
     160             :         }
     161           0 :         if (flags & MYSQLND_DEBUG_DUMP_LINE) {
     162           0 :                 snprintf(line_buffer, sizeof(line_buffer) - 1, "%5u: ", line);
     163           0 :                 line_buffer[sizeof(line_buffer) - 1 ] = '\0';
     164             :         }
     165           0 :         if (flags & MYSQLND_DEBUG_DUMP_LEVEL) {
     166           0 :                 snprintf(level_buffer, sizeof(level_buffer) - 1, "%4u: ", level);
     167           0 :                 level_buffer[sizeof(level_buffer) - 1 ] = '\0';
     168             :         }
     169             : 
     170           0 :         message_line_len = spprintf(&message_line, 0, "%s%s%s%s%s%s%s%s\n",
     171           0 :                                                                 flags & MYSQLND_DEBUG_DUMP_PID? pid_buffer:"",
     172           0 :                                                                 flags & MYSQLND_DEBUG_DUMP_TIME? time_buffer:"",
     173           0 :                                                                 flags & MYSQLND_DEBUG_DUMP_FILE? file_buffer:"",
     174           0 :                                                                 flags & MYSQLND_DEBUG_DUMP_LINE? line_buffer:"",
     175           0 :                                                                 flags & MYSQLND_DEBUG_DUMP_LEVEL? level_buffer:"",
     176             :                                                                 pipe_buffer, type? type:"", message);
     177             : 
     178           0 :         ret = php_stream_write(self->stream, message_line, message_line_len)? PASS:FAIL;
     179           0 :         efree(message_line); /* allocated by spprintf */
     180           0 :         if (flags & MYSQLND_DEBUG_FLUSH) {
     181           0 :                 self->m->close(self);
     182           0 :                 self->m->open(self, TRUE);
     183             :         }
     184           0 :         return ret;
     185             : }
     186             : /* }}} */
     187             : 
     188             : 
     189             : /* {{{ mysqlnd_debug::log_va */
     190             : static enum_func_status
     191           0 : MYSQLND_METHOD(mysqlnd_debug, log_va)(MYSQLND_DEBUG *self,
     192             :                                                                           unsigned int line, const char * const file,
     193             :                                                                           unsigned int level, const char * type,
     194             :                                                                           const char *format, ...)
     195             : {
     196             :         char pipe_buffer[512];
     197             :         int i;
     198             :         enum_func_status ret;
     199             :         char * message_line, *buffer;
     200             :         unsigned int message_line_len;
     201             :         va_list args;
     202           0 :         unsigned int flags = self->flags;
     203             :         char pid_buffer[10], time_buffer[30], file_buffer[200],
     204             :                  line_buffer[6], level_buffer[7];
     205             :         MYSQLND_ZTS(self);
     206             : 
     207           0 :         if (!self->stream && FAIL == self->m->open(self, FALSE)) {
     208           0 :                 return FAIL;
     209             :         }
     210             : 
     211           0 :         if (level == -1) {
     212           0 :                 level = zend_stack_count(&self->call_stack);
     213             :         }
     214           0 :         i = MIN(level, sizeof(pipe_buffer) / 2  - 1);
     215           0 :         pipe_buffer[i*2] = '\0';
     216           0 :         for (;i > 0;i--) {
     217           0 :                 pipe_buffer[i*2 - 1] = ' ';
     218           0 :                 pipe_buffer[i*2 - 2] = '|';
     219             :         }
     220             : 
     221             : 
     222           0 :         if (flags & MYSQLND_DEBUG_DUMP_PID) {
     223           0 :                 snprintf(pid_buffer, sizeof(pid_buffer) - 1, "%5u: ", self->pid);
     224           0 :                 pid_buffer[sizeof(pid_buffer) - 1 ] = '\0';
     225             :         }
     226           0 :         if (flags & MYSQLND_DEBUG_DUMP_TIME) {
     227             :                 /* The following from FF's DBUG library, which is in the public domain */
     228             : #if defined(PHP_WIN32)
     229             :                 /* FIXME This doesn't give microseconds as in Unix case, and the resolution is
     230             :                 in system ticks, 10 ms intervals. See my_getsystime.c for high res */
     231             :                 SYSTEMTIME loc_t;
     232             :                 GetLocalTime(&loc_t);
     233             :                 snprintf(time_buffer, sizeof(time_buffer) - 1,
     234             :                                  /* "%04d-%02d-%02d " */
     235             :                                  "%02d:%02d:%02d.%06d ",
     236             :                                  /*tm_p->tm_year + 1900, tm_p->tm_mon + 1, tm_p->tm_mday,*/
     237             :                                  loc_t.wHour, loc_t.wMinute, loc_t.wSecond, loc_t.wMilliseconds);
     238             :                 time_buffer[sizeof(time_buffer) - 1 ] = '\0';
     239             : #else
     240             :                 struct timeval tv;
     241             :                 struct tm *tm_p;
     242           0 :                 if (gettimeofday(&tv, NULL) != -1) {
     243           0 :                         if ((tm_p= localtime((const time_t *)&tv.tv_sec))) {
     244           0 :                                 snprintf(time_buffer, sizeof(time_buffer) - 1,
     245             :                                                  /* "%04d-%02d-%02d " */
     246             :                                                  "%02d:%02d:%02d.%06d ",
     247             :                                                  /*tm_p->tm_year + 1900, tm_p->tm_mon + 1, tm_p->tm_mday,*/
     248             :                                                  tm_p->tm_hour, tm_p->tm_min, tm_p->tm_sec,
     249           0 :                                                  (int) (tv.tv_usec));
     250           0 :                                 time_buffer[sizeof(time_buffer) - 1 ] = '\0';
     251             :                         }
     252             :                 }
     253             : #endif
     254             :         }
     255           0 :         if (flags & MYSQLND_DEBUG_DUMP_FILE) {
     256           0 :                 snprintf(file_buffer, sizeof(file_buffer) - 1, "%14s: ", file);
     257           0 :                 file_buffer[sizeof(file_buffer) - 1 ] = '\0';
     258             :         }
     259           0 :         if (flags & MYSQLND_DEBUG_DUMP_LINE) {
     260           0 :                 snprintf(line_buffer, sizeof(line_buffer) - 1, "%5u: ", line);
     261           0 :                 line_buffer[sizeof(line_buffer) - 1 ] = '\0';
     262             :         }
     263           0 :         if (flags & MYSQLND_DEBUG_DUMP_LEVEL) {
     264           0 :                 snprintf(level_buffer, sizeof(level_buffer) - 1, "%4u: ", level);
     265           0 :                 level_buffer[sizeof(level_buffer) - 1 ] = '\0';
     266             :         }
     267             : 
     268             : 
     269           0 :         va_start(args, format);
     270           0 :         vspprintf(&buffer, 0, format, args);
     271           0 :         va_end(args);
     272             : 
     273           0 :         message_line_len = spprintf(&message_line, 0, "%s%s%s%s%s%s%s%s\n",
     274           0 :                                                                 flags & MYSQLND_DEBUG_DUMP_PID? pid_buffer:"",
     275           0 :                                                                 flags & MYSQLND_DEBUG_DUMP_TIME? time_buffer:"",
     276           0 :                                                                 flags & MYSQLND_DEBUG_DUMP_FILE? file_buffer:"",
     277           0 :                                                                 flags & MYSQLND_DEBUG_DUMP_LINE? line_buffer:"",
     278           0 :                                                                 flags & MYSQLND_DEBUG_DUMP_LEVEL? level_buffer:"",
     279             :                                                                 pipe_buffer, type? type:"", buffer);
     280           0 :         efree(buffer);
     281           0 :         ret = php_stream_write(self->stream, message_line, message_line_len)? PASS:FAIL;
     282           0 :         efree(message_line); /* allocated by spprintf */
     283             : 
     284           0 :         if (flags & MYSQLND_DEBUG_FLUSH) {
     285           0 :                 self->m->close(self);
     286           0 :                 self->m->open(self, TRUE);
     287             :         }
     288           0 :         return ret;
     289             : }
     290             : /* }}} */
     291             : 
     292             : 
     293             : /* FALSE - The DBG_ calls won't be traced, TRUE - will be traced */
     294             : /* {{{ mysqlnd_debug::func_enter */
     295             : static zend_bool
     296           0 : MYSQLND_METHOD(mysqlnd_debug, func_enter)(MYSQLND_DEBUG * self,
     297             :                                                                                   unsigned int line, const char * const file,
     298             :                                                                                   const char * const func_name, unsigned int func_name_len)
     299             : {
     300           0 :         if ((self->flags & MYSQLND_DEBUG_DUMP_TRACE) == 0 || self->file_name == NULL) {
     301           0 :                 return FALSE;
     302             :         }
     303           0 :         if ((uint) zend_stack_count(&self->call_stack) >= self->nest_level_limit) {
     304           0 :                 return FALSE;
     305             :         }
     306             : 
     307           0 :         if ((self->flags & MYSQLND_DEBUG_TRACE_MEMORY_CALLS) == 0 && self->skip_functions) {
     308           0 :                 const char ** p = self->skip_functions;
     309           0 :                 while (*p) {
     310           0 :                         if (*p == func_name) {
     311           0 :                                 zend_stack_push(&self->call_stack, "", sizeof(""));
     312             : #ifndef MYSQLND_PROFILING_DISABLED
     313           0 :                                 if (self->flags & MYSQLND_DEBUG_PROFILE_CALLS) {
     314           0 :                                         uint64_t some_time = 0;
     315           0 :                                         zend_stack_push(&self->call_time_stack, &some_time, sizeof(some_time));
     316             :                                 }
     317             : #endif
     318           0 :                                 return FALSE;
     319             :                         }
     320           0 :                         p++;
     321             :                 }
     322             :         }
     323             : 
     324           0 :         zend_stack_push(&self->call_stack, func_name, func_name_len + 1);
     325             : #ifndef MYSQLND_PROFILING_DISABLED
     326           0 :         if (self->flags & MYSQLND_DEBUG_PROFILE_CALLS) {
     327           0 :                 uint64_t some_time = 0;
     328           0 :                 zend_stack_push(&self->call_time_stack, &some_time, sizeof(some_time));
     329             :         }
     330             : #endif
     331             : 
     332           0 :         if (zend_hash_num_elements(&self->not_filtered_functions) &&
     333           0 :                 0 == zend_hash_exists(&self->not_filtered_functions, func_name, strlen(func_name) + 1))
     334             :         {
     335           0 :                 return FALSE;
     336             :         }
     337             : 
     338           0 :         self->m->log_va(self, line, file, zend_stack_count(&self->call_stack) - 1, NULL, ">%s", func_name);
     339           0 :         return TRUE;
     340             : }
     341             : /* }}} */
     342             : 
     343             : #ifndef MYSQLND_PROFILING_DISABLED
     344             : struct st_mysqlnd_dbg_function_profile {
     345             :         uint64_t calls;
     346             :         uint64_t min_own;
     347             :         uint64_t max_own;
     348             :         uint64_t avg_own;
     349             :         uint64_t own_underporm_calls;
     350             :         uint64_t min_in_calls;
     351             :         uint64_t max_in_calls;
     352             :         uint64_t avg_in_calls;
     353             :         uint64_t in_calls_underporm_calls;
     354             :         uint64_t min_total;
     355             :         uint64_t max_total;
     356             :         uint64_t avg_total;     
     357             :         uint64_t total_underporm_calls;
     358             : };
     359             : #define PROFILE_UNDERPERFORM_THRESHOLD 10
     360             : #endif
     361             : 
     362             : /* {{{ mysqlnd_debug::func_leave */
     363             : static enum_func_status
     364           0 : MYSQLND_METHOD(mysqlnd_debug, func_leave)(MYSQLND_DEBUG * self, unsigned int line, const char * const file, uint64_t call_time)
     365             : {
     366             :         char *func_name;
     367           0 :         uint64_t * parent_non_own_time_ptr = NULL, * mine_non_own_time_ptr = NULL;
     368           0 :         uint64_t mine_non_own_time = 0;
     369           0 :         zend_bool profile_calls = self->flags & MYSQLND_DEBUG_PROFILE_CALLS? TRUE:FALSE;
     370             : 
     371           0 :         if ((self->flags & MYSQLND_DEBUG_DUMP_TRACE) == 0 || self->file_name == NULL) {
     372           0 :                 return PASS;
     373             :         }
     374           0 :         if ((uint) zend_stack_count(&self->call_stack) >= self->nest_level_limit) {
     375           0 :                 return PASS;
     376             :         }
     377             : 
     378           0 :         zend_stack_top(&self->call_stack, (void **)&func_name);
     379             : 
     380             : #ifndef MYSQLND_PROFILING_DISABLED
     381           0 :         if (profile_calls) {
     382           0 :                 zend_stack_top(&self->call_time_stack, (void **)&mine_non_own_time_ptr);
     383           0 :                 mine_non_own_time = *mine_non_own_time_ptr;
     384           0 :                 zend_stack_del_top(&self->call_time_stack); /* callee - removing ourselves */
     385             :         }
     386             : #endif
     387             : 
     388           0 :         if (func_name[0] == '\0') {
     389             :                 ; /* don't log that function */
     390           0 :         } else if (!zend_hash_num_elements(&self->not_filtered_functions) ||
     391           0 :                            1 == zend_hash_exists(&self->not_filtered_functions, func_name, strlen(func_name) + 1))
     392             :         {
     393             : #ifndef MYSQLND_PROFILING_DISABLED
     394           0 :                 if (FALSE == profile_calls) {
     395             : #endif
     396           0 :                         self->m->log_va(self, line, file, zend_stack_count(&self->call_stack) - 1, NULL, "<%s", func_name);
     397             : 
     398             : #ifndef MYSQLND_PROFILING_DISABLED
     399             :                 } else {
     400           0 :                         struct st_mysqlnd_dbg_function_profile f_profile_stack = {0};
     401           0 :                         struct st_mysqlnd_dbg_function_profile * f_profile = NULL;
     402           0 :                         uint64_t own_time = call_time - mine_non_own_time;
     403           0 :                         uint func_name_len = strlen(func_name);
     404             : 
     405           0 :                         self->m->log_va(self, line, file, zend_stack_count(&self->call_stack) - 1, NULL, "<%s (total=%u own=%u in_calls=%u)",
     406             :                                                 func_name, (unsigned int) call_time, (unsigned int) own_time, (unsigned int) mine_non_own_time
     407             :                                         );
     408             : 
     409           0 :                         if (SUCCESS == zend_hash_find(&self->function_profiles, func_name, func_name_len + 1, (void **) &f_profile)) {
     410             :                                 /* found */
     411           0 :                                         if (f_profile) {
     412           0 :                                         if (mine_non_own_time < f_profile->min_in_calls) {
     413           0 :                                                 f_profile->min_in_calls = mine_non_own_time;
     414           0 :                                         } else if (mine_non_own_time > f_profile->max_in_calls) {
     415           0 :                                                 f_profile->max_in_calls = mine_non_own_time;
     416             :                                         }
     417           0 :                                         f_profile->avg_in_calls = (f_profile->avg_in_calls * f_profile->calls + mine_non_own_time) / (f_profile->calls + 1);
     418             : 
     419           0 :                                         if (own_time < f_profile->min_own) {
     420           0 :                                                 f_profile->min_own = own_time;
     421           0 :                                         } else if (own_time > f_profile->max_own) {
     422           0 :                                                 f_profile->max_own = own_time;
     423             :                                         }
     424           0 :                                         f_profile->avg_own = (f_profile->avg_own * f_profile->calls + own_time) / (f_profile->calls + 1);
     425             : 
     426           0 :                                         if (call_time < f_profile->min_total) {
     427           0 :                                                 f_profile->min_total = call_time;
     428           0 :                                         } else if (call_time > f_profile->max_total) {
     429           0 :                                                 f_profile->max_total = call_time;
     430             :                                         }
     431           0 :                                         f_profile->avg_total = (f_profile->avg_total * f_profile->calls + call_time) / (f_profile->calls + 1);
     432             : 
     433           0 :                                         ++f_profile->calls;
     434           0 :                                         if (f_profile->calls > PROFILE_UNDERPERFORM_THRESHOLD) {
     435           0 :                                                 if (f_profile->avg_in_calls < mine_non_own_time) {
     436           0 :                                                         f_profile->in_calls_underporm_calls++;
     437             :                                                 }
     438           0 :                                                 if (f_profile->avg_own < own_time) {
     439           0 :                                                         f_profile->own_underporm_calls++;
     440             :                                                 }
     441           0 :                                                 if (f_profile->avg_total < call_time) {
     442           0 :                                                         f_profile->total_underporm_calls++;
     443             :                                                 }
     444             :                                         }
     445             :                                 }
     446             :                         } else {
     447             :                                 /* add */
     448           0 :                                 f_profile = &f_profile_stack;
     449           0 :                                 f_profile->min_in_calls = f_profile->max_in_calls = f_profile->avg_in_calls = mine_non_own_time;
     450           0 :                                 f_profile->min_total = f_profile->max_total = f_profile->avg_total = call_time;
     451           0 :                                 f_profile->min_own = f_profile->max_own = f_profile->avg_own = own_time;
     452           0 :                                 f_profile->calls = 1;
     453           0 :                                 zend_hash_add(&self->function_profiles, func_name, func_name_len+1, f_profile, sizeof(struct st_mysqlnd_dbg_function_profile), NULL);
     454             :                         }
     455           0 :                         if ((uint) zend_stack_count(&self->call_time_stack)) {
     456           0 :                                 uint64_t parent_non_own_time = 0;
     457             : 
     458           0 :                                 zend_stack_top(&self->call_time_stack, (void **)&parent_non_own_time_ptr);
     459           0 :                                 parent_non_own_time = *parent_non_own_time_ptr;
     460           0 :                                 parent_non_own_time += call_time;
     461           0 :                                 zend_stack_del_top(&self->call_time_stack); /* the caller */
     462           0 :                                 zend_stack_push(&self->call_time_stack, &parent_non_own_time, sizeof(parent_non_own_time)); /* add back the caller */
     463             :                         }
     464             :                 }
     465             : #endif
     466             :         }
     467             : 
     468           0 :         return zend_stack_del_top(&self->call_stack) == SUCCESS? PASS:FAIL;
     469             : }
     470             : /* }}} */
     471             : 
     472             : 
     473             : /* {{{ mysqlnd_debug::close */
     474             : static enum_func_status
     475           1 : MYSQLND_METHOD(mysqlnd_debug, close)(MYSQLND_DEBUG * self)
     476             : {
     477             :         MYSQLND_ZTS(self);
     478           1 :         if (self->stream) {
     479             : #ifndef MYSQLND_PROFILING_DISABLED
     480           0 :                 if (!(self->flags & MYSQLND_DEBUG_FLUSH) && (self->flags & MYSQLND_DEBUG_PROFILE_CALLS)) {
     481             :                         struct st_mysqlnd_dbg_function_profile * f_profile;
     482             :                         HashPosition pos_values;
     483             : 
     484           0 :                         self->m->log_va(self, __LINE__, __FILE__, 0, "info : ", 
     485           0 :                                         "number of functions: %d", zend_hash_num_elements(&self->function_profiles));
     486           0 :                         zend_hash_internal_pointer_reset_ex(&self->function_profiles, &pos_values);
     487           0 :                         while (zend_hash_get_current_data_ex(&self->function_profiles, (void **) &f_profile, &pos_values) == SUCCESS) {
     488           0 :                                 char    *string_key = NULL;
     489             :                                 uint    string_key_len;
     490             :                                 ulong   num_key;
     491             : 
     492           0 :                                 zend_hash_get_current_key_ex(&self->function_profiles, &string_key, &string_key_len, &num_key, 0, &pos_values);
     493             : 
     494           0 :                                 self->m->log_va(self, __LINE__, __FILE__, -1, "info : ",
     495             :                                                 "%-40s\tcalls=%5llu  own_slow=%5llu  in_calls_slow=%5llu  total_slow=%5llu"
     496             :                                                 "   min_own=%5llu  max_own=%7llu  avg_own=%7llu   "
     497             :                                                 "   min_in_calls=%5llu  max_in_calls=%7llu  avg_in_calls=%7llu"
     498             :                                                 "   min_total=%5llu  max_total=%7llu  avg_total=%7llu"
     499             :                                                 ,string_key
     500           0 :                                                 ,(uint64_t) f_profile->calls
     501           0 :                                                 ,(uint64_t) f_profile->own_underporm_calls
     502           0 :                                                 ,(uint64_t) f_profile->in_calls_underporm_calls
     503           0 :                                                 ,(uint64_t) f_profile->total_underporm_calls
     504             :                                                 
     505           0 :                                                 ,(uint64_t) f_profile->min_own
     506           0 :                                                 ,(uint64_t) f_profile->max_own
     507           0 :                                                 ,(uint64_t) f_profile->avg_own
     508           0 :                                                 ,(uint64_t) f_profile->min_in_calls
     509           0 :                                                 ,(uint64_t) f_profile->max_in_calls
     510           0 :                                                 ,(uint64_t) f_profile->avg_in_calls
     511           0 :                                                 ,(uint64_t) f_profile->min_total
     512           0 :                                                 ,(uint64_t) f_profile->max_total
     513           0 :                                                 ,(uint64_t) f_profile->avg_total
     514             :                                                 );
     515           0 :                                 zend_hash_move_forward_ex(&self->function_profiles, &pos_values);
     516             :                         }
     517             :                 }
     518             : #endif  
     519             : 
     520           0 :                 php_stream_free(self->stream, PHP_STREAM_FREE_CLOSE);
     521           0 :                 self->stream = NULL;
     522             :         }
     523             :         /* no DBG_RETURN please */
     524           1 :         return PASS;
     525             : }
     526             : /* }}} */
     527             : 
     528             : 
     529             : /* {{{ mysqlnd_res_meta::free */
     530             : static enum_func_status
     531           1 : MYSQLND_METHOD(mysqlnd_debug, free)(MYSQLND_DEBUG * self)
     532             : {
     533           1 :         if (self->file_name && self->file_name != mysqlnd_debug_default_trace_file) {
     534           1 :                 efree(self->file_name);
     535           1 :                 self->file_name = NULL;
     536             :         }
     537           1 :         zend_stack_destroy(&self->call_stack);
     538           1 :         zend_stack_destroy(&self->call_time_stack);
     539           1 :         zend_hash_destroy(&self->not_filtered_functions);
     540           1 :         zend_hash_destroy(&self->function_profiles);
     541           1 :         efree(self);
     542           1 :         return PASS;
     543             : }
     544             : /* }}} */
     545             : 
     546             : enum mysqlnd_debug_parser_state
     547             : {
     548             :         PARSER_WAIT_MODIFIER,
     549             :         PARSER_WAIT_COLON,
     550             :         PARSER_WAIT_VALUE
     551             : };
     552             : 
     553             : 
     554             : /* {{{ mysqlnd_res_meta::set_mode */
     555             : static void
     556           1 : MYSQLND_METHOD(mysqlnd_debug, set_mode)(MYSQLND_DEBUG * self, const char * const mode)
     557             : {
     558           1 :         unsigned int mode_len = strlen(mode), i;
     559           1 :         enum mysqlnd_debug_parser_state state = PARSER_WAIT_MODIFIER;
     560             : 
     561           1 :         self->flags = 0;
     562           1 :         self->nest_level_limit = 0;
     563           1 :         if (self->file_name && self->file_name != mysqlnd_debug_default_trace_file) {
     564           0 :                 efree(self->file_name);
     565           0 :                 self->file_name = NULL;
     566             :         }
     567           1 :         if (zend_hash_num_elements(&self->not_filtered_functions)) {
     568           0 :                 zend_hash_destroy(&self->not_filtered_functions);
     569           0 :                 zend_hash_init(&self->not_filtered_functions, 0, NULL, NULL, 0);
     570             :         }
     571             : 
     572           4 :         for (i = 0; i < mode_len; i++) {
     573           3 :                 switch (mode[i]) {
     574             :                         case 'O':
     575             :                         case 'A':
     576           1 :                                 self->flags |= MYSQLND_DEBUG_FLUSH;
     577             :                         case 'a':
     578             :                         case 'o':
     579           1 :                                 if (mode[i] == 'a' || mode[i] == 'A') {
     580           0 :                                         self->flags |= MYSQLND_DEBUG_APPEND;
     581             :                                 }
     582           2 :                                 if (i + 1 < mode_len && mode[i+1] == ',') {
     583           1 :                                         unsigned int j = i + 2;
     584             : #ifdef PHP_WIN32
     585             :                                         if (i+4 < mode_len && mode[i+3] == ':' && (mode[i+4] == '\\' || mode[i+5] == '/')) {
     586             :                                                 j = i + 5;
     587             :                                         }
     588             : #endif
     589          30 :                                         while (j < mode_len) {
     590          28 :                                                 if (mode[j] == ':') {
     591           0 :                                                         break;
     592             :                                                 }
     593          28 :                                                 j++;
     594             :                                         }
     595           1 :                                         if (j > i + 2) {
     596           1 :                                                 self->file_name = estrndup(mode + i + 2, j - i - 2);
     597             :                                         }
     598           1 :                                         i = j;
     599             :                                 } else {
     600           0 :                                         if (!self->file_name)
     601           0 :                                                 self->file_name = (char *) mysqlnd_debug_default_trace_file;
     602             :                                 }
     603           1 :                                 state = PARSER_WAIT_COLON;
     604           1 :                                 break;
     605             :                         case ':':
     606             : #if 0
     607             :                                 if (state != PARSER_WAIT_COLON) {
     608             :                                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Consecutive semicolons at position %u", i);
     609             :                                 }
     610             : #endif
     611           1 :                                 state = PARSER_WAIT_MODIFIER;
     612           1 :                                 break;
     613             :                         case 'f': /* limit output to these functions */
     614           0 :                                 if (i + 1 < mode_len && mode[i+1] == ',') {
     615           0 :                                         unsigned int j = i + 2;
     616           0 :                                         i++;
     617           0 :                                         while (j < mode_len) {
     618           0 :                                                 if (mode[j] == ':') {
     619             :                                                         /* function names with :: */
     620           0 :                                                         if ((j + 1 < mode_len) && mode[j+1] == ':') {
     621           0 :                                                                 j += 2;
     622           0 :                                                                 continue;
     623             :                                                         }
     624             :                                                 }
     625           0 :                                                 if (mode[j] == ',' || mode[j] == ':') {
     626           0 :                                                         if (j > i + 2) {
     627             :                                                                 char func_name[1024];
     628           0 :                                                                 unsigned int func_name_len = MIN(sizeof(func_name) - 1, j - i - 1);
     629           0 :                                                                 memcpy(func_name, mode + i + 1, func_name_len);
     630           0 :                                                                 func_name[func_name_len] = '\0'; 
     631             : 
     632           0 :                                                                 zend_hash_add_empty_element(&self->not_filtered_functions,
     633             :                                                                                                                         func_name, func_name_len + 1);
     634           0 :                                                                 i = j;
     635             :                                                         }
     636           0 :                                                         if (mode[j] == ':') {
     637           0 :                                                                 break;
     638             :                                                         }
     639             :                                                 }
     640           0 :                                                 j++;
     641             :                                         }
     642           0 :                                         i = j;
     643             :                                 } else {
     644             : #if 0
     645             :                                         php_error_docref(NULL TSRMLS_CC, E_WARNING,
     646             :                                                                          "Expected list of functions for '%c' found none", mode[i]);
     647             : #endif
     648             :                                 }
     649           0 :                                 state = PARSER_WAIT_COLON;
     650           0 :                                 break;
     651             :                         case 'D':
     652             :                         case 'd':
     653             :                         case 'g':
     654             :                         case 'p':
     655             :                                 /* unsupported */
     656           0 :                                 if ((i + 1) < mode_len && mode[i+1] == ',') {
     657           0 :                                         i+= 2;
     658           0 :                                         while (i < mode_len) {
     659           0 :                                                 if (mode[i] == ':') {
     660           0 :                                                         break;
     661             :                                                 }
     662           0 :                                                 i++;
     663             :                                         }
     664             :                                 }
     665           0 :                                 state = PARSER_WAIT_COLON;
     666           0 :                                 break;
     667             :                         case 'F':
     668           0 :                                 self->flags |= MYSQLND_DEBUG_DUMP_FILE;
     669           0 :                                 state = PARSER_WAIT_COLON;
     670           0 :                                 break;
     671             :                         case 'i':
     672           0 :                                 self->flags |= MYSQLND_DEBUG_DUMP_PID;
     673           0 :                                 state = PARSER_WAIT_COLON;
     674           0 :                                 break;
     675             :                         case 'L':
     676           0 :                                 self->flags |= MYSQLND_DEBUG_DUMP_LINE;
     677           0 :                                 state = PARSER_WAIT_COLON;
     678           0 :                                 break;
     679             :                         case 'n':
     680           0 :                                 self->flags |= MYSQLND_DEBUG_DUMP_LEVEL;
     681           0 :                                 state = PARSER_WAIT_COLON;
     682           0 :                                 break;
     683             :                         case 't':
     684           1 :                                 if (mode[i+1] == ',') {
     685           0 :                                         unsigned int j = i + 2;
     686           0 :                                         while (j < mode_len) {
     687           0 :                                                 if (mode[j] == ':') {
     688           0 :                                                         break;
     689             :                                                 }
     690           0 :                                                 j++;
     691             :                                         }
     692           0 :                                         if (j > i + 2) {
     693           0 :                                                 char *value_str = estrndup(mode + i + 2, j - i - 2);
     694           0 :                                                 self->nest_level_limit = atoi(value_str);
     695           0 :                                                 efree(value_str);
     696             :                                         }
     697           0 :                                         i = j;
     698             :                                 } else {
     699           1 :                                         self->nest_level_limit = 200; /* default value for FF DBUG */
     700             :                                 }
     701           1 :                                 self->flags |= MYSQLND_DEBUG_DUMP_TRACE;
     702           1 :                                 state = PARSER_WAIT_COLON;
     703           1 :                                 break;
     704             :                         case 'T':
     705           0 :                                 self->flags |= MYSQLND_DEBUG_DUMP_TIME;
     706           0 :                                 state = PARSER_WAIT_COLON;
     707           0 :                                 break;
     708             :                         case 'N':
     709             :                         case 'P':
     710             :                         case 'r':
     711             :                         case 'S':
     712           0 :                                 state = PARSER_WAIT_COLON;
     713           0 :                                 break;
     714             :                         case 'm': /* mysqlnd extension - trace memory functions */
     715           0 :                                 self->flags |= MYSQLND_DEBUG_TRACE_MEMORY_CALLS;
     716           0 :                                 state = PARSER_WAIT_COLON;
     717           0 :                                 break;
     718             :                         case 'x': /* mysqlnd extension - profile calls */
     719           0 :                                 self->flags |= MYSQLND_DEBUG_PROFILE_CALLS;
     720           0 :                                 state = PARSER_WAIT_COLON;
     721           0 :                                 break;                          
     722             :                         default:
     723           0 :                                 if (state == PARSER_WAIT_MODIFIER) {
     724             : #if 0
     725             :                                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unrecognized format '%c'", mode[i]);
     726             : #endif
     727           0 :                                         if (i+1 < mode_len && mode[i+1] == ',') {
     728           0 :                                                 i+= 2;
     729           0 :                                                 while (i < mode_len) {
     730           0 :                                                         if (mode[i] == ':') {
     731           0 :                                                                 break;
     732             :                                                         }
     733           0 :                                                         i++;
     734             :                                                 }
     735             :                                         }
     736           0 :                                         state = PARSER_WAIT_COLON;
     737             :                                 } else if (state == PARSER_WAIT_COLON) {
     738             : #if 0
     739             :                                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Colon expected, '%c' found", mode[i]);
     740             : #endif
     741             :                                 }
     742             :                                 break;
     743             :                 }
     744             :         }
     745           1 : }
     746             : /* }}} */
     747             : 
     748             : MYSQLND_CLASS_METHODS_START(mysqlnd_debug)
     749             :         MYSQLND_METHOD(mysqlnd_debug, open),
     750             :         MYSQLND_METHOD(mysqlnd_debug, set_mode),
     751             :         MYSQLND_METHOD(mysqlnd_debug, log),
     752             :         MYSQLND_METHOD(mysqlnd_debug, log_va),
     753             :         MYSQLND_METHOD(mysqlnd_debug, func_enter),
     754             :         MYSQLND_METHOD(mysqlnd_debug, func_leave),
     755             :         MYSQLND_METHOD(mysqlnd_debug, close),
     756             :         MYSQLND_METHOD(mysqlnd_debug, free),
     757             : MYSQLND_CLASS_METHODS_END;
     758             : 
     759             : 
     760             : /* {{{ mysqlnd_debug_init */
     761             : PHPAPI MYSQLND_DEBUG *
     762           1 : mysqlnd_debug_init(const char * skip_functions[] TSRMLS_DC)
     763             : {
     764           1 :         MYSQLND_DEBUG *ret = ecalloc(1, sizeof(MYSQLND_DEBUG));
     765             : #ifdef ZTS
     766             :         ret->TSRMLS_C = TSRMLS_C;
     767             : #endif
     768           1 :         ret->nest_level_limit = 0;
     769           1 :         ret->pid = getpid();
     770           1 :         zend_stack_init(&ret->call_stack);
     771           1 :         zend_stack_init(&ret->call_time_stack);
     772           1 :         zend_hash_init(&ret->not_filtered_functions, 0, NULL, NULL, 0);
     773           1 :         zend_hash_init(&ret->function_profiles, 0, NULL, NULL, 0);
     774             : 
     775           1 :         ret->m = & mysqlnd_mysqlnd_debug_methods;
     776           1 :         ret->skip_functions = skip_functions;
     777             : 
     778           1 :         return ret;
     779             : }
     780             : /* }}} */
     781             : 
     782             : 
     783             : /* {{{ _mysqlnd_debug */
     784           0 : PHPAPI void _mysqlnd_debug(const char * mode TSRMLS_DC)
     785             : {
     786             : #ifdef PHP_DEBUG
     787           0 :         MYSQLND_DEBUG *dbg = MYSQLND_G(dbg);
     788           0 :         if (!dbg) {
     789           0 :                 MYSQLND_G(dbg) = dbg = mysqlnd_debug_init(mysqlnd_debug_std_no_trace_funcs TSRMLS_CC);
     790           0 :                 if (!dbg) {
     791           0 :                         return;
     792             :                 }
     793             :         }
     794             : 
     795           0 :         dbg->m->close(dbg);
     796           0 :         dbg->m->set_mode(dbg, mode);
     797           0 :         while (zend_stack_count(&dbg->call_stack)) {
     798           0 :                 zend_stack_del_top(&dbg->call_stack);
     799             :         }
     800           0 :         while (zend_stack_count(&dbg->call_time_stack)) {
     801           0 :                 zend_stack_del_top(&dbg->call_time_stack);
     802             :         }
     803             : #endif
     804             : }
     805             : /* }}} */
     806             : 
     807             : 
     808             : #if ZEND_DEBUG
     809             : #else
     810             : #define __zend_filename "/unknown/unknown"
     811             : #define __zend_lineno   0
     812             : #endif
     813             : 
     814             : #define REAL_SIZE(s) (collect_memory_statistics? (s) + sizeof(size_t) : (s))
     815             : #define REAL_PTR(p) (collect_memory_statistics && (p)? (((char *)(p)) - sizeof(size_t)) : (p))
     816             : #define FAKE_PTR(p) (collect_memory_statistics && (p)? (((char *)(p)) + sizeof(size_t)) : (p))
     817             : 
     818             : /* {{{ _mysqlnd_emalloc */
     819         546 : void * _mysqlnd_emalloc(size_t size MYSQLND_MEM_D)
     820             : {
     821             :         void *ret;
     822         546 :         zend_bool collect_memory_statistics = MYSQLND_G(collect_memory_statistics);
     823         546 :         long * threshold = &MYSQLND_G(debug_emalloc_fail_threshold);
     824         546 :         DBG_ENTER(mysqlnd_emalloc_name);
     825             : 
     826         546 :         DBG_INF_FMT("file=%-15s line=%4d", strrchr(__zend_filename, PHP_DIR_SEPARATOR) + 1, __zend_lineno);
     827             : 
     828             : #ifdef PHP_DEBUG
     829             :         /* -1 is also "true" */
     830         546 :         if (*threshold) {
     831             : #endif
     832         546 :                 ret = emalloc(REAL_SIZE(size));
     833             : #ifdef PHP_DEBUG
     834         546 :                 --*threshold;
     835           0 :         } else if (*threshold == 0) {
     836           0 :                 ret = NULL;
     837             :         }
     838             : #endif
     839             : 
     840         546 :         DBG_INF_FMT("size=%lu ptr=%p", size, ret);
     841             : 
     842         546 :         if (ret && collect_memory_statistics) {
     843          12 :                 *(size_t *) ret = size;
     844          12 :                 MYSQLND_INC_GLOBAL_STATISTIC_W_VALUE2(STAT_MEM_EMALLOC_COUNT, 1, STAT_MEM_EMALLOC_AMOUNT, size);
     845             :         }
     846         546 :         DBG_RETURN(FAKE_PTR(ret));
     847             : }
     848             : /* }}} */
     849             : 
     850             : 
     851             : /* {{{ _mysqlnd_pemalloc */
     852       42821 : void * _mysqlnd_pemalloc(size_t size, zend_bool persistent MYSQLND_MEM_D)
     853             : {
     854             :         void *ret;
     855       42821 :         zend_bool collect_memory_statistics = MYSQLND_G(collect_memory_statistics);
     856       42821 :         long * threshold = persistent? &MYSQLND_G(debug_malloc_fail_threshold):&MYSQLND_G(debug_emalloc_fail_threshold);
     857       42821 :         DBG_ENTER(mysqlnd_pemalloc_name);
     858       42821 :         DBG_INF_FMT("file=%-15s line=%4d", strrchr(__zend_filename, PHP_DIR_SEPARATOR) + 1, __zend_lineno);
     859             : 
     860             : #ifdef PHP_DEBUG
     861             :         /* -1 is also "true" */
     862       42821 :         if (*threshold) {
     863             : #endif
     864       42821 :                 ret = pemalloc(REAL_SIZE(size), persistent);
     865             : #ifdef PHP_DEBUG
     866       42821 :                 --*threshold;
     867           0 :         } else if (*threshold == 0) {
     868           0 :                 ret = NULL;
     869             :         }
     870             : #endif
     871             : 
     872       42821 :         DBG_INF_FMT("size=%lu ptr=%p persistent=%u", size, ret, persistent);
     873             : 
     874       42821 :         if (ret && collect_memory_statistics) {
     875          95 :                 enum mysqlnd_collected_stats s1 = persistent? STAT_MEM_MALLOC_COUNT:STAT_MEM_EMALLOC_COUNT;
     876          95 :                 enum mysqlnd_collected_stats s2 = persistent? STAT_MEM_MALLOC_AMOUNT:STAT_MEM_EMALLOC_AMOUNT;
     877          95 :                 *(size_t *) ret = size;
     878          95 :                 MYSQLND_INC_GLOBAL_STATISTIC_W_VALUE2(s1, 1, s2, size);
     879             :         }
     880             : 
     881       42821 :         DBG_RETURN(FAKE_PTR(ret));
     882             : }
     883             : /* }}} */
     884             : 
     885             : 
     886             : /* {{{ _mysqlnd_ecalloc */
     887        5403 : void * _mysqlnd_ecalloc(unsigned int nmemb, size_t size MYSQLND_MEM_D)
     888             : {
     889             :         void *ret;
     890        5403 :         zend_bool collect_memory_statistics = MYSQLND_G(collect_memory_statistics);
     891        5403 :         long * threshold = &MYSQLND_G(debug_ecalloc_fail_threshold);
     892        5403 :         DBG_ENTER(mysqlnd_ecalloc_name);
     893        5403 :         DBG_INF_FMT("file=%-15s line=%4d", strrchr(__zend_filename, PHP_DIR_SEPARATOR) + 1, __zend_lineno);
     894        5403 :         DBG_INF_FMT("before: %lu", zend_memory_usage(FALSE TSRMLS_CC));
     895             : 
     896             : #ifdef PHP_DEBUG
     897             :         /* -1 is also "true" */
     898        5403 :         if (*threshold) {
     899             : #endif
     900        5403 :                 ret = ecalloc(nmemb, REAL_SIZE(size));
     901             : #ifdef PHP_DEBUG
     902        5403 :                 --*threshold;
     903           0 :         } else if (*threshold == 0) {
     904           0 :                 ret = NULL;
     905             :         }
     906             : #endif
     907             : 
     908        5403 :         DBG_INF_FMT("after : %lu", zend_memory_usage(FALSE TSRMLS_CC));
     909        5403 :         DBG_INF_FMT("size=%lu ptr=%p", size, ret);
     910        5403 :         if (ret && collect_memory_statistics) {
     911          20 :                 *(size_t *) ret = size;
     912          20 :                 MYSQLND_INC_GLOBAL_STATISTIC_W_VALUE2(STAT_MEM_ECALLOC_COUNT, 1, STAT_MEM_ECALLOC_AMOUNT, size);
     913             :         }
     914        5403 :         DBG_RETURN(FAKE_PTR(ret));
     915             : }
     916             : /* }}} */
     917             : 
     918             : 
     919             : /* {{{ _mysqlnd_pecalloc */
     920      177900 : void * _mysqlnd_pecalloc(unsigned int nmemb, size_t size, zend_bool persistent MYSQLND_MEM_D)
     921             : {
     922             :         void *ret;
     923      177900 :         zend_bool collect_memory_statistics = MYSQLND_G(collect_memory_statistics);
     924      177900 :         long * threshold = persistent? &MYSQLND_G(debug_calloc_fail_threshold):&MYSQLND_G(debug_ecalloc_fail_threshold);
     925      177900 :         DBG_ENTER(mysqlnd_pecalloc_name);
     926      177900 :         DBG_INF_FMT("file=%-15s line=%4d", strrchr(__zend_filename, PHP_DIR_SEPARATOR) + 1, __zend_lineno);
     927             : 
     928             : #ifdef PHP_DEBUG
     929             :         /* -1 is also "true" */
     930      177900 :         if (*threshold) {
     931             : #endif
     932      177900 :                 ret = pecalloc(nmemb, REAL_SIZE(size), persistent);
     933             : #ifdef PHP_DEBUG
     934      177900 :                 --*threshold;
     935           0 :         } else if (*threshold == 0) {
     936           0 :                 ret = NULL;
     937             :         }
     938             : #endif
     939             : 
     940      177900 :         DBG_INF_FMT("size=%lu ptr=%p", size, ret);
     941             : 
     942      177900 :         if (ret && collect_memory_statistics) {
     943         446 :                 enum mysqlnd_collected_stats s1 = persistent? STAT_MEM_CALLOC_COUNT:STAT_MEM_ECALLOC_COUNT;
     944         446 :                 enum mysqlnd_collected_stats s2 = persistent? STAT_MEM_CALLOC_AMOUNT:STAT_MEM_ECALLOC_AMOUNT;
     945         446 :                 *(size_t *) ret = size;
     946         446 :                 MYSQLND_INC_GLOBAL_STATISTIC_W_VALUE2(s1, 1, s2, size);
     947             :         }
     948             : 
     949      177900 :         DBG_RETURN(FAKE_PTR(ret));
     950             : }
     951             : /* }}} */
     952             : 
     953             : 
     954             : /* {{{ _mysqlnd_erealloc */
     955           0 : void * _mysqlnd_erealloc(void *ptr, size_t new_size MYSQLND_MEM_D)
     956             : {
     957             :         void *ret;
     958           0 :         zend_bool collect_memory_statistics = MYSQLND_G(collect_memory_statistics);
     959           0 :         size_t old_size = collect_memory_statistics && ptr? *(size_t *) (((char*)ptr) - sizeof(size_t)) : 0;
     960           0 :         long * threshold = &MYSQLND_G(debug_erealloc_fail_threshold);
     961           0 :         DBG_ENTER(mysqlnd_erealloc_name);
     962           0 :         DBG_INF_FMT("file=%-15s line=%4d", strrchr(__zend_filename, PHP_DIR_SEPARATOR) + 1, __zend_lineno);
     963           0 :         DBG_INF_FMT("ptr=%p old_size=%lu, new_size=%lu", ptr, old_size, new_size); 
     964             : 
     965             : #ifdef PHP_DEBUG
     966             :         /* -1 is also "true" */
     967           0 :         if (*threshold) {
     968             : #endif
     969           0 :                 ret = erealloc(REAL_PTR(ptr), REAL_SIZE(new_size));
     970             : #ifdef PHP_DEBUG
     971           0 :                 --*threshold;
     972           0 :         } else if (*threshold == 0) {
     973           0 :                 ret = NULL;
     974             :         }
     975             : #endif
     976             : 
     977           0 :         DBG_INF_FMT("new_ptr=%p", (char*)ret);
     978           0 :         if (ret && collect_memory_statistics) {
     979           0 :                 *(size_t *) ret = new_size;
     980           0 :                 MYSQLND_INC_GLOBAL_STATISTIC_W_VALUE2(STAT_MEM_EREALLOC_COUNT, 1, STAT_MEM_EREALLOC_AMOUNT, new_size);
     981             :         }
     982           0 :         DBG_RETURN(FAKE_PTR(ret));
     983             : }
     984             : /* }}} */
     985             : 
     986             : 
     987             : /* {{{ _mysqlnd_perealloc */
     988       28761 : void * _mysqlnd_perealloc(void *ptr, size_t new_size, zend_bool persistent MYSQLND_MEM_D)
     989             : {
     990             :         void *ret;
     991       28761 :         zend_bool collect_memory_statistics = MYSQLND_G(collect_memory_statistics);
     992       28761 :         size_t old_size = collect_memory_statistics && ptr? *(size_t *) (((char*)ptr) - sizeof(size_t)) : 0;
     993       28761 :         long * threshold = persistent? &MYSQLND_G(debug_realloc_fail_threshold):&MYSQLND_G(debug_erealloc_fail_threshold);
     994       28761 :         DBG_ENTER(mysqlnd_perealloc_name);
     995       28761 :         DBG_INF_FMT("file=%-15s line=%4d", strrchr(__zend_filename, PHP_DIR_SEPARATOR) + 1, __zend_lineno);
     996       28761 :         DBG_INF_FMT("ptr=%p old_size=%lu new_size=%lu persistent=%u", ptr, old_size, new_size, persistent); 
     997             : 
     998             : #ifdef PHP_DEBUG
     999             :         /* -1 is also "true" */
    1000       28761 :         if (*threshold) {
    1001             : #endif
    1002       28761 :                 ret = perealloc(REAL_PTR(ptr), REAL_SIZE(new_size), persistent);
    1003             : #ifdef PHP_DEBUG
    1004       28761 :                 --*threshold;
    1005           0 :         } else if (*threshold == 0) {
    1006           0 :                 ret = NULL;
    1007             :         }
    1008             : #endif
    1009             : 
    1010       28761 :         DBG_INF_FMT("new_ptr=%p", (char*)ret);
    1011             : 
    1012       28761 :         if (ret && collect_memory_statistics) {
    1013          34 :                 enum mysqlnd_collected_stats s1 = persistent? STAT_MEM_REALLOC_COUNT:STAT_MEM_EREALLOC_COUNT;
    1014          34 :                 enum mysqlnd_collected_stats s2 = persistent? STAT_MEM_REALLOC_AMOUNT:STAT_MEM_EREALLOC_AMOUNT;
    1015          34 :                 *(size_t *) ret = new_size;
    1016          34 :                 MYSQLND_INC_GLOBAL_STATISTIC_W_VALUE2(s1, 1, s2, new_size);
    1017             :         }
    1018       28761 :         DBG_RETURN(FAKE_PTR(ret));
    1019             : }
    1020             : /* }}} */
    1021             : 
    1022             : 
    1023             : /* {{{ _mysqlnd_efree */
    1024       23648 : void _mysqlnd_efree(void *ptr MYSQLND_MEM_D)
    1025             : {
    1026       23648 :         size_t free_amount = 0;
    1027       23648 :         zend_bool collect_memory_statistics = MYSQLND_G(collect_memory_statistics);
    1028       23648 :         DBG_ENTER(mysqlnd_efree_name);
    1029       23648 :         DBG_INF_FMT("file=%-15s line=%4d", strrchr(__zend_filename, PHP_DIR_SEPARATOR) + 1, __zend_lineno);
    1030       23648 :         DBG_INF_FMT("ptr=%p", ptr); 
    1031             : 
    1032       23648 :         if (ptr) {
    1033       23648 :                 if (collect_memory_statistics) {
    1034          68 :                         free_amount = *(size_t *)(((char*)ptr) - sizeof(size_t));
    1035          68 :                         DBG_INF_FMT("ptr=%p size=%u", ((char*)ptr) - sizeof(size_t), (unsigned int) free_amount);
    1036             :                 }
    1037       23648 :                 efree(REAL_PTR(ptr));
    1038             :         }
    1039             : 
    1040       23648 :         if (collect_memory_statistics) {
    1041          68 :                 MYSQLND_INC_GLOBAL_STATISTIC_W_VALUE2(STAT_MEM_EFREE_COUNT, 1, STAT_MEM_EFREE_AMOUNT, free_amount);
    1042             :         }
    1043       23648 :         DBG_VOID_RETURN;
    1044             : }
    1045             : /* }}} */
    1046             : 
    1047             : 
    1048             : /* {{{ _mysqlnd_pefree */
    1049      216158 : void _mysqlnd_pefree(void *ptr, zend_bool persistent MYSQLND_MEM_D)
    1050             : {
    1051      216158 :         size_t free_amount = 0;
    1052      216158 :         zend_bool collect_memory_statistics = MYSQLND_G(collect_memory_statistics);
    1053      216158 :         DBG_ENTER(mysqlnd_pefree_name);
    1054      216158 :         DBG_INF_FMT("file=%-15s line=%4d", strrchr(__zend_filename, PHP_DIR_SEPARATOR) + 1, __zend_lineno);
    1055      216158 :         DBG_INF_FMT("ptr=%p persistent=%u", ptr, persistent); 
    1056             : 
    1057      216158 :         if (ptr) {
    1058      216158 :                 if (collect_memory_statistics) {
    1059         602 :                         free_amount = *(size_t *)(((char*)ptr) - sizeof(size_t));
    1060         602 :                         DBG_INF_FMT("ptr=%p size=%u", ((char*)ptr) - sizeof(size_t), (unsigned int) free_amount);
    1061             :                 }
    1062      216158 :                 pefree(REAL_PTR(ptr), persistent);
    1063             :         }
    1064             : 
    1065      216158 :         if (collect_memory_statistics) {
    1066         602 :                 MYSQLND_INC_GLOBAL_STATISTIC_W_VALUE2(persistent? STAT_MEM_FREE_COUNT:STAT_MEM_EFREE_COUNT, 1,
    1067             :                                                                                           persistent? STAT_MEM_FREE_AMOUNT:STAT_MEM_EFREE_AMOUNT, free_amount);
    1068             :         }
    1069      216158 :         DBG_VOID_RETURN;
    1070             : }
    1071             : 
    1072             : 
    1073             : /* {{{ _mysqlnd_malloc */
    1074      140538 : void * _mysqlnd_malloc(size_t size MYSQLND_MEM_D)
    1075             : {
    1076             :         void *ret;
    1077      140538 :         zend_bool collect_memory_statistics = MYSQLND_G(collect_memory_statistics);
    1078      140538 :         long * threshold = &MYSQLND_G(debug_malloc_fail_threshold);
    1079      140538 :         DBG_ENTER(mysqlnd_malloc_name);
    1080      140538 :         DBG_INF_FMT("file=%-15s line=%4d", strrchr(__zend_filename, PHP_DIR_SEPARATOR) + 1, __zend_lineno);
    1081             : 
    1082             : #ifdef PHP_DEBUG
    1083             :         /* -1 is also "true" */
    1084      140538 :         if (*threshold) {
    1085             : #endif
    1086      140538 :                 ret = malloc(REAL_SIZE(size));
    1087             : #ifdef PHP_DEBUG
    1088      140538 :                 --*threshold;
    1089           0 :         } else if (*threshold == 0) {
    1090           0 :                 ret = NULL;
    1091             :         }
    1092             : #endif
    1093             : 
    1094      140538 :         DBG_INF_FMT("size=%lu ptr=%p", size, ret);
    1095      140538 :         if (ret && collect_memory_statistics) {
    1096         131 :                 *(size_t *) ret = size;
    1097         131 :                 MYSQLND_INC_GLOBAL_STATISTIC_W_VALUE2(STAT_MEM_MALLOC_COUNT, 1, STAT_MEM_MALLOC_AMOUNT, size);
    1098             :         }
    1099      140538 :         DBG_RETURN(FAKE_PTR(ret));
    1100             : }
    1101             : /* }}} */
    1102             : 
    1103             : 
    1104             : /* {{{ _mysqlnd_calloc */
    1105        4595 : void * _mysqlnd_calloc(unsigned int nmemb, size_t size MYSQLND_MEM_D)
    1106             : {
    1107             :         void *ret;
    1108        4595 :         zend_bool collect_memory_statistics = MYSQLND_G(collect_memory_statistics);
    1109        4595 :         long * threshold = &MYSQLND_G(debug_calloc_fail_threshold);
    1110        4595 :         DBG_ENTER(mysqlnd_calloc_name);
    1111        4595 :         DBG_INF_FMT("file=%-15s line=%4d", strrchr(__zend_filename, PHP_DIR_SEPARATOR) + 1, __zend_lineno);
    1112             : 
    1113             : #ifdef PHP_DEBUG
    1114             :         /* -1 is also "true" */
    1115        4595 :         if (*threshold) {
    1116             : #endif
    1117        4595 :                 ret = calloc(nmemb, REAL_SIZE(size));
    1118             : #ifdef PHP_DEBUG
    1119        4595 :                 --*threshold;
    1120           0 :         } else if (*threshold == 0) {
    1121           0 :                 ret = NULL;
    1122             :         }
    1123             : #endif
    1124             : 
    1125        4595 :         DBG_INF_FMT("size=%lu ptr=%p", size, ret);
    1126        4595 :         if (ret && collect_memory_statistics) {
    1127          18 :                 *(size_t *) ret = size;
    1128          18 :                 MYSQLND_INC_GLOBAL_STATISTIC_W_VALUE2(STAT_MEM_CALLOC_COUNT, 1, STAT_MEM_CALLOC_AMOUNT, size);
    1129             :         }
    1130        4595 :         DBG_RETURN(FAKE_PTR(ret));
    1131             : }
    1132             : /* }}} */
    1133             : 
    1134             : 
    1135             : /* {{{ _mysqlnd_realloc */
    1136           0 : void * _mysqlnd_realloc(void *ptr, size_t new_size MYSQLND_MEM_D)
    1137             : {
    1138             :         void *ret;
    1139           0 :         zend_bool collect_memory_statistics = MYSQLND_G(collect_memory_statistics);
    1140           0 :         long * threshold = &MYSQLND_G(debug_realloc_fail_threshold);
    1141           0 :         DBG_ENTER(mysqlnd_realloc_name);
    1142           0 :         DBG_INF_FMT("file=%-15s line=%4d", strrchr(__zend_filename, PHP_DIR_SEPARATOR) + 1, __zend_lineno);
    1143           0 :         DBG_INF_FMT("ptr=%p new_size=%lu ", new_size, ptr); 
    1144           0 :         DBG_INF_FMT("before: %lu", zend_memory_usage(TRUE TSRMLS_CC));
    1145             : 
    1146             : #ifdef PHP_DEBUG
    1147             :         /* -1 is also "true" */
    1148           0 :         if (*threshold) {
    1149             : #endif
    1150           0 :                 ret = realloc(REAL_PTR(ptr), REAL_SIZE(new_size));
    1151             : #ifdef PHP_DEBUG
    1152           0 :                 --*threshold;
    1153           0 :         } else if (*threshold == 0) {
    1154           0 :                 ret = NULL;
    1155             :         }
    1156             : #endif
    1157             : 
    1158           0 :         DBG_INF_FMT("new_ptr=%p", (char*)ret);
    1159             : 
    1160           0 :         if (ret && collect_memory_statistics) {
    1161           0 :                 *(size_t *) ret = new_size;
    1162           0 :                 MYSQLND_INC_GLOBAL_STATISTIC_W_VALUE2(STAT_MEM_REALLOC_COUNT, 1, STAT_MEM_REALLOC_AMOUNT, new_size);
    1163             :         }
    1164           0 :         DBG_RETURN(FAKE_PTR(ret));
    1165             : }
    1166             : /* }}} */
    1167             : 
    1168             : 
    1169             : /* {{{ _mysqlnd_free */
    1170      145129 : void _mysqlnd_free(void *ptr MYSQLND_MEM_D)
    1171             : {
    1172      145129 :         size_t free_amount = 0;
    1173      145129 :         zend_bool collect_memory_statistics = MYSQLND_G(collect_memory_statistics);
    1174      145129 :         DBG_ENTER(mysqlnd_free_name);
    1175      145129 :         DBG_INF_FMT("file=%-15s line=%4d", strrchr(__zend_filename, PHP_DIR_SEPARATOR) + 1, __zend_lineno);
    1176      145129 :         DBG_INF_FMT("ptr=%p", ptr); 
    1177             : 
    1178      145129 :         if (ptr) {
    1179      145129 :                 if (collect_memory_statistics) {
    1180         149 :                         free_amount = *(size_t *)(((char*)ptr) - sizeof(size_t));
    1181         149 :                         DBG_INF_FMT("ptr=%p size=%u", ((char*)ptr) - sizeof(size_t), (unsigned int) free_amount);
    1182             :                 }
    1183      145129 :                 free(REAL_PTR(ptr));
    1184             :         }
    1185             : 
    1186      145129 :         if (collect_memory_statistics) {
    1187         149 :                 MYSQLND_INC_GLOBAL_STATISTIC_W_VALUE2(STAT_MEM_FREE_COUNT, 1, STAT_MEM_FREE_AMOUNT, free_amount);
    1188             :         }
    1189      145129 :         DBG_VOID_RETURN;
    1190             : }
    1191             : /* }}} */
    1192             : 
    1193             : #define SMART_STR_START_SIZE 2048
    1194             : #define SMART_STR_PREALLOC 512
    1195             : #include "ext/standard/php_smart_str.h"
    1196             : 
    1197             : 
    1198             : /* {{{ _mysqlnd_pestrndup */
    1199        6091 : char * _mysqlnd_pestrndup(const char * const ptr, size_t length, zend_bool persistent MYSQLND_MEM_D)
    1200             : {
    1201             :         char * ret;
    1202        6091 :         zend_bool collect_memory_statistics = MYSQLND_G(collect_memory_statistics);
    1203        6091 :         DBG_ENTER(mysqlnd_pestrndup_name);
    1204        6091 :         DBG_INF_FMT("file=%-15s line=%4d", strrchr(__zend_filename, PHP_DIR_SEPARATOR) + 1, __zend_lineno);
    1205        6091 :         DBG_INF_FMT("ptr=%p", ptr); 
    1206             : 
    1207        6091 :         ret = pemalloc(REAL_SIZE(length) + 1, persistent);
    1208             :         {
    1209        6091 :                 size_t l = length;
    1210        6091 :                 char * p = (char *) ptr;
    1211        6091 :                 char * dest = (char *) FAKE_PTR(ret);
    1212      102183 :                 while (*p && l--) {
    1213       90001 :                         *dest++ = *p++;
    1214             :                 }
    1215        6091 :                 *dest = '\0';
    1216             :         }
    1217             : 
    1218        6091 :         if (collect_memory_statistics) {
    1219          49 :                 *(size_t *) ret = length;
    1220          49 :                 MYSQLND_INC_GLOBAL_STATISTIC(persistent? STAT_MEM_STRNDUP_COUNT : STAT_MEM_ESTRNDUP_COUNT);
    1221             :         }
    1222             : 
    1223        6091 :         DBG_RETURN(FAKE_PTR(ret));
    1224             : }
    1225             : /* }}} */
    1226             : 
    1227             : 
    1228             : /* {{{ _mysqlnd_pestrdup */
    1229        7269 : char * _mysqlnd_pestrdup(const char * const ptr, zend_bool persistent MYSQLND_MEM_D)
    1230             : {
    1231             :         char * ret;
    1232        7269 :         smart_str tmp_str = {0, 0, 0};
    1233        7269 :         const char * p = ptr;
    1234        7269 :         zend_bool collect_memory_statistics = MYSQLND_G(collect_memory_statistics);
    1235        7269 :         DBG_ENTER(mysqlnd_pestrdup_name);
    1236        7269 :         DBG_INF_FMT("file=%-15s line=%4d", strrchr(__zend_filename, PHP_DIR_SEPARATOR) + 1, __zend_lineno);
    1237        7269 :         DBG_INF_FMT("ptr=%p", ptr);
    1238             :         do {
    1239      116798 :                 smart_str_appendc(&tmp_str, *p);
    1240      116798 :         } while (*p++);
    1241             : 
    1242        7269 :         ret = pemalloc(tmp_str.len + sizeof(size_t), persistent);
    1243        7269 :         memcpy(FAKE_PTR(ret), tmp_str.c, tmp_str.len);
    1244             : 
    1245        7269 :         if (ret && collect_memory_statistics) {
    1246          48 :                 *(size_t *) ret = tmp_str.len;
    1247          48 :                 MYSQLND_INC_GLOBAL_STATISTIC(persistent? STAT_MEM_STRDUP_COUNT : STAT_MEM_ESTRDUP_COUNT);
    1248             :         }
    1249        7269 :         smart_str_free(&tmp_str);
    1250             : 
    1251        7269 :         DBG_RETURN(FAKE_PTR(ret));
    1252             : }
    1253             : /* }}} */
    1254             : 
    1255             : #define MYSQLND_DEBUG_MEMORY 1
    1256             : 
    1257             : #if MYSQLND_DEBUG_MEMORY == 0
    1258             : 
    1259             : /* {{{ mysqlnd_zend_mm_emalloc */
    1260             : static void * mysqlnd_zend_mm_emalloc(size_t size MYSQLND_MEM_D)
    1261             : {
    1262             :         return emalloc(size);
    1263             : }
    1264             : /* }}} */
    1265             : 
    1266             : 
    1267             : /* {{{ mysqlnd_zend_mm_pemalloc */
    1268             : static void * mysqlnd_zend_mm_pemalloc(size_t size, zend_bool persistent MYSQLND_MEM_D)
    1269             : {
    1270             :         return pemalloc(size, persistent);
    1271             : }
    1272             : /* }}} */
    1273             : 
    1274             : 
    1275             : /* {{{ mysqlnd_zend_mm_ecalloc */
    1276             : static void * mysqlnd_zend_mm_ecalloc(unsigned int nmemb, size_t size MYSQLND_MEM_D)
    1277             : {
    1278             :         return ecalloc(nmemb, size);
    1279             : }
    1280             : /* }}} */
    1281             : 
    1282             : 
    1283             : /* {{{ mysqlnd_zend_mm_pecalloc */
    1284             : static void * mysqlnd_zend_mm_pecalloc(unsigned int nmemb, size_t size, zend_bool persistent MYSQLND_MEM_D)
    1285             : {
    1286             :         return pecalloc(nmemb, size, persistent);
    1287             : }
    1288             : /* }}} */
    1289             : 
    1290             : 
    1291             : /* {{{ mysqlnd_zend_mm_erealloc */
    1292             : static void * mysqlnd_zend_mm_erealloc(void *ptr, size_t new_size MYSQLND_MEM_D)
    1293             : {
    1294             :         return erealloc(ptr, new_size);
    1295             : }
    1296             : /* }}} */
    1297             : 
    1298             : 
    1299             : /* {{{ mysqlnd_zend_mm_perealloc */
    1300             : static void * mysqlnd_zend_mm_perealloc(void *ptr, size_t new_size, zend_bool persistent MYSQLND_MEM_D)
    1301             : {
    1302             :         return perealloc(ptr, new_size, persistent);
    1303             : }
    1304             : /* }}} */
    1305             : 
    1306             : 
    1307             : /* {{{ mysqlnd_zend_mm_efree */
    1308             : static void mysqlnd_zend_mm_efree(void * ptr MYSQLND_MEM_D)
    1309             : {
    1310             :         efree(ptr);
    1311             : }
    1312             : /* }}} */
    1313             : 
    1314             : 
    1315             : /* {{{ mysqlnd_zend_mm_pefree */
    1316             : static void mysqlnd_zend_mm_pefree(void * ptr, zend_bool persistent MYSQLND_MEM_D)
    1317             : {
    1318             :         pefree(ptr, persistent);
    1319             : }
    1320             : /* }}} */
    1321             : 
    1322             : 
    1323             : /* {{{ mysqlnd_zend_mm_malloc */
    1324             : static void * mysqlnd_zend_mm_malloc(size_t size MYSQLND_MEM_D)
    1325             : {
    1326             :         return malloc(size);
    1327             : }
    1328             : /* }}} */
    1329             : 
    1330             : 
    1331             : /* {{{ mysqlnd_zend_mm_calloc */
    1332             : static void * mysqlnd_zend_mm_calloc(unsigned int nmemb, size_t size MYSQLND_MEM_D)
    1333             : {
    1334             :         return calloc(nmemb, size);
    1335             : }
    1336             : /* }}} */
    1337             : 
    1338             : 
    1339             : /* {{{ mysqlnd_zend_mm_realloc */
    1340             : static void * mysqlnd_zend_mm_realloc(void * ptr, size_t new_size MYSQLND_MEM_D)
    1341             : {
    1342             :         return realloc(ptr, new_size);
    1343             : }
    1344             : /* }}} */
    1345             : 
    1346             : 
    1347             : /* {{{ mysqlnd_zend_mm_free */
    1348             : static void mysqlnd_zend_mm_free(void * ptr MYSQLND_MEM_D)
    1349             : {
    1350             :         free(ptr);
    1351             : }
    1352             : /* }}} */
    1353             : 
    1354             : 
    1355             : /* {{{ mysqlnd_zend_mm_pestrndup */
    1356             : static char * mysqlnd_zend_mm_pestrndup(const char * const ptr, size_t length, zend_bool persistent MYSQLND_MEM_D)
    1357             : {
    1358             :         return pestrndup(ptr, length, persistent);
    1359             : }
    1360             : /* }}} */
    1361             : 
    1362             : 
    1363             : /* {{{ mysqlnd_zend_mm_pestrdup */
    1364             : static char * mysqlnd_zend_mm_pestrdup(const char * const ptr, zend_bool persistent MYSQLND_MEM_D)
    1365             : {
    1366             :         return pestrdup(ptr, persistent);
    1367             : }
    1368             : /* }}} */
    1369             : 
    1370             : #endif
    1371             : 
    1372             : 
    1373             : PHPAPI struct st_mysqlnd_allocator_methods mysqlnd_allocator = 
    1374             : {
    1375             : #if MYSQLND_DEBUG_MEMORY
    1376             :         _mysqlnd_emalloc,
    1377             :         _mysqlnd_pemalloc,
    1378             :         _mysqlnd_ecalloc,
    1379             :         _mysqlnd_pecalloc,
    1380             :         _mysqlnd_erealloc,
    1381             :         _mysqlnd_perealloc,
    1382             :         _mysqlnd_efree,
    1383             :         _mysqlnd_pefree,
    1384             :         _mysqlnd_malloc,
    1385             :         _mysqlnd_calloc,
    1386             :         _mysqlnd_realloc,
    1387             :         _mysqlnd_free,
    1388             :         _mysqlnd_pestrndup,
    1389             :         _mysqlnd_pestrdup
    1390             : #else
    1391             :         mysqlnd_zend_mm_emalloc,
    1392             :         mysqlnd_zend_mm_pemalloc,
    1393             :         mysqlnd_zend_mm_ecalloc,
    1394             :         mysqlnd_zend_mm_pecalloc,
    1395             :         mysqlnd_zend_mm_erealloc,
    1396             :         mysqlnd_zend_mm_perealloc,
    1397             :         mysqlnd_zend_mm_efree,
    1398             :         mysqlnd_zend_mm_pefree,
    1399             :         mysqlnd_zend_mm_malloc,
    1400             :         mysqlnd_zend_mm_calloc,
    1401             :         mysqlnd_zend_mm_realloc,
    1402             :         mysqlnd_zend_mm_free,
    1403             :         mysqlnd_zend_mm_pestrndup,
    1404             :         mysqlnd_zend_mm_pestrdup
    1405             : #endif
    1406             : };
    1407             : 
    1408             : 
    1409             : 
    1410             : /* Follows code borrowed from zend_builtin_functions.c because the functions there are static */
    1411             : 
    1412             : #if MYSQLND_UNICODE
    1413             : /* {{{ gettraceasstring() macros */
    1414             : #define TRACE_APPEND_CHR(chr)                                            \
    1415             :         *str = (char*)erealloc(*str, *len + 1 + 1);                          \
    1416             :         (*str)[(*len)++] = chr
    1417             : 
    1418             : #define TRACE_APPEND_STRL(val, vallen)                                   \
    1419             :         {                                                                    \
    1420             :                 int l = vallen;                                                  \
    1421             :                 *str = (char*)erealloc(*str, *len + l + 1);                      \
    1422             :                 memcpy((*str) + *len, val, l);                                   \
    1423             :                 *len += l;                                                       \
    1424             :         }
    1425             : 
    1426             : #define TRACE_APPEND_USTRL(val, vallen) \
    1427             :         { \
    1428             :                 zval tmp, copy; \
    1429             :                 int use_copy; \
    1430             :                 ZVAL_UNICODEL(&tmp, val, vallen, 1); \
    1431             :                 zend_make_printable_zval(&tmp, &copy, &use_copy); \
    1432             :                 TRACE_APPEND_STRL(Z_STRVAL(copy), Z_STRLEN(copy)); \
    1433             :                 zval_dtor(&copy); \
    1434             :                 zval_dtor(&tmp); \
    1435             :         }
    1436             : 
    1437             : #define TRACE_APPEND_ZVAL(zv) \
    1438             :         if (Z_TYPE_P((zv)) == IS_UNICODE) { \
    1439             :                 zval copy; \
    1440             :                 int use_copy; \
    1441             :                 zend_make_printable_zval((zv), &copy, &use_copy); \
    1442             :                 TRACE_APPEND_STRL(Z_STRVAL(copy), Z_STRLEN(copy)); \
    1443             :                 zval_dtor(&copy); \
    1444             :         } else { \
    1445             :                 TRACE_APPEND_STRL(Z_STRVAL_P((zv)), Z_STRLEN_P((zv))); \
    1446             :         }
    1447             : 
    1448             : #define TRACE_APPEND_STR(val)                                            \
    1449             :         TRACE_APPEND_STRL(val, sizeof(val)-1)
    1450             : 
    1451             : #define TRACE_APPEND_KEY(key)                                            \
    1452             :         if (zend_ascii_hash_find(ht, key, sizeof(key), (void**)&tmp) == SUCCESS) { \
    1453             :                 if (Z_TYPE_PP(tmp) == IS_UNICODE) { \
    1454             :                         zval copy; \
    1455             :                         int use_copy; \
    1456             :                         zend_make_printable_zval(*tmp, &copy, &use_copy); \
    1457             :                         TRACE_APPEND_STRL(Z_STRVAL(copy), Z_STRLEN(copy)); \
    1458             :                         zval_dtor(&copy); \
    1459             :                 } else { \
    1460             :                 TRACE_APPEND_STRL(Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp));           \
    1461             :                 } \
    1462             :         }
    1463             : /* }}} */
    1464             : 
    1465             : /* {{{ mysqlnd_build_trace_args */
    1466             : static int mysqlnd_build_trace_args(zval **arg TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key)
    1467             : {
    1468             :         char **str;
    1469             :         int *len;
    1470             : 
    1471             :         str = va_arg(args, char**);
    1472             :         len = va_arg(args, int*);
    1473             : 
    1474             :         /* the trivial way would be to do:
    1475             :          * conver_to_string_ex(arg);
    1476             :          * append it and kill the now tmp arg.
    1477             :          * but that could cause some E_NOTICE and also damn long lines.
    1478             :          */
    1479             : 
    1480             :         switch (Z_TYPE_PP(arg)) {
    1481             :                 case IS_NULL:
    1482             :                         TRACE_APPEND_STR("NULL, ");
    1483             :                         break;
    1484             :                 case IS_STRING: {
    1485             :                         int l_added;
    1486             :                         TRACE_APPEND_CHR('\'');
    1487             :                         if (Z_STRLEN_PP(arg) > 15) {
    1488             :                                 TRACE_APPEND_STRL(Z_STRVAL_PP(arg), 15);
    1489             :                                 TRACE_APPEND_STR("...', ");
    1490             :                                 l_added = 15 + 6 + 1; /* +1 because of while (--l_added) */
    1491             :                         } else {
    1492             :                                 l_added = Z_STRLEN_PP(arg);
    1493             :                                 TRACE_APPEND_STRL(Z_STRVAL_PP(arg), l_added);
    1494             :                                 TRACE_APPEND_STR("', ");
    1495             :                                 l_added += 3 + 1;
    1496             :                         }
    1497             :                         while (--l_added) {
    1498             :                                 if ((unsigned char)(*str)[*len - l_added] < 32) {
    1499             :                                         (*str)[*len - l_added] = '?';
    1500             :                                 }
    1501             :                         }
    1502             :                         break;
    1503             :                 }
    1504             :                 case IS_UNICODE: {
    1505             :                         int l_added;
    1506             : 
    1507             :                         /*
    1508             :                          * We do not want to apply current error mode here, since
    1509             :                          * zend_make_printable_zval() uses output encoding converter.
    1510             :                          * Temporarily set output encoding converter to escape offending
    1511             :                          * chars with \uXXXX notation.
    1512             :                          */
    1513             :                         zend_set_converter_error_mode(ZEND_U_CONVERTER(UG(output_encoding_conv)), ZEND_FROM_UNICODE, ZEND_CONV_ERROR_ESCAPE_JAVA);
    1514             :                         TRACE_APPEND_CHR('\'');
    1515             :                         if (Z_USTRLEN_PP(arg) > 15) {
    1516             :                                 TRACE_APPEND_USTRL(Z_USTRVAL_PP(arg), 15);
    1517             :                                 TRACE_APPEND_STR("...', ");
    1518             :                                 l_added = 15 + 6 + 1; /* +1 because of while (--l_added) */
    1519             :                         } else {
    1520             :                                 l_added = Z_USTRLEN_PP(arg);
    1521             :                                 TRACE_APPEND_USTRL(Z_USTRVAL_PP(arg), l_added);
    1522             :                                 TRACE_APPEND_STR("', ");
    1523             :                                 l_added += 3 + 1;
    1524             :                         }
    1525             :                         /*
    1526             :                          * Reset output encoding converter error mode.
    1527             :                          */
    1528             :                         zend_set_converter_error_mode(ZEND_U_CONVERTER(UG(output_encoding_conv)), ZEND_FROM_UNICODE, UG(from_error_mode));
    1529             :                         while (--l_added) {
    1530             :                                 if ((unsigned char)(*str)[*len - l_added] < 32) {
    1531             :                                         (*str)[*len - l_added] = '?';
    1532             :                                 }
    1533             :                         }
    1534             :                         break;
    1535             :                 }
    1536             :                 case IS_BOOL:
    1537             :                         if (Z_LVAL_PP(arg)) {
    1538             :                                 TRACE_APPEND_STR("true, ");
    1539             :                         } else {
    1540             :                                 TRACE_APPEND_STR("false, ");
    1541             :                         }
    1542             :                         break;
    1543             :                 case IS_RESOURCE:
    1544             :                         TRACE_APPEND_STR("Resource id #");
    1545             :                         /* break; */
    1546             :                 case IS_LONG: {
    1547             :                         long lval = Z_LVAL_PP(arg);
    1548             :                         char s_tmp[MAX_LENGTH_OF_LONG + 1];
    1549             :                         int l_tmp = zend_sprintf(s_tmp, "%ld", lval);  /* SAFE */
    1550             :                         TRACE_APPEND_STRL(s_tmp, l_tmp);
    1551             :                         TRACE_APPEND_STR(", ");
    1552             :                         break;
    1553             :                 }
    1554             :                 case IS_DOUBLE: {
    1555             :                         double dval = Z_DVAL_PP(arg);
    1556             :                         char *s_tmp;
    1557             :                         int l_tmp;
    1558             : 
    1559             :                         s_tmp = emalloc(MAX_LENGTH_OF_DOUBLE + EG(precision) + 1);
    1560             :                         l_tmp = zend_sprintf(s_tmp, "%.*G", (int) EG(precision), dval);  /* SAFE */
    1561             :                         TRACE_APPEND_STRL(s_tmp, l_tmp);
    1562             :                         /* %G already handles removing trailing zeros from the fractional part, yay */
    1563             :                         efree(s_tmp);
    1564             :                         TRACE_APPEND_STR(", ");
    1565             :                         break;
    1566             :                 }
    1567             :                 case IS_ARRAY:
    1568             :                         TRACE_APPEND_STR("Array, ");
    1569             :                         break;
    1570             :                 case IS_OBJECT: {
    1571             :                         zval tmp;
    1572             :                         zstr class_name;
    1573             :                         zend_uint class_name_len;
    1574             :                         int dup;
    1575             : 
    1576             :                         TRACE_APPEND_STR("Object(");
    1577             : 
    1578             :                         dup = zend_get_object_classname(*arg, &class_name, &class_name_len TSRMLS_CC);
    1579             : 
    1580             :                         ZVAL_UNICODEL(&tmp, class_name.u, class_name_len, 1);
    1581             :                         convert_to_string_with_converter(&tmp, ZEND_U_CONVERTER(UG(output_encoding_conv)));
    1582             :                         TRACE_APPEND_STRL(Z_STRVAL(tmp), Z_STRLEN(tmp));
    1583             :                         zval_dtor(&tmp);
    1584             : 
    1585             :                         if(!dup) {
    1586             :                                 efree(class_name.v);
    1587             :                         }
    1588             : 
    1589             :                         TRACE_APPEND_STR("), ");
    1590             :                         break;
    1591             :                 }
    1592             :                 default:
    1593             :                         break;
    1594             :         }
    1595             :         return ZEND_HASH_APPLY_KEEP;
    1596             : }
    1597             : /* }}} */
    1598             : 
    1599             : 
    1600             : static int mysqlnd_build_trace_string(zval **frame TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) /* {{{ */
    1601             : {
    1602             :         char *s_tmp, **str;
    1603             :         int *len, *num;
    1604             :         long line;
    1605             :         HashTable *ht = Z_ARRVAL_PP(frame);
    1606             :         zval **file, **tmp;
    1607             :         uint * level;
    1608             : 
    1609             :         level = va_arg(args, uint *);
    1610             :         str = va_arg(args, char**);
    1611             :         len = va_arg(args, int*);
    1612             :         num = va_arg(args, int*);
    1613             : 
    1614             :         if (!*level) {
    1615             :                 return ZEND_HASH_APPLY_KEEP;
    1616             :         }
    1617             :         --*level;
    1618             : 
    1619             :         s_tmp = emalloc(1 + MAX_LENGTH_OF_LONG + 1 + 1);
    1620             :         sprintf(s_tmp, "#%d ", (*num)++);
    1621             :         TRACE_APPEND_STRL(s_tmp, strlen(s_tmp));
    1622             :         efree(s_tmp);
    1623             :         if (zend_ascii_hash_find(ht, "file", sizeof("file"), (void**)&file) == SUCCESS) {
    1624             :                 if (zend_ascii_hash_find(ht, "line", sizeof("line"), (void**)&tmp) == SUCCESS) {
    1625             :                         line = Z_LVAL_PP(tmp);
    1626             :                 } else {
    1627             :                         line = 0;
    1628             :                 }
    1629             :                 TRACE_APPEND_ZVAL(*file);
    1630             :                 s_tmp = emalloc(MAX_LENGTH_OF_LONG + 2 + 1);
    1631             :                 sprintf(s_tmp, "(%ld): ", line);
    1632             :                 TRACE_APPEND_STRL(s_tmp, strlen(s_tmp));
    1633             :                 efree(s_tmp);
    1634             :         } else {
    1635             :                 TRACE_APPEND_STR("[internal function]: ");
    1636             :         }
    1637             :         TRACE_APPEND_KEY("class");
    1638             :         TRACE_APPEND_KEY("type");
    1639             :         TRACE_APPEND_KEY("function");
    1640             :         TRACE_APPEND_CHR('(');
    1641             :         if (zend_ascii_hash_find(ht, "args", sizeof("args"), (void**)&tmp) == SUCCESS) {
    1642             :                 int last_len = *len;
    1643             :                 zend_hash_apply_with_arguments(Z_ARRVAL_PP(tmp) TSRMLS_CC, (apply_func_args_t)mysqlnd_build_trace_args, 2, str, len);
    1644             :                 if (last_len != *len) {
    1645             :                         *len -= 2; /* remove last ', ' */
    1646             :                 }
    1647             :         }
    1648             :         TRACE_APPEND_STR(")\n");
    1649             :         return ZEND_HASH_APPLY_KEEP;
    1650             : }
    1651             : /* }}} */
    1652             : 
    1653             : 
    1654             : #else /* PHP 5*/
    1655             : 
    1656             : 
    1657             : /* {{{ gettraceasstring() macros */
    1658             : #define TRACE_APPEND_CHR(chr)                                            \
    1659             :         *str = (char*)erealloc(*str, *len + 1 + 1);                          \
    1660             :         (*str)[(*len)++] = chr
    1661             : 
    1662             : #define TRACE_APPEND_STRL(val, vallen)                                   \
    1663             :         {                                                                    \
    1664             :                 int l = vallen;                                                  \
    1665             :                 *str = (char*)erealloc(*str, *len + l + 1);                      \
    1666             :                 memcpy((*str) + *len, val, l);                                   \
    1667             :                 *len += l;                                                       \
    1668             :         }
    1669             : 
    1670             : #define TRACE_APPEND_STR(val)                                            \
    1671             :         TRACE_APPEND_STRL(val, sizeof(val)-1)
    1672             : 
    1673             : #define TRACE_APPEND_KEY(key)                                            \
    1674             :         if (zend_hash_find(ht, key, sizeof(key), (void**)&tmp) == SUCCESS) { \
    1675             :             TRACE_APPEND_STRL(Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp));           \
    1676             :         }
    1677             : 
    1678             : /* }}} */
    1679             : 
    1680             : 
    1681           0 : static int mysqlnd_build_trace_args(zval **arg TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) /* {{{ */
    1682             : {
    1683             :         char **str;
    1684             :         int *len;
    1685             : 
    1686           0 :         str = va_arg(args, char**);
    1687           0 :         len = va_arg(args, int*);
    1688             : 
    1689             :         /* the trivial way would be to do:
    1690             :          * conver_to_string_ex(arg);
    1691             :          * append it and kill the now tmp arg.
    1692             :          * but that could cause some E_NOTICE and also damn long lines.
    1693             :          */
    1694             : 
    1695           0 :         switch (Z_TYPE_PP(arg)) {
    1696             :                 case IS_NULL:
    1697           0 :                         TRACE_APPEND_STR("NULL, ");
    1698           0 :                         break;
    1699             :                 case IS_STRING: {
    1700             :                         int l_added;
    1701           0 :                         TRACE_APPEND_CHR('\'');
    1702           0 :                         if (Z_STRLEN_PP(arg) > 15) {
    1703           0 :                                 TRACE_APPEND_STRL(Z_STRVAL_PP(arg), 15);
    1704           0 :                                 TRACE_APPEND_STR("...', ");
    1705           0 :                                 l_added = 15 + 6 + 1; /* +1 because of while (--l_added) */
    1706             :                         } else {
    1707           0 :                                 l_added = Z_STRLEN_PP(arg);
    1708           0 :                                 TRACE_APPEND_STRL(Z_STRVAL_PP(arg), l_added);
    1709           0 :                                 TRACE_APPEND_STR("', ");
    1710           0 :                                 l_added += 3 + 1;
    1711             :                         }
    1712           0 :                         while (--l_added) {
    1713           0 :                                 if ((*str)[*len - l_added] < 32) {
    1714           0 :                                         (*str)[*len - l_added] = '?';
    1715             :                                 }
    1716             :                         }
    1717           0 :                         break;
    1718             :                 }
    1719             :                 case IS_BOOL:
    1720           0 :                         if (Z_LVAL_PP(arg)) {
    1721           0 :                                 TRACE_APPEND_STR("true, ");
    1722             :                         } else {
    1723           0 :                                 TRACE_APPEND_STR("false, ");
    1724             :                         }
    1725           0 :                         break;
    1726             :                 case IS_RESOURCE:
    1727           0 :                         TRACE_APPEND_STR("Resource id #");
    1728             :                         /* break; */
    1729             :                 case IS_LONG: {
    1730           0 :                         long lval = Z_LVAL_PP(arg);
    1731             :                         char s_tmp[MAX_LENGTH_OF_LONG + 1];
    1732           0 :                         int l_tmp = zend_sprintf(s_tmp, "%ld", lval);  /* SAFE */
    1733           0 :                         TRACE_APPEND_STRL(s_tmp, l_tmp);
    1734           0 :                         TRACE_APPEND_STR(", ");
    1735           0 :                         break;
    1736             :                 }
    1737             :                 case IS_DOUBLE: {
    1738           0 :                         double dval = Z_DVAL_PP(arg);
    1739             :                         char *s_tmp;
    1740             :                         int l_tmp;
    1741             : 
    1742           0 :                         s_tmp = emalloc(MAX_LENGTH_OF_DOUBLE + EG(precision) + 1);
    1743           0 :                         l_tmp = zend_sprintf(s_tmp, "%.*G", (int) EG(precision), dval);  /* SAFE */
    1744           0 :                         TRACE_APPEND_STRL(s_tmp, l_tmp);
    1745             :                         /* %G already handles removing trailing zeros from the fractional part, yay */
    1746           0 :                         efree(s_tmp);
    1747           0 :                         TRACE_APPEND_STR(", ");
    1748           0 :                         break;
    1749             :                 }
    1750             :                 case IS_ARRAY:
    1751           0 :                         TRACE_APPEND_STR("Array, ");
    1752           0 :                         break;
    1753             :                 case IS_OBJECT: {
    1754             :                         char *class_name;
    1755             :                         zend_uint class_name_len;
    1756             :                         int dupl;
    1757             : 
    1758           0 :                         TRACE_APPEND_STR("Object(");
    1759             : 
    1760           0 :                         dupl = zend_get_object_classname(*arg, &class_name, &class_name_len TSRMLS_CC);
    1761             : 
    1762           0 :                         TRACE_APPEND_STRL(class_name, class_name_len);
    1763           0 :                         if (!dupl) {
    1764           0 :                                 efree(class_name);
    1765             :                         }
    1766             : 
    1767           0 :                         TRACE_APPEND_STR("), ");
    1768             :                         break;
    1769             :                 }
    1770             :                 default:
    1771             :                         break;
    1772             :         }
    1773           0 :         return ZEND_HASH_APPLY_KEEP;
    1774             : }
    1775             : /* }}} */
    1776             : 
    1777           0 : static int mysqlnd_build_trace_string(zval **frame TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) /* {{{ */
    1778             : {
    1779             :         char *s_tmp, **str;
    1780             :         int *len, *num;
    1781             :         long line;
    1782           0 :         HashTable *ht = Z_ARRVAL_PP(frame);
    1783             :         zval **file, **tmp;
    1784             :         uint * level;
    1785             : 
    1786           0 :         level = va_arg(args, uint *);
    1787           0 :         str = va_arg(args, char**);
    1788           0 :         len = va_arg(args, int*);
    1789           0 :         num = va_arg(args, int*);
    1790             : 
    1791           0 :         if (!*level) {
    1792           0 :                 return ZEND_HASH_APPLY_KEEP;
    1793             :         }
    1794           0 :         --*level;
    1795             : 
    1796           0 :         s_tmp = emalloc(1 + MAX_LENGTH_OF_LONG + 1 + 1);
    1797           0 :         sprintf(s_tmp, "#%d ", (*num)++);
    1798           0 :         TRACE_APPEND_STRL(s_tmp, strlen(s_tmp));
    1799           0 :         efree(s_tmp);
    1800           0 :         if (zend_hash_find(ht, "file", sizeof("file"), (void**)&file) == SUCCESS) {
    1801           0 :                 if (zend_hash_find(ht, "line", sizeof("line"), (void**)&tmp) == SUCCESS) {
    1802           0 :                         line = Z_LVAL_PP(tmp);
    1803             :                 } else {
    1804           0 :                         line = 0;
    1805             :                 }
    1806           0 :                 s_tmp = emalloc(Z_STRLEN_PP(file) + MAX_LENGTH_OF_LONG + 4 + 1);
    1807           0 :                 sprintf(s_tmp, "%s(%ld): ", Z_STRVAL_PP(file), line);
    1808           0 :                 TRACE_APPEND_STRL(s_tmp, strlen(s_tmp));
    1809           0 :                 efree(s_tmp);
    1810             :         } else {
    1811           0 :                 TRACE_APPEND_STR("[internal function]: ");
    1812             :         }
    1813           0 :         TRACE_APPEND_KEY("class");
    1814           0 :         TRACE_APPEND_KEY("type");
    1815           0 :         TRACE_APPEND_KEY("function");
    1816           0 :         TRACE_APPEND_CHR('(');
    1817           0 :         if (zend_hash_find(ht, "args", sizeof("args"), (void**)&tmp) == SUCCESS) {
    1818           0 :                 int last_len = *len;
    1819           0 :                 zend_hash_apply_with_arguments(Z_ARRVAL_PP(tmp) TSRMLS_CC, (apply_func_args_t)mysqlnd_build_trace_args, 2, str, len);
    1820           0 :                 if (last_len != *len) {
    1821           0 :                         *len -= 2; /* remove last ', ' */
    1822             :                 }
    1823             :         }
    1824           0 :         TRACE_APPEND_STR(")\n");
    1825           0 :         return ZEND_HASH_APPLY_KEEP;
    1826             : }
    1827             : /* }}} */
    1828             : #endif
    1829             : 
    1830             : 
    1831           0 : PHPAPI char * mysqlnd_get_backtrace(uint max_levels, size_t * length TSRMLS_DC)
    1832             : {
    1833             :         zval *trace;
    1834           0 :         char *res = estrdup(""), **str = &res, *s_tmp;
    1835           0 :         int res_len = 0, *len = &res_len, num = 0;
    1836           0 :         if (max_levels == 0) {
    1837           0 :                 max_levels = 99999;
    1838             :         }
    1839             : 
    1840           0 :         MAKE_STD_ZVAL(trace);
    1841           0 :         zend_fetch_debug_backtrace(trace, 0, 0 TSRMLS_CC);
    1842             : 
    1843           0 :         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);
    1844           0 :         zval_ptr_dtor(&trace);
    1845             : 
    1846           0 :         if (max_levels) {
    1847           0 :                 s_tmp = emalloc(1 + MAX_LENGTH_OF_LONG + 7 + 1);
    1848           0 :                 sprintf(s_tmp, "#%d {main}", num);
    1849           0 :                 TRACE_APPEND_STRL(s_tmp, strlen(s_tmp));
    1850           0 :                 efree(s_tmp);
    1851             :         }
    1852             : 
    1853           0 :         res[res_len] = '\0';
    1854           0 :         *length = res_len;
    1855             : 
    1856           0 :         return res;
    1857             : }
    1858             : 
    1859             : /*
    1860             :  * Local variables:
    1861             :  * tab-width: 4
    1862             :  * c-basic-offset: 4
    1863             :  * End:
    1864             :  * vim600: noet sw=4 ts=4 fdm=marker
    1865             :  * vim<600: noet sw=4 ts=4
    1866             :  */

Generated by: LCOV version 1.10

Generated at Tue, 08 Apr 2014 11:59:40 +0000 (7 days ago)

Copyright © 2005-2014 The PHP Group
All rights reserved.