Annotation of embedaddon/curl/lib/memdebug.c, revision 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>