Annotation of embedaddon/curl/lib/memdebug.c, revision 1.1.1.1
1.1 misho 1: /***************************************************************************
2: * _ _ ____ _
3: * Project ___| | | | _ \| |
4: * / __| | | | |_) | |
5: * | (__| |_| | _ <| |___
6: * \___|\___/|_| \_\_____|
7: *
8: * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
9: *
10: * This software is licensed as described in the file COPYING, which
11: * you should have received as part of this distribution. The terms
12: * are also available at https://curl.haxx.se/docs/copyright.html.
13: *
14: * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15: * copies of the Software, and permit persons to whom the Software is
16: * furnished to do so, under the terms of the COPYING file.
17: *
18: * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19: * KIND, either express or implied.
20: *
21: ***************************************************************************/
22:
23: #include "curl_setup.h"
24:
25: #ifdef CURLDEBUG
26:
27: #include <curl/curl.h>
28:
29: #include "urldata.h"
30:
31: #define MEMDEBUG_NODEFINES /* don't redefine the standard functions */
32:
33: /* The last 3 #include files should be in this order */
34: #include "curl_printf.h"
35: #include "curl_memory.h"
36: #include "memdebug.h"
37:
38: /*
39: * Until 2011-08-17 libcurl's Memory Tracking feature also performed
40: * automatic malloc and free filling operations using 0xA5 and 0x13
41: * values. Our own preinitialization of dynamically allocated memory
42: * might be useful when not using third party memory debuggers, but
43: * on the other hand this would fool memory debuggers into thinking
44: * that all dynamically allocated memory is properly initialized.
45: *
46: * As a default setting, libcurl's Memory Tracking feature no longer
47: * performs preinitialization of dynamically allocated memory on its
48: * own. If you know what you are doing, and really want to retain old
49: * behavior, you can achieve this compiling with preprocessor symbols
50: * CURL_MT_MALLOC_FILL and CURL_MT_FREE_FILL defined with appropriate
51: * values.
52: */
53:
54: #ifdef CURL_MT_MALLOC_FILL
55: # if (CURL_MT_MALLOC_FILL < 0) || (CURL_MT_MALLOC_FILL > 0xff)
56: # error "invalid CURL_MT_MALLOC_FILL or out of range"
57: # endif
58: #endif
59:
60: #ifdef CURL_MT_FREE_FILL
61: # if (CURL_MT_FREE_FILL < 0) || (CURL_MT_FREE_FILL > 0xff)
62: # error "invalid CURL_MT_FREE_FILL or out of range"
63: # endif
64: #endif
65:
66: #if defined(CURL_MT_MALLOC_FILL) && defined(CURL_MT_FREE_FILL)
67: # if (CURL_MT_MALLOC_FILL == CURL_MT_FREE_FILL)
68: # error "CURL_MT_MALLOC_FILL same as CURL_MT_FREE_FILL"
69: # endif
70: #endif
71:
72: #ifdef CURL_MT_MALLOC_FILL
73: # define mt_malloc_fill(buf,len) memset((buf), CURL_MT_MALLOC_FILL, (len))
74: #else
75: # define mt_malloc_fill(buf,len) Curl_nop_stmt
76: #endif
77:
78: #ifdef CURL_MT_FREE_FILL
79: # define mt_free_fill(buf,len) memset((buf), CURL_MT_FREE_FILL, (len))
80: #else
81: # define mt_free_fill(buf,len) Curl_nop_stmt
82: #endif
83:
84: struct memdebug {
85: size_t size;
86: union {
87: curl_off_t o;
88: double d;
89: void *p;
90: } mem[1];
91: /* I'm hoping this is the thing with the strictest alignment
92: * requirements. That also means we waste some space :-( */
93: };
94:
95: /*
96: * Note that these debug functions are very simple and they are meant to
97: * remain so. For advanced analysis, record a log file and write perl scripts
98: * to analyze them!
99: *
100: * Don't use these with multithreaded test programs!
101: */
102:
103: FILE *curl_dbg_logfile = NULL;
104: static bool memlimit = FALSE; /* enable memory limit */
105: static long memsize = 0; /* set number of mallocs allowed */
106:
107: /* this sets the log file name */
108: void curl_dbg_memdebug(const char *logname)
109: {
110: if(!curl_dbg_logfile) {
111: if(logname && *logname)
112: curl_dbg_logfile = fopen(logname, FOPEN_WRITETEXT);
113: else
114: curl_dbg_logfile = stderr;
115: #ifdef MEMDEBUG_LOG_SYNC
116: /* Flush the log file after every line so the log isn't lost in a crash */
117: if(curl_dbg_logfile)
118: setbuf(curl_dbg_logfile, (char *)NULL);
119: #endif
120: }
121: }
122:
123: /* This function sets the number of malloc() calls that should return
124: successfully! */
125: void curl_dbg_memlimit(long limit)
126: {
127: if(!memlimit) {
128: memlimit = TRUE;
129: memsize = limit;
130: }
131: }
132:
133: /* returns TRUE if this isn't allowed! */
134: static bool countcheck(const char *func, int line, const char *source)
135: {
136: /* if source is NULL, then the call is made internally and this check
137: should not be made */
138: if(memlimit && source) {
139: if(!memsize) {
140: if(source) {
141: /* log to file */
142: curl_dbg_log("LIMIT %s:%d %s reached memlimit\n",
143: source, line, func);
144: /* log to stderr also */
145: fprintf(stderr, "LIMIT %s:%d %s reached memlimit\n",
146: source, line, func);
147: fflush(curl_dbg_logfile); /* because it might crash now */
148: }
149: errno = ENOMEM;
150: return TRUE; /* RETURN ERROR! */
151: }
152: else
153: memsize--; /* countdown */
154:
155:
156: }
157:
158: return FALSE; /* allow this */
159: }
160:
161: void *curl_dbg_malloc(size_t wantedsize, int line, const char *source)
162: {
163: struct memdebug *mem;
164: size_t size;
165:
166: DEBUGASSERT(wantedsize != 0);
167:
168: if(countcheck("malloc", line, source))
169: return NULL;
170:
171: /* alloc at least 64 bytes */
172: size = sizeof(struct memdebug) + wantedsize;
173:
174: mem = (Curl_cmalloc)(size);
175: if(mem) {
176: /* fill memory with junk */
177: mt_malloc_fill(mem->mem, wantedsize);
178: mem->size = wantedsize;
179: }
180:
181: if(source)
182: curl_dbg_log("MEM %s:%d malloc(%zu) = %p\n",
183: source, line, wantedsize,
184: mem ? (void *)mem->mem : (void *)0);
185:
186: return (mem ? mem->mem : NULL);
187: }
188:
189: void *curl_dbg_calloc(size_t wanted_elements, size_t wanted_size,
190: int line, const char *source)
191: {
192: struct memdebug *mem;
193: size_t size, user_size;
194:
195: DEBUGASSERT(wanted_elements != 0);
196: DEBUGASSERT(wanted_size != 0);
197:
198: if(countcheck("calloc", line, source))
199: return NULL;
200:
201: /* alloc at least 64 bytes */
202: user_size = wanted_size * wanted_elements;
203: size = sizeof(struct memdebug) + user_size;
204:
205: mem = (Curl_ccalloc)(1, size);
206: if(mem)
207: mem->size = user_size;
208:
209: if(source)
210: curl_dbg_log("MEM %s:%d calloc(%zu,%zu) = %p\n",
211: source, line, wanted_elements, wanted_size,
212: mem ? (void *)mem->mem : (void *)0);
213:
214: return (mem ? mem->mem : NULL);
215: }
216:
217: char *curl_dbg_strdup(const char *str, int line, const char *source)
218: {
219: char *mem;
220: size_t len;
221:
222: DEBUGASSERT(str != NULL);
223:
224: if(countcheck("strdup", line, source))
225: return NULL;
226:
227: len = strlen(str) + 1;
228:
229: mem = curl_dbg_malloc(len, 0, NULL); /* NULL prevents logging */
230: if(mem)
231: memcpy(mem, str, len);
232:
233: if(source)
234: curl_dbg_log("MEM %s:%d strdup(%p) (%zu) = %p\n",
235: source, line, (const void *)str, len, (const void *)mem);
236:
237: return mem;
238: }
239:
240: #if defined(WIN32) && defined(UNICODE)
241: wchar_t *curl_dbg_wcsdup(const wchar_t *str, int line, const char *source)
242: {
243: wchar_t *mem;
244: size_t wsiz, bsiz;
245:
246: DEBUGASSERT(str != NULL);
247:
248: if(countcheck("wcsdup", line, source))
249: return NULL;
250:
251: wsiz = wcslen(str) + 1;
252: bsiz = wsiz * sizeof(wchar_t);
253:
254: mem = curl_dbg_malloc(bsiz, 0, NULL); /* NULL prevents logging */
255: if(mem)
256: memcpy(mem, str, bsiz);
257:
258: if(source)
259: curl_dbg_log("MEM %s:%d wcsdup(%p) (%zu) = %p\n",
260: source, line, (void *)str, bsiz, (void *)mem);
261:
262: return mem;
263: }
264: #endif
265:
266: /* We provide a realloc() that accepts a NULL as pointer, which then
267: performs a malloc(). In order to work with ares. */
268: void *curl_dbg_realloc(void *ptr, size_t wantedsize,
269: int line, const char *source)
270: {
271: struct memdebug *mem = NULL;
272:
273: size_t size = sizeof(struct memdebug) + wantedsize;
274:
275: DEBUGASSERT(wantedsize != 0);
276:
277: if(countcheck("realloc", line, source))
278: return NULL;
279:
280: #ifdef __INTEL_COMPILER
281: # pragma warning(push)
282: # pragma warning(disable:1684)
283: /* 1684: conversion from pointer to same-sized integral type */
284: #endif
285:
286: if(ptr)
287: mem = (void *)((char *)ptr - offsetof(struct memdebug, mem));
288:
289: #ifdef __INTEL_COMPILER
290: # pragma warning(pop)
291: #endif
292:
293: mem = (Curl_crealloc)(mem, size);
294: if(source)
295: curl_dbg_log("MEM %s:%d realloc(%p, %zu) = %p\n",
296: source, line, (void *)ptr, wantedsize,
297: mem ? (void *)mem->mem : (void *)0);
298:
299: if(mem) {
300: mem->size = wantedsize;
301: return mem->mem;
302: }
303:
304: return NULL;
305: }
306:
307: void curl_dbg_free(void *ptr, int line, const char *source)
308: {
309: if(ptr) {
310: struct memdebug *mem;
311:
312: #ifdef __INTEL_COMPILER
313: # pragma warning(push)
314: # pragma warning(disable:1684)
315: /* 1684: conversion from pointer to same-sized integral type */
316: #endif
317:
318: mem = (void *)((char *)ptr - offsetof(struct memdebug, mem));
319:
320: #ifdef __INTEL_COMPILER
321: # pragma warning(pop)
322: #endif
323:
324: /* destroy */
325: mt_free_fill(mem->mem, mem->size);
326:
327: /* free for real */
328: (Curl_cfree)(mem);
329: }
330:
331: if(source && ptr)
332: curl_dbg_log("MEM %s:%d free(%p)\n", source, line, (void *)ptr);
333: }
334:
335: curl_socket_t curl_dbg_socket(int domain, int type, int protocol,
336: int line, const char *source)
337: {
338: const char *fmt = (sizeof(curl_socket_t) == sizeof(int)) ?
339: "FD %s:%d socket() = %d\n" :
340: (sizeof(curl_socket_t) == sizeof(long)) ?
341: "FD %s:%d socket() = %ld\n" :
342: "FD %s:%d socket() = %zd\n";
343:
344: curl_socket_t sockfd;
345:
346: if(countcheck("socket", line, source))
347: return CURL_SOCKET_BAD;
348:
349: sockfd = socket(domain, type, protocol);
350:
351: if(source && (sockfd != CURL_SOCKET_BAD))
352: curl_dbg_log(fmt, source, line, sockfd);
353:
354: return sockfd;
355: }
356:
357: SEND_TYPE_RETV curl_dbg_send(SEND_TYPE_ARG1 sockfd,
358: SEND_QUAL_ARG2 SEND_TYPE_ARG2 buf,
359: SEND_TYPE_ARG3 len, SEND_TYPE_ARG4 flags, int line,
360: const char *source)
361: {
362: SEND_TYPE_RETV rc;
363: if(countcheck("send", line, source))
364: return -1;
365: rc = send(sockfd, buf, len, flags);
366: if(source)
367: curl_dbg_log("SEND %s:%d send(%lu) = %ld\n",
368: source, line, (unsigned long)len, (long)rc);
369: return rc;
370: }
371:
372: RECV_TYPE_RETV curl_dbg_recv(RECV_TYPE_ARG1 sockfd, RECV_TYPE_ARG2 buf,
373: RECV_TYPE_ARG3 len, RECV_TYPE_ARG4 flags, int line,
374: const char *source)
375: {
376: RECV_TYPE_RETV rc;
377: if(countcheck("recv", line, source))
378: return -1;
379: rc = recv(sockfd, buf, len, flags);
380: if(source)
381: curl_dbg_log("RECV %s:%d recv(%lu) = %ld\n",
382: source, line, (unsigned long)len, (long)rc);
383: return rc;
384: }
385:
386: #ifdef HAVE_SOCKETPAIR
387: int curl_dbg_socketpair(int domain, int type, int protocol,
388: curl_socket_t socket_vector[2],
389: int line, const char *source)
390: {
391: const char *fmt = (sizeof(curl_socket_t) == sizeof(int)) ?
392: "FD %s:%d socketpair() = %d %d\n" :
393: (sizeof(curl_socket_t) == sizeof(long)) ?
394: "FD %s:%d socketpair() = %ld %ld\n" :
395: "FD %s:%d socketpair() = %zd %zd\n";
396:
397: int res = socketpair(domain, type, protocol, socket_vector);
398:
399: if(source && (0 == res))
400: curl_dbg_log(fmt, source, line, socket_vector[0], socket_vector[1]);
401:
402: return res;
403: }
404: #endif
405:
406: curl_socket_t curl_dbg_accept(curl_socket_t s, void *saddr, void *saddrlen,
407: int line, const char *source)
408: {
409: const char *fmt = (sizeof(curl_socket_t) == sizeof(int)) ?
410: "FD %s:%d accept() = %d\n" :
411: (sizeof(curl_socket_t) == sizeof(long)) ?
412: "FD %s:%d accept() = %ld\n" :
413: "FD %s:%d accept() = %zd\n";
414:
415: struct sockaddr *addr = (struct sockaddr *)saddr;
416: curl_socklen_t *addrlen = (curl_socklen_t *)saddrlen;
417:
418: curl_socket_t sockfd = accept(s, addr, addrlen);
419:
420: if(source && (sockfd != CURL_SOCKET_BAD))
421: curl_dbg_log(fmt, source, line, sockfd);
422:
423: return sockfd;
424: }
425:
426: /* separate function to allow libcurl to mark a "faked" close */
427: void curl_dbg_mark_sclose(curl_socket_t sockfd, int line, const char *source)
428: {
429: const char *fmt = (sizeof(curl_socket_t) == sizeof(int)) ?
430: "FD %s:%d sclose(%d)\n":
431: (sizeof(curl_socket_t) == sizeof(long)) ?
432: "FD %s:%d sclose(%ld)\n":
433: "FD %s:%d sclose(%zd)\n";
434:
435: if(source)
436: curl_dbg_log(fmt, source, line, sockfd);
437: }
438:
439: /* this is our own defined way to close sockets on *ALL* platforms */
440: int curl_dbg_sclose(curl_socket_t sockfd, int line, const char *source)
441: {
442: int res = sclose(sockfd);
443: curl_dbg_mark_sclose(sockfd, line, source);
444: return res;
445: }
446:
447: FILE *curl_dbg_fopen(const char *file, const char *mode,
448: int line, const char *source)
449: {
450: FILE *res = fopen(file, mode);
451:
452: if(source)
453: curl_dbg_log("FILE %s:%d fopen(\"%s\",\"%s\") = %p\n",
454: source, line, file, mode, (void *)res);
455:
456: return res;
457: }
458:
459: int curl_dbg_fclose(FILE *file, int line, const char *source)
460: {
461: int res;
462:
463: DEBUGASSERT(file != NULL);
464:
465: if(source)
466: curl_dbg_log("FILE %s:%d fclose(%p)\n",
467: source, line, (void *)file);
468:
469: res = fclose(file);
470:
471: return res;
472: }
473:
474: #define LOGLINE_BUFSIZE 1024
475:
476: /* this does the writing to the memory tracking log file */
477: void curl_dbg_log(const char *format, ...)
478: {
479: char *buf;
480: int nchars;
481: va_list ap;
482:
483: if(!curl_dbg_logfile)
484: return;
485:
486: buf = (Curl_cmalloc)(LOGLINE_BUFSIZE);
487: if(!buf)
488: return;
489:
490: va_start(ap, format);
491: nchars = mvsnprintf(buf, LOGLINE_BUFSIZE, format, ap);
492: va_end(ap);
493:
494: if(nchars > LOGLINE_BUFSIZE - 1)
495: nchars = LOGLINE_BUFSIZE - 1;
496:
497: if(nchars > 0)
498: fwrite(buf, 1, (size_t)nchars, curl_dbg_logfile);
499:
500: (Curl_cfree)(buf);
501: }
502:
503: #endif /* CURLDEBUG */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>