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>