1/*
2  +----------------------------------------------------------------------+
3  | PHP Version 7                                                        |
4  +----------------------------------------------------------------------+
5  | Copyright (c) 2006-2016 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: Andrey Hristov <andrey@php.net>                             |
16  |          Ulf Wendel <uw@php.net>                                     |
17  +----------------------------------------------------------------------+
18*/
19
20#include "php.h"
21#include "mysqlnd.h"
22#include "mysqlnd_priv.h"
23#include "mysqlnd_debug.h"
24#include "mysqlnd_wireprotocol.h"
25#include "mysqlnd_statistics.h"
26
27#define MYSQLND_DEBUG_MEMORY 1
28
29static const char mysqlnd_emalloc_name[]	= "_mysqlnd_emalloc";
30static const char mysqlnd_pemalloc_name[]	= "_mysqlnd_pemalloc";
31static const char mysqlnd_ecalloc_name[]	= "_mysqlnd_ecalloc";
32static const char mysqlnd_pecalloc_name[]	= "_mysqlnd_pecalloc";
33static const char mysqlnd_erealloc_name[]	= "_mysqlnd_erealloc";
34static const char mysqlnd_perealloc_name[]	= "_mysqlnd_perealloc";
35static const char mysqlnd_efree_name[]		= "_mysqlnd_efree";
36static const char mysqlnd_pefree_name[]		= "_mysqlnd_pefree";
37static const char mysqlnd_malloc_name[]		= "_mysqlnd_malloc";
38static const char mysqlnd_calloc_name[]		= "_mysqlnd_calloc";
39static const char mysqlnd_realloc_name[]	= "_mysqlnd_realloc";
40static const char mysqlnd_free_name[]		= "_mysqlnd_free";
41static const char mysqlnd_pememdup_name[]	= "_mysqlnd_pememdup";
42static const char mysqlnd_pestrndup_name[]	= "_mysqlnd_pestrndup";
43static const char mysqlnd_pestrdup_name[]	= "_mysqlnd_pestrdup";
44
45PHPAPI const char * mysqlnd_debug_std_no_trace_funcs[] =
46{
47	mysqlnd_emalloc_name,
48	mysqlnd_ecalloc_name,
49	mysqlnd_efree_name,
50	mysqlnd_erealloc_name,
51	mysqlnd_pemalloc_name,
52	mysqlnd_pecalloc_name,
53	mysqlnd_pefree_name,
54	mysqlnd_perealloc_name,
55	mysqlnd_malloc_name,
56	mysqlnd_calloc_name,
57	mysqlnd_realloc_name,
58	mysqlnd_free_name,
59	mysqlnd_pestrndup_name,
60	mysqlnd_read_header_name,
61	mysqlnd_read_body_name,
62	NULL /* must be always last */
63};
64
65#if MYSQLND_DEBUG_MEMORY
66
67
68#if ZEND_DEBUG
69#else
70#define __zend_orig_filename "/unknown/unknown"
71#define __zend_orig_lineno   0
72#endif
73
74#define REAL_SIZE(s) (collect_memory_statistics? (s) + sizeof(size_t) : (s))
75#define REAL_PTR(p) (collect_memory_statistics && (p)? (((char *)(p)) - sizeof(size_t)) : (p))
76#define FAKE_PTR(p) (collect_memory_statistics && (p)? (((char *)(p)) + sizeof(size_t)) : (p))
77
78/* {{{ _mysqlnd_emalloc */
79static void * _mysqlnd_emalloc(size_t size MYSQLND_MEM_D)
80{
81	void *ret;
82	zend_bool collect_memory_statistics = MYSQLND_G(collect_memory_statistics);
83#if PHP_DEBUG
84	zend_long * threshold = &MYSQLND_G(debug_emalloc_fail_threshold);
85#endif
86	TRACE_ALLOC_ENTER(mysqlnd_emalloc_name);
87
88#if PHP_DEBUG
89	{
90		char * fn = strrchr(__zend_filename, PHP_DIR_SEPARATOR);
91		TRACE_ALLOC_INF_FMT("file=%-15s line=%4d", fn? fn + 1:__zend_filename, __zend_lineno);
92	}
93#endif
94
95#if PHP_DEBUG
96	/* -1 is also "true" */
97	if (*threshold) {
98#endif
99		ret = emalloc_rel(REAL_SIZE(size));
100#if PHP_DEBUG
101		--*threshold;
102	} else if (*threshold == 0) {
103		ret = NULL;
104	}
105#endif
106
107	TRACE_ALLOC_INF_FMT("size=%lu ptr=%p", size, ret);
108
109	if (ret && collect_memory_statistics) {
110		*(size_t *) ret = size;
111		MYSQLND_INC_GLOBAL_STATISTIC_W_VALUE2(STAT_MEM_EMALLOC_COUNT, 1, STAT_MEM_EMALLOC_AMOUNT, size);
112	}
113	TRACE_ALLOC_RETURN(FAKE_PTR(ret));
114}
115/* }}} */
116
117
118/* {{{ _mysqlnd_pemalloc */
119static void * _mysqlnd_pemalloc(size_t size, zend_bool persistent MYSQLND_MEM_D)
120{
121	void *ret;
122	zend_bool collect_memory_statistics = MYSQLND_G(collect_memory_statistics);
123#if PHP_DEBUG
124	zend_long * threshold = persistent? &MYSQLND_G(debug_malloc_fail_threshold):&MYSQLND_G(debug_emalloc_fail_threshold);
125#endif
126	TRACE_ALLOC_ENTER(mysqlnd_pemalloc_name);
127
128#if PHP_DEBUG
129	{
130		char * fn = strrchr(__zend_filename, PHP_DIR_SEPARATOR);
131		TRACE_ALLOC_INF_FMT("file=%-15s line=%4d", fn? fn + 1:__zend_filename, __zend_lineno);
132	}
133#endif
134
135#if PHP_DEBUG
136	/* -1 is also "true" */
137	if (*threshold) {
138#endif
139		ret = pemalloc_rel(REAL_SIZE(size), persistent);
140#if PHP_DEBUG
141		--*threshold;
142	} else if (*threshold == 0) {
143		ret = NULL;
144	}
145#endif
146
147	TRACE_ALLOC_INF_FMT("size=%lu ptr=%p persistent=%u", size, ret, persistent);
148
149	if (ret && collect_memory_statistics) {
150		enum mysqlnd_collected_stats s1 = persistent? STAT_MEM_MALLOC_COUNT:STAT_MEM_EMALLOC_COUNT;
151		enum mysqlnd_collected_stats s2 = persistent? STAT_MEM_MALLOC_AMOUNT:STAT_MEM_EMALLOC_AMOUNT;
152		*(size_t *) ret = size;
153		MYSQLND_INC_GLOBAL_STATISTIC_W_VALUE2(s1, 1, s2, size);
154	}
155
156	TRACE_ALLOC_RETURN(FAKE_PTR(ret));
157}
158/* }}} */
159
160
161/* {{{ _mysqlnd_ecalloc */
162static void * _mysqlnd_ecalloc(unsigned int nmemb, size_t size MYSQLND_MEM_D)
163{
164	void *ret;
165	zend_bool collect_memory_statistics = MYSQLND_G(collect_memory_statistics);
166#if PHP_DEBUG
167	zend_long * threshold = &MYSQLND_G(debug_ecalloc_fail_threshold);
168#endif
169	TRACE_ALLOC_ENTER(mysqlnd_ecalloc_name);
170
171#if PHP_DEBUG
172	{
173		char * fn = strrchr(__zend_filename, PHP_DIR_SEPARATOR);
174		TRACE_ALLOC_INF_FMT("file=%-15s line=%4d", fn? fn + 1:__zend_filename, __zend_lineno);
175	}
176#endif
177	TRACE_ALLOC_INF_FMT("before: %lu", zend_memory_usage(FALSE));
178
179#if PHP_DEBUG
180	/* -1 is also "true" */
181	if (*threshold) {
182#endif
183		ret = ecalloc_rel(nmemb, REAL_SIZE(size));
184#if PHP_DEBUG
185		--*threshold;
186	} else if (*threshold == 0) {
187		ret = NULL;
188	}
189#endif
190
191	TRACE_ALLOC_INF_FMT("after : %lu", zend_memory_usage(FALSE));
192	TRACE_ALLOC_INF_FMT("size=%lu ptr=%p", size, ret);
193	if (ret && collect_memory_statistics) {
194		*(size_t *) ret = size;
195		MYSQLND_INC_GLOBAL_STATISTIC_W_VALUE2(STAT_MEM_ECALLOC_COUNT, 1, STAT_MEM_ECALLOC_AMOUNT, size);
196	}
197	TRACE_ALLOC_RETURN(FAKE_PTR(ret));
198}
199/* }}} */
200
201
202/* {{{ _mysqlnd_pecalloc */
203static void * _mysqlnd_pecalloc(unsigned int nmemb, size_t size, zend_bool persistent MYSQLND_MEM_D)
204{
205	void *ret;
206	zend_bool collect_memory_statistics = MYSQLND_G(collect_memory_statistics);
207#if PHP_DEBUG
208	zend_long * threshold = persistent? &MYSQLND_G(debug_calloc_fail_threshold):&MYSQLND_G(debug_ecalloc_fail_threshold);
209#endif
210	TRACE_ALLOC_ENTER(mysqlnd_pecalloc_name);
211#if PHP_DEBUG
212	{
213		char * fn = strrchr(__zend_filename, PHP_DIR_SEPARATOR);
214		TRACE_ALLOC_INF_FMT("file=%-15s line=%4d", fn? fn + 1:__zend_filename, __zend_lineno);
215	}
216#endif
217
218#if PHP_DEBUG
219	/* -1 is also "true" */
220	if (*threshold) {
221#endif
222		ret = pecalloc_rel(nmemb, REAL_SIZE(size), persistent);
223#if PHP_DEBUG
224		--*threshold;
225	} else if (*threshold == 0) {
226		ret = NULL;
227	}
228#endif
229
230	TRACE_ALLOC_INF_FMT("size=%lu ptr=%p", size, ret);
231
232	if (ret && collect_memory_statistics) {
233		enum mysqlnd_collected_stats s1 = persistent? STAT_MEM_CALLOC_COUNT:STAT_MEM_ECALLOC_COUNT;
234		enum mysqlnd_collected_stats s2 = persistent? STAT_MEM_CALLOC_AMOUNT:STAT_MEM_ECALLOC_AMOUNT;
235		*(size_t *) ret = size;
236		MYSQLND_INC_GLOBAL_STATISTIC_W_VALUE2(s1, 1, s2, size);
237	}
238
239	TRACE_ALLOC_RETURN(FAKE_PTR(ret));
240}
241/* }}} */
242
243
244/* {{{ _mysqlnd_erealloc */
245static void * _mysqlnd_erealloc(void *ptr, size_t new_size MYSQLND_MEM_D)
246{
247	void *ret;
248	zend_bool collect_memory_statistics = MYSQLND_G(collect_memory_statistics);
249	size_t old_size = collect_memory_statistics && ptr? *(size_t *) (((char*)ptr) - sizeof(size_t)) : 0;
250#if PHP_DEBUG
251	zend_long * threshold = &MYSQLND_G(debug_erealloc_fail_threshold);
252#endif
253	TRACE_ALLOC_ENTER(mysqlnd_erealloc_name);
254
255#if PHP_DEBUG
256	{
257		char * fn = strrchr(__zend_filename, PHP_DIR_SEPARATOR);
258		TRACE_ALLOC_INF_FMT("file=%-15s line=%4d", fn? fn + 1:__zend_filename, __zend_lineno);
259	}
260#endif
261	TRACE_ALLOC_INF_FMT("ptr=%p old_size=%lu, new_size=%lu", ptr, old_size, new_size);
262
263#if PHP_DEBUG
264	/* -1 is also "true" */
265	if (*threshold) {
266#endif
267		ret = erealloc_rel(REAL_PTR(ptr), REAL_SIZE(new_size));
268#if PHP_DEBUG
269		--*threshold;
270	} else if (*threshold == 0) {
271		ret = NULL;
272	}
273#endif
274
275	TRACE_ALLOC_INF_FMT("new_ptr=%p", (char*)ret);
276	if (ret && collect_memory_statistics) {
277		*(size_t *) ret = new_size;
278		MYSQLND_INC_GLOBAL_STATISTIC_W_VALUE2(STAT_MEM_EREALLOC_COUNT, 1, STAT_MEM_EREALLOC_AMOUNT, new_size);
279	}
280	TRACE_ALLOC_RETURN(FAKE_PTR(ret));
281}
282/* }}} */
283
284
285/* {{{ _mysqlnd_perealloc */
286static void * _mysqlnd_perealloc(void *ptr, size_t new_size, zend_bool persistent MYSQLND_MEM_D)
287{
288	void *ret;
289	zend_bool collect_memory_statistics = MYSQLND_G(collect_memory_statistics);
290	size_t old_size = collect_memory_statistics && ptr? *(size_t *) (((char*)ptr) - sizeof(size_t)) : 0;
291#if PHP_DEBUG
292	zend_long * threshold = persistent? &MYSQLND_G(debug_realloc_fail_threshold):&MYSQLND_G(debug_erealloc_fail_threshold);
293#endif
294	TRACE_ALLOC_ENTER(mysqlnd_perealloc_name);
295
296#if PHP_DEBUG
297	{
298		char * fn = strrchr(__zend_filename, PHP_DIR_SEPARATOR);
299		TRACE_ALLOC_INF_FMT("file=%-15s line=%4d", fn? fn + 1:__zend_filename, __zend_lineno);
300	}
301#endif
302	TRACE_ALLOC_INF_FMT("ptr=%p old_size=%lu new_size=%lu   persistent=%u", ptr, old_size, new_size, persistent);
303
304#if PHP_DEBUG
305	/* -1 is also "true" */
306	if (*threshold) {
307#endif
308		ret = perealloc_rel(REAL_PTR(ptr), REAL_SIZE(new_size), persistent);
309#if PHP_DEBUG
310		--*threshold;
311	} else if (*threshold == 0) {
312		ret = NULL;
313	}
314#endif
315
316	TRACE_ALLOC_INF_FMT("new_ptr=%p", (char*)ret);
317
318	if (ret && collect_memory_statistics) {
319		enum mysqlnd_collected_stats s1 = persistent? STAT_MEM_REALLOC_COUNT:STAT_MEM_EREALLOC_COUNT;
320		enum mysqlnd_collected_stats s2 = persistent? STAT_MEM_REALLOC_AMOUNT:STAT_MEM_EREALLOC_AMOUNT;
321		*(size_t *) ret = new_size;
322		MYSQLND_INC_GLOBAL_STATISTIC_W_VALUE2(s1, 1, s2, new_size);
323	}
324	TRACE_ALLOC_RETURN(FAKE_PTR(ret));
325}
326/* }}} */
327
328
329/* {{{ _mysqlnd_efree */
330static void _mysqlnd_efree(void *ptr MYSQLND_MEM_D)
331{
332	size_t free_amount = 0;
333	zend_bool collect_memory_statistics = MYSQLND_G(collect_memory_statistics);
334	TRACE_ALLOC_ENTER(mysqlnd_efree_name);
335
336#if PHP_DEBUG
337	{
338		char * fn = strrchr(__zend_filename, PHP_DIR_SEPARATOR);
339		TRACE_ALLOC_INF_FMT("file=%-15s line=%4d", fn? fn + 1:__zend_filename, __zend_lineno);
340	}
341#endif
342	TRACE_ALLOC_INF_FMT("ptr=%p", ptr);
343
344	if (ptr) {
345		if (collect_memory_statistics) {
346			free_amount = *(size_t *)(((char*)ptr) - sizeof(size_t));
347			TRACE_ALLOC_INF_FMT("ptr=%p size=%u", ((char*)ptr) - sizeof(size_t), (unsigned int) free_amount);
348		}
349		efree_rel(REAL_PTR(ptr));
350	}
351
352	if (collect_memory_statistics) {
353		MYSQLND_INC_GLOBAL_STATISTIC_W_VALUE2(STAT_MEM_EFREE_COUNT, 1, STAT_MEM_EFREE_AMOUNT, free_amount);
354	}
355	TRACE_ALLOC_VOID_RETURN;
356}
357/* }}} */
358
359
360/* {{{ _mysqlnd_pefree */
361static void _mysqlnd_pefree(void *ptr, zend_bool persistent MYSQLND_MEM_D)
362{
363	size_t free_amount = 0;
364	zend_bool collect_memory_statistics = MYSQLND_G(collect_memory_statistics);
365	TRACE_ALLOC_ENTER(mysqlnd_pefree_name);
366
367#if PHP_DEBUG
368	{
369		char * fn = strrchr(__zend_filename, PHP_DIR_SEPARATOR);
370		TRACE_ALLOC_INF_FMT("file=%-15s line=%4d", fn? fn + 1:__zend_filename, __zend_lineno);
371	}
372#endif
373	TRACE_ALLOC_INF_FMT("ptr=%p persistent=%u", ptr, persistent);
374
375	if (ptr) {
376		if (collect_memory_statistics) {
377			free_amount = *(size_t *)(((char*)ptr) - sizeof(size_t));
378			TRACE_ALLOC_INF_FMT("ptr=%p size=%u", ((char*)ptr) - sizeof(size_t), (unsigned int) free_amount);
379		}
380		pefree_rel(REAL_PTR(ptr), persistent);
381	}
382
383	if (collect_memory_statistics) {
384		MYSQLND_INC_GLOBAL_STATISTIC_W_VALUE2(persistent? STAT_MEM_FREE_COUNT:STAT_MEM_EFREE_COUNT, 1,
385											  persistent? STAT_MEM_FREE_AMOUNT:STAT_MEM_EFREE_AMOUNT, free_amount);
386	}
387	TRACE_ALLOC_VOID_RETURN;
388}
389/* }}} */
390
391
392/* {{{ _mysqlnd_malloc */
393static void * _mysqlnd_malloc(size_t size MYSQLND_MEM_D)
394{
395	void *ret;
396	zend_bool collect_memory_statistics = MYSQLND_G(collect_memory_statistics);
397#if PHP_DEBUG
398	zend_long * threshold = &MYSQLND_G(debug_malloc_fail_threshold);
399#endif
400	TRACE_ALLOC_ENTER(mysqlnd_malloc_name);
401
402#if PHP_DEBUG
403	{
404		char * fn = strrchr(__zend_filename, PHP_DIR_SEPARATOR);
405		TRACE_ALLOC_INF_FMT("file=%-15s line=%4d", fn? fn + 1:__zend_filename, __zend_lineno);
406	}
407#endif
408
409#if PHP_DEBUG
410	/* -1 is also "true" */
411	if (*threshold) {
412#endif
413		ret = malloc(REAL_SIZE(size));
414#if PHP_DEBUG
415		--*threshold;
416	} else if (*threshold == 0) {
417		ret = NULL;
418	}
419#endif
420
421	TRACE_ALLOC_INF_FMT("size=%lu ptr=%p", size, ret);
422	if (ret && collect_memory_statistics) {
423		*(size_t *) ret = size;
424		MYSQLND_INC_GLOBAL_STATISTIC_W_VALUE2(STAT_MEM_MALLOC_COUNT, 1, STAT_MEM_MALLOC_AMOUNT, size);
425	}
426	TRACE_ALLOC_RETURN(FAKE_PTR(ret));
427}
428/* }}} */
429
430
431/* {{{ _mysqlnd_calloc */
432static void * _mysqlnd_calloc(unsigned int nmemb, size_t size MYSQLND_MEM_D)
433{
434	void *ret;
435	zend_bool collect_memory_statistics = MYSQLND_G(collect_memory_statistics);
436#if PHP_DEBUG
437	zend_long * threshold = &MYSQLND_G(debug_calloc_fail_threshold);
438#endif
439	TRACE_ALLOC_ENTER(mysqlnd_calloc_name);
440
441#if PHP_DEBUG
442	{
443		char * fn = strrchr(__zend_filename, PHP_DIR_SEPARATOR);
444		TRACE_ALLOC_INF_FMT("file=%-15s line=%4d", fn? fn + 1:__zend_filename, __zend_lineno);
445	}
446#endif
447
448#if PHP_DEBUG
449	/* -1 is also "true" */
450	if (*threshold) {
451#endif
452		ret = calloc(nmemb, REAL_SIZE(size));
453#if PHP_DEBUG
454		--*threshold;
455	} else if (*threshold == 0) {
456		ret = NULL;
457	}
458#endif
459
460	TRACE_ALLOC_INF_FMT("size=%lu ptr=%p", size, ret);
461	if (ret && collect_memory_statistics) {
462		*(size_t *) ret = size;
463		MYSQLND_INC_GLOBAL_STATISTIC_W_VALUE2(STAT_MEM_CALLOC_COUNT, 1, STAT_MEM_CALLOC_AMOUNT, size);
464	}
465	TRACE_ALLOC_RETURN(FAKE_PTR(ret));
466}
467/* }}} */
468
469
470/* {{{ _mysqlnd_realloc */
471static void * _mysqlnd_realloc(void *ptr, size_t new_size MYSQLND_MEM_D)
472{
473	void *ret;
474	zend_bool collect_memory_statistics = MYSQLND_G(collect_memory_statistics);
475#if PHP_DEBUG
476	zend_long * threshold = &MYSQLND_G(debug_realloc_fail_threshold);
477#endif
478	TRACE_ALLOC_ENTER(mysqlnd_realloc_name);
479
480#if PHP_DEBUG
481	{
482		char * fn = strrchr(__zend_filename, PHP_DIR_SEPARATOR);
483		TRACE_ALLOC_INF_FMT("file=%-15s line=%4d", fn? fn + 1:__zend_filename, __zend_lineno);
484	}
485#endif
486	TRACE_ALLOC_INF_FMT("ptr=%p new_size=%lu ", new_size, ptr);
487	TRACE_ALLOC_INF_FMT("before: %lu", zend_memory_usage(TRUE));
488
489#if PHP_DEBUG
490	/* -1 is also "true" */
491	if (*threshold) {
492#endif
493		ret = realloc(REAL_PTR(ptr), REAL_SIZE(new_size));
494#if PHP_DEBUG
495		--*threshold;
496	} else if (*threshold == 0) {
497		ret = NULL;
498	}
499#endif
500
501	TRACE_ALLOC_INF_FMT("new_ptr=%p", (char*)ret);
502
503	if (ret && collect_memory_statistics) {
504		*(size_t *) ret = new_size;
505		MYSQLND_INC_GLOBAL_STATISTIC_W_VALUE2(STAT_MEM_REALLOC_COUNT, 1, STAT_MEM_REALLOC_AMOUNT, new_size);
506	}
507	TRACE_ALLOC_RETURN(FAKE_PTR(ret));
508}
509/* }}} */
510
511
512/* {{{ _mysqlnd_free */
513static void _mysqlnd_free(void *ptr MYSQLND_MEM_D)
514{
515	size_t free_amount = 0;
516	zend_bool collect_memory_statistics = MYSQLND_G(collect_memory_statistics);
517	TRACE_ALLOC_ENTER(mysqlnd_free_name);
518
519#if PHP_DEBUG
520	{
521		char * fn = strrchr(__zend_filename, PHP_DIR_SEPARATOR);
522		TRACE_ALLOC_INF_FMT("file=%-15s line=%4d", fn? fn + 1:__zend_filename, __zend_lineno);
523	}
524#endif
525	TRACE_ALLOC_INF_FMT("ptr=%p", ptr);
526
527	if (ptr) {
528		if (collect_memory_statistics) {
529			free_amount = *(size_t *)(((char*)ptr) - sizeof(size_t));
530			TRACE_ALLOC_INF_FMT("ptr=%p size=%u", ((char*)ptr) - sizeof(size_t), (unsigned int) free_amount);
531		}
532		free(REAL_PTR(ptr));
533	}
534
535	if (collect_memory_statistics) {
536		MYSQLND_INC_GLOBAL_STATISTIC_W_VALUE2(STAT_MEM_FREE_COUNT, 1, STAT_MEM_FREE_AMOUNT, free_amount);
537	}
538	TRACE_ALLOC_VOID_RETURN;
539}
540/* }}} */
541
542
543/* {{{ _mysqlnd_pememdup */
544static char * _mysqlnd_pememdup(const char * const ptr, size_t length, zend_bool persistent MYSQLND_MEM_D)
545{
546	char * ret;
547	zend_bool collect_memory_statistics = MYSQLND_G(collect_memory_statistics);
548	TRACE_ALLOC_ENTER(mysqlnd_pememdup_name);
549
550#if PHP_DEBUG
551	{
552		char * fn = strrchr(__zend_filename, PHP_DIR_SEPARATOR);
553		TRACE_ALLOC_INF_FMT("file=%-15s line=%4d", fn? fn + 1:__zend_filename, __zend_lineno);
554	}
555#endif
556	TRACE_ALLOC_INF_FMT("ptr=%p", ptr);
557
558	ret = pemalloc_rel(REAL_SIZE(length + 1), persistent);
559	{
560		char * dest = (char *) FAKE_PTR(ret);
561		memcpy(dest, ptr, length);
562	}
563
564	if (collect_memory_statistics) {
565		*(size_t *) ret = length;
566		MYSQLND_INC_GLOBAL_STATISTIC(persistent? STAT_MEM_DUP_COUNT : STAT_MEM_EDUP_COUNT);
567	}
568
569	TRACE_ALLOC_RETURN(FAKE_PTR(ret));
570}
571/* }}} */
572
573
574/* {{{ _mysqlnd_pestrndup */
575static char * _mysqlnd_pestrndup(const char * const ptr, size_t length, zend_bool persistent MYSQLND_MEM_D)
576{
577	char * ret;
578	zend_bool collect_memory_statistics = MYSQLND_G(collect_memory_statistics);
579	TRACE_ALLOC_ENTER(mysqlnd_pestrndup_name);
580
581#if PHP_DEBUG
582	{
583		char * fn = strrchr(__zend_filename, PHP_DIR_SEPARATOR);
584		TRACE_ALLOC_INF_FMT("file=%-15s line=%4d", fn? fn + 1:__zend_filename, __zend_lineno);
585	}
586#endif
587	TRACE_ALLOC_INF_FMT("ptr=%p", ptr);
588
589	ret = pemalloc_rel(REAL_SIZE(length + 1), persistent);
590	{
591		size_t l = length;
592		char * p = (char *) ptr;
593		char * dest = (char *) FAKE_PTR(ret);
594		while (*p && l--) {
595			*dest++ = *p++;
596		}
597		*dest = '\0';
598	}
599
600	if (collect_memory_statistics) {
601		*(size_t *) ret = length;
602		MYSQLND_INC_GLOBAL_STATISTIC(persistent? STAT_MEM_STRNDUP_COUNT : STAT_MEM_ESTRNDUP_COUNT);
603	}
604
605	TRACE_ALLOC_RETURN(FAKE_PTR(ret));
606}
607/* }}} */
608
609
610#define SMART_STR_START_SIZE 2048
611#define SMART_STR_PREALLOC 512
612#include "zend_smart_str.h"
613
614
615/* {{{ _mysqlnd_pestrdup */
616static char * _mysqlnd_pestrdup(const char * const ptr, zend_bool persistent MYSQLND_MEM_D)
617{
618	char * ret;
619	smart_str tmp_str = {0, 0};
620	const char * p = ptr;
621	zend_bool collect_memory_statistics = MYSQLND_G(collect_memory_statistics);
622	TRACE_ALLOC_ENTER(mysqlnd_pestrdup_name);
623#if PHP_DEBUG
624	{
625		char * fn = strrchr(__zend_filename, PHP_DIR_SEPARATOR);
626		TRACE_ALLOC_INF_FMT("file=%-15s line=%4d", fn? fn + 1:__zend_filename, __zend_lineno);
627	}
628#endif
629	TRACE_ALLOC_INF_FMT("ptr=%p", ptr);
630	do {
631		smart_str_appendc(&tmp_str, *p);
632	} while (*p++);
633
634	ret = pemalloc_rel(ZSTR_LEN(tmp_str.s) + sizeof(size_t), persistent);
635	memcpy(FAKE_PTR(ret), ZSTR_VAL(tmp_str.s), ZSTR_LEN(tmp_str.s));
636
637	if (ret && collect_memory_statistics) {
638		*(size_t *) ret = ZSTR_LEN(tmp_str.s);
639		MYSQLND_INC_GLOBAL_STATISTIC(persistent? STAT_MEM_STRDUP_COUNT : STAT_MEM_ESTRDUP_COUNT);
640	}
641	smart_str_free(&tmp_str);
642
643	TRACE_ALLOC_RETURN(FAKE_PTR(ret));
644}
645/* }}} */
646
647
648
649
650#endif /* MYSQLND_DEBUG_MEMORY */
651
652/* {{{ _mysqlnd_sprintf_free */
653static void _mysqlnd_sprintf_free(char * p)
654{
655	efree(p);
656}
657/* }}} */
658
659
660/* {{{ _mysqlnd_sprintf */
661static int _mysqlnd_sprintf(char ** pbuf, size_t max_len, const char *format, ...)
662{
663	int len;
664	va_list ap;
665	va_start(ap, format);
666	len = vspprintf(pbuf, max_len, format, ap);
667	va_end(ap);
668	return len;
669}
670/* }}} */
671
672/* {{{ _mysqlnd_vsprintf */
673static int _mysqlnd_vsprintf(char ** pbuf, size_t max_len, const char * format, va_list ap)
674{
675	return vspprintf(pbuf, max_len, format, ap);
676}
677/* }}} */
678
679
680
681#if MYSQLND_DEBUG_MEMORY == 0
682
683/* {{{ mysqlnd_zend_mm_emalloc */
684static void * mysqlnd_zend_mm_emalloc(size_t size MYSQLND_MEM_D)
685{
686	return emalloc_rel(size);
687}
688/* }}} */
689
690
691/* {{{ mysqlnd_zend_mm_pemalloc */
692static void * mysqlnd_zend_mm_pemalloc(size_t size, zend_bool persistent MYSQLND_MEM_D)
693{
694	return pemalloc_rel(size, persistent);
695}
696/* }}} */
697
698
699/* {{{ mysqlnd_zend_mm_ecalloc */
700static void * mysqlnd_zend_mm_ecalloc(unsigned int nmemb, size_t size MYSQLND_MEM_D)
701{
702	return ecalloc_rel(nmemb, size);
703}
704/* }}} */
705
706
707/* {{{ mysqlnd_zend_mm_pecalloc */
708static void * mysqlnd_zend_mm_pecalloc(unsigned int nmemb, size_t size, zend_bool persistent MYSQLND_MEM_D)
709{
710	return pecalloc_rel(nmemb, size, persistent);
711}
712/* }}} */
713
714
715/* {{{ mysqlnd_zend_mm_erealloc */
716static void * mysqlnd_zend_mm_erealloc(void *ptr, size_t new_size MYSQLND_MEM_D)
717{
718	return erealloc_rel(ptr, new_size);
719}
720/* }}} */
721
722
723/* {{{ mysqlnd_zend_mm_perealloc */
724static void * mysqlnd_zend_mm_perealloc(void *ptr, size_t new_size, zend_bool persistent MYSQLND_MEM_D)
725{
726	return perealloc_rel(ptr, new_size, persistent);
727}
728/* }}} */
729
730
731/* {{{ mysqlnd_zend_mm_efree */
732static void mysqlnd_zend_mm_efree(void * ptr MYSQLND_MEM_D)
733{
734	efree_rel(ptr);
735}
736/* }}} */
737
738
739/* {{{ mysqlnd_zend_mm_pefree */
740static void mysqlnd_zend_mm_pefree(void * ptr, zend_bool persistent MYSQLND_MEM_D)
741{
742	pefree_rel(ptr, persistent);
743}
744/* }}} */
745
746
747/* {{{ mysqlnd_zend_mm_malloc */
748static void * mysqlnd_zend_mm_malloc(size_t size MYSQLND_MEM_D)
749{
750	return malloc(size);
751}
752/* }}} */
753
754
755/* {{{ mysqlnd_zend_mm_calloc */
756static void * mysqlnd_zend_mm_calloc(unsigned int nmemb, size_t size MYSQLND_MEM_D)
757{
758	return calloc(nmemb, size);
759}
760/* }}} */
761
762
763/* {{{ mysqlnd_zend_mm_realloc */
764static void * mysqlnd_zend_mm_realloc(void * ptr, size_t new_size MYSQLND_MEM_D)
765{
766	return realloc(ptr, new_size);
767}
768/* }}} */
769
770
771/* {{{ mysqlnd_zend_mm_free */
772static void mysqlnd_zend_mm_free(void * ptr MYSQLND_MEM_D)
773{
774	free(ptr);
775}
776/* }}} */
777
778
779/* {{{ mysqlnd_zend_mm_pememdup */
780static char * mysqlnd_zend_mm_pememdup(const char * const ptr, size_t length, zend_bool persistent MYSQLND_MEM_D)
781{
782	char * dest = pemalloc_rel(length, persistent);
783	if (dest) {
784		memcpy(dest, ptr, length);
785	}
786	return dest;
787}
788/* }}} */
789
790
791/* {{{ mysqlnd_zend_mm_pestrndup */
792static char * mysqlnd_zend_mm_pestrndup(const char * const ptr, size_t length, zend_bool persistent MYSQLND_MEM_D)
793{
794	return persistent? zend_strndup(ptr, length ) : estrndup_rel(ptr, length);
795}
796/* }}} */
797
798
799/* {{{ mysqlnd_zend_mm_pestrdup */
800static char * mysqlnd_zend_mm_pestrdup(const char * const ptr, zend_bool persistent MYSQLND_MEM_D)
801{
802	return pestrdup_rel(ptr, persistent);
803}
804/* }}} */
805
806#endif
807
808
809PHPAPI struct st_mysqlnd_allocator_methods mysqlnd_allocator =
810{
811#if MYSQLND_DEBUG_MEMORY == 1
812	_mysqlnd_emalloc,
813	_mysqlnd_pemalloc,
814	_mysqlnd_ecalloc,
815	_mysqlnd_pecalloc,
816	_mysqlnd_erealloc,
817	_mysqlnd_perealloc,
818	_mysqlnd_efree,
819	_mysqlnd_pefree,
820	_mysqlnd_malloc,
821	_mysqlnd_calloc,
822	_mysqlnd_realloc,
823	_mysqlnd_free,
824	_mysqlnd_pememdup,
825	_mysqlnd_pestrndup,
826	_mysqlnd_pestrdup,
827	_mysqlnd_sprintf,
828	_mysqlnd_vsprintf,
829	_mysqlnd_sprintf_free
830#else
831	mysqlnd_zend_mm_emalloc,
832	mysqlnd_zend_mm_pemalloc,
833	mysqlnd_zend_mm_ecalloc,
834	mysqlnd_zend_mm_pecalloc,
835	mysqlnd_zend_mm_erealloc,
836	mysqlnd_zend_mm_perealloc,
837	mysqlnd_zend_mm_efree,
838	mysqlnd_zend_mm_pefree,
839	mysqlnd_zend_mm_malloc,
840	mysqlnd_zend_mm_calloc,
841	mysqlnd_zend_mm_realloc,
842	mysqlnd_zend_mm_free,
843	mysqlnd_zend_mm_pememdup,
844	mysqlnd_zend_mm_pestrndup,
845	mysqlnd_zend_mm_pestrdup,
846	_mysqlnd_sprintf,
847	_mysqlnd_vsprintf,
848	_mysqlnd_sprintf_free,
849#endif
850};
851
852
853/*
854 * Local variables:
855 * tab-width: 4
856 * c-basic-offset: 4
857 * End:
858 * vim600: noet sw=4 ts=4 fdm=marker
859 * vim<600: noet sw=4 ts=4
860 */
861