File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / curl / lib / memdebug.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Jun 3 10:01:15 2020 UTC (4 years, 1 month ago) by misho
Branches: curl, MAIN
CVS tags: v7_70_0p4, HEAD
curl

    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>