memdebug.c
Go to the documentation of this file.
00001 /***************************************************************************
00002  *                                  _   _ ____  _
00003  *  Project                     ___| | | |  _ \| |
00004  *                             / __| | | | |_) | |
00005  *                            | (__| |_| |  _ <| |___
00006  *                             \___|\___/|_| \_\_____|
00007  *
00008  * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
00009  *
00010  * This software is licensed as described in the file COPYING, which
00011  * you should have received as part of this distribution. The terms
00012  * are also available at https://curl.haxx.se/docs/copyright.html.
00013  *
00014  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
00015  * copies of the Software, and permit persons to whom the Software is
00016  * furnished to do so, under the terms of the COPYING file.
00017  *
00018  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
00019  * KIND, either express or implied.
00020  *
00021  ***************************************************************************/
00022 
00023 #include "curl_setup.h"
00024 
00025 #ifdef CURLDEBUG
00026 
00027 #include <curl/curl.h>
00028 
00029 #include "urldata.h"
00030 
00031 #define MEMDEBUG_NODEFINES /* don't redefine the standard functions */
00032 
00033 /* The last 3 #include files should be in this order */
00034 #include "curl_printf.h"
00035 #include "curl_memory.h"
00036 #include "memdebug.h"
00037 
00038 #ifndef HAVE_ASSERT_H
00039 #  define assert(x) Curl_nop_stmt
00040 #endif
00041 
00042 /*
00043  * Until 2011-08-17 libcurl's Memory Tracking feature also performed
00044  * automatic malloc and free filling operations using 0xA5 and 0x13
00045  * values. Our own preinitialization of dynamically allocated memory
00046  * might be useful when not using third party memory debuggers, but
00047  * on the other hand this would fool memory debuggers into thinking
00048  * that all dynamically allocated memory is properly initialized.
00049  *
00050  * As a default setting, libcurl's Memory Tracking feature no longer
00051  * performs preinitialization of dynamically allocated memory on its
00052  * own. If you know what you are doing, and really want to retain old
00053  * behavior, you can achieve this compiling with preprocessor symbols
00054  * CURL_MT_MALLOC_FILL and CURL_MT_FREE_FILL defined with appropriate
00055  * values.
00056  */
00057 
00058 #ifdef CURL_MT_MALLOC_FILL
00059 # if (CURL_MT_MALLOC_FILL < 0) || (CURL_MT_MALLOC_FILL > 0xff)
00060 #   error "invalid CURL_MT_MALLOC_FILL or out of range"
00061 # endif
00062 #endif
00063 
00064 #ifdef CURL_MT_FREE_FILL
00065 # if (CURL_MT_FREE_FILL < 0) || (CURL_MT_FREE_FILL > 0xff)
00066 #   error "invalid CURL_MT_FREE_FILL or out of range"
00067 # endif
00068 #endif
00069 
00070 #if defined(CURL_MT_MALLOC_FILL) && defined(CURL_MT_FREE_FILL)
00071 # if (CURL_MT_MALLOC_FILL == CURL_MT_FREE_FILL)
00072 #   error "CURL_MT_MALLOC_FILL same as CURL_MT_FREE_FILL"
00073 # endif
00074 #endif
00075 
00076 #ifdef CURL_MT_MALLOC_FILL
00077 #  define mt_malloc_fill(buf,len) memset((buf), CURL_MT_MALLOC_FILL, (len))
00078 #else
00079 #  define mt_malloc_fill(buf,len) Curl_nop_stmt
00080 #endif
00081 
00082 #ifdef CURL_MT_FREE_FILL
00083 #  define mt_free_fill(buf,len) memset((buf), CURL_MT_FREE_FILL, (len))
00084 #else
00085 #  define mt_free_fill(buf,len) Curl_nop_stmt
00086 #endif
00087 
00088 struct memdebug {
00089   size_t size;
00090   union {
00091     curl_off_t o;
00092     double d;
00093     void *p;
00094   } mem[1];
00095   /* I'm hoping this is the thing with the strictest alignment
00096    * requirements.  That also means we waste some space :-( */
00097 };
00098 
00099 /*
00100  * Note that these debug functions are very simple and they are meant to
00101  * remain so. For advanced analysis, record a log file and write perl scripts
00102  * to analyze them!
00103  *
00104  * Don't use these with multithreaded test programs!
00105  */
00106 
00107 #define logfile curl_debuglogfile
00108 FILE *curl_debuglogfile = NULL;
00109 static bool memlimit = FALSE; /* enable memory limit */
00110 static long memsize = 0;  /* set number of mallocs allowed */
00111 
00112 /* this sets the log file name */
00113 void curl_memdebug(const char *logname)
00114 {
00115   if(!logfile) {
00116     if(logname && *logname)
00117       logfile = fopen(logname, FOPEN_WRITETEXT);
00118     else
00119       logfile = stderr;
00120 #ifdef MEMDEBUG_LOG_SYNC
00121     /* Flush the log file after every line so the log isn't lost in a crash */
00122     setbuf(logfile, (char *)NULL);
00123 #endif
00124   }
00125 }
00126 
00127 /* This function sets the number of malloc() calls that should return
00128    successfully! */
00129 void curl_memlimit(long limit)
00130 {
00131   if(!memlimit) {
00132     memlimit = TRUE;
00133     memsize = limit;
00134   }
00135 }
00136 
00137 /* returns TRUE if this isn't allowed! */
00138 static bool countcheck(const char *func, int line, const char *source)
00139 {
00140   /* if source is NULL, then the call is made internally and this check
00141      should not be made */
00142   if(memlimit && source) {
00143     if(!memsize) {
00144       if(source) {
00145         /* log to file */
00146         curl_memlog("LIMIT %s:%d %s reached memlimit\n",
00147                     source, line, func);
00148         /* log to stderr also */
00149         fprintf(stderr, "LIMIT %s:%d %s reached memlimit\n",
00150                 source, line, func);
00151         fflush(logfile); /* because it might crash now */
00152       }
00153       SET_ERRNO(ENOMEM);
00154       return TRUE; /* RETURN ERROR! */
00155     }
00156     else
00157       memsize--; /* countdown */
00158 
00159 
00160   }
00161 
00162   return FALSE; /* allow this */
00163 }
00164 
00165 void *curl_domalloc(size_t wantedsize, int line, const char *source)
00166 {
00167   struct memdebug *mem;
00168   size_t size;
00169 
00170   assert(wantedsize != 0);
00171 
00172   if(countcheck("malloc", line, source))
00173     return NULL;
00174 
00175   /* alloc at least 64 bytes */
00176   size = sizeof(struct memdebug)+wantedsize;
00177 
00178   mem = (Curl_cmalloc)(size);
00179   if(mem) {
00180     /* fill memory with junk */
00181     mt_malloc_fill(mem->mem, wantedsize);
00182     mem->size = wantedsize;
00183   }
00184 
00185   if(source)
00186     curl_memlog("MEM %s:%d malloc(%zu) = %p\n",
00187                 source, line, wantedsize,
00188                 mem ? (void *)mem->mem : (void *)0);
00189 
00190   return (mem ? mem->mem : NULL);
00191 }
00192 
00193 void *curl_docalloc(size_t wanted_elements, size_t wanted_size,
00194                     int line, const char *source)
00195 {
00196   struct memdebug *mem;
00197   size_t size, user_size;
00198 
00199   assert(wanted_elements != 0);
00200   assert(wanted_size != 0);
00201 
00202   if(countcheck("calloc", line, source))
00203     return NULL;
00204 
00205   /* alloc at least 64 bytes */
00206   user_size = wanted_size * wanted_elements;
00207   size = sizeof(struct memdebug) + user_size;
00208 
00209   mem = (Curl_ccalloc)(1, size);
00210   if(mem)
00211     mem->size = user_size;
00212 
00213   if(source)
00214     curl_memlog("MEM %s:%d calloc(%zu,%zu) = %p\n",
00215                 source, line, wanted_elements, wanted_size,
00216                 mem ? (void *)mem->mem : (void *)0);
00217 
00218   return (mem ? mem->mem : NULL);
00219 }
00220 
00221 char *curl_dostrdup(const char *str, int line, const char *source)
00222 {
00223   char *mem;
00224   size_t len;
00225 
00226   assert(str != NULL);
00227 
00228   if(countcheck("strdup", line, source))
00229     return NULL;
00230 
00231   len=strlen(str)+1;
00232 
00233   mem=curl_domalloc(len, 0, NULL); /* NULL prevents logging */
00234   if(mem)
00235     memcpy(mem, str, len);
00236 
00237   if(source)
00238     curl_memlog("MEM %s:%d strdup(%p) (%zu) = %p\n",
00239                 source, line, (void *)str, len, (void *)mem);
00240 
00241   return mem;
00242 }
00243 
00244 #if defined(WIN32) && defined(UNICODE)
00245 wchar_t *curl_dowcsdup(const wchar_t *str, int line, const char *source)
00246 {
00247   wchar_t *mem;
00248   size_t wsiz, bsiz;
00249 
00250   assert(str != NULL);
00251 
00252   if(countcheck("wcsdup", line, source))
00253     return NULL;
00254 
00255   wsiz = wcslen(str) + 1;
00256   bsiz = wsiz * sizeof(wchar_t);
00257 
00258   mem = curl_domalloc(bsiz, 0, NULL); /* NULL prevents logging */
00259   if(mem)
00260     memcpy(mem, str, bsiz);
00261 
00262   if(source)
00263     curl_memlog("MEM %s:%d wcsdup(%p) (%zu) = %p\n",
00264                 source, line, (void *)str, bsiz, (void *)mem);
00265 
00266   return mem;
00267 }
00268 #endif
00269 
00270 /* We provide a realloc() that accepts a NULL as pointer, which then
00271    performs a malloc(). In order to work with ares. */
00272 void *curl_dorealloc(void *ptr, size_t wantedsize,
00273                      int line, const char *source)
00274 {
00275   struct memdebug *mem=NULL;
00276 
00277   size_t size = sizeof(struct memdebug)+wantedsize;
00278 
00279   assert(wantedsize != 0);
00280 
00281   if(countcheck("realloc", line, source))
00282     return NULL;
00283 
00284 #ifdef __INTEL_COMPILER
00285 #  pragma warning(push)
00286 #  pragma warning(disable:1684)
00287    /* 1684: conversion from pointer to same-sized integral type */
00288 #endif
00289 
00290   if(ptr)
00291     mem = (void *)((char *)ptr - offsetof(struct memdebug, mem));
00292 
00293 #ifdef __INTEL_COMPILER
00294 #  pragma warning(pop)
00295 #endif
00296 
00297   mem = (Curl_crealloc)(mem, size);
00298   if(source)
00299     curl_memlog("MEM %s:%d realloc(%p, %zu) = %p\n",
00300                 source, line, (void *)ptr, wantedsize,
00301                 mem ? (void *)mem->mem : (void *)0);
00302 
00303   if(mem) {
00304     mem->size = wantedsize;
00305     return mem->mem;
00306   }
00307 
00308   return NULL;
00309 }
00310 
00311 void curl_dofree(void *ptr, int line, const char *source)
00312 {
00313   struct memdebug *mem;
00314 
00315   if(ptr) {
00316 
00317 #ifdef __INTEL_COMPILER
00318 #  pragma warning(push)
00319 #  pragma warning(disable:1684)
00320    /* 1684: conversion from pointer to same-sized integral type */
00321 #endif
00322 
00323     mem = (void *)((char *)ptr - offsetof(struct memdebug, mem));
00324 
00325 #ifdef __INTEL_COMPILER
00326 #  pragma warning(pop)
00327 #endif
00328 
00329     /* destroy */
00330     mt_free_fill(mem->mem, mem->size);
00331 
00332     /* free for real */
00333     (Curl_cfree)(mem);
00334   }
00335 
00336   if(source)
00337     curl_memlog("MEM %s:%d free(%p)\n", source, line, (void *)ptr);
00338 }
00339 
00340 curl_socket_t curl_socket(int domain, int type, int protocol,
00341                           int line, const char *source)
00342 {
00343   const char *fmt = (sizeof(curl_socket_t) == sizeof(int)) ?
00344     "FD %s:%d socket() = %d\n" :
00345     (sizeof(curl_socket_t) == sizeof(long)) ?
00346     "FD %s:%d socket() = %ld\n" :
00347     "FD %s:%d socket() = %zd\n";
00348 
00349   curl_socket_t sockfd = socket(domain, type, protocol);
00350 
00351   if(source && (sockfd != CURL_SOCKET_BAD))
00352     curl_memlog(fmt, source, line, sockfd);
00353 
00354   return sockfd;
00355 }
00356 
00357 #ifdef HAVE_SOCKETPAIR
00358 int curl_socketpair(int domain, int type, int protocol,
00359                     curl_socket_t socket_vector[2],
00360                     int line, const char *source)
00361 {
00362   const char *fmt = (sizeof(curl_socket_t) == sizeof(int)) ?
00363     "FD %s:%d socketpair() = %d %d\n" :
00364     (sizeof(curl_socket_t) == sizeof(long)) ?
00365     "FD %s:%d socketpair() = %ld %ld\n" :
00366     "FD %s:%d socketpair() = %zd %zd\n";
00367 
00368   int res = socketpair(domain, type, protocol, socket_vector);
00369 
00370   if(source && (0 == res))
00371     curl_memlog(fmt, source, line, socket_vector[0], socket_vector[1]);
00372 
00373   return res;
00374 }
00375 #endif
00376 
00377 curl_socket_t curl_accept(curl_socket_t s, void *saddr, void *saddrlen,
00378                           int line, const char *source)
00379 {
00380   const char *fmt = (sizeof(curl_socket_t) == sizeof(int)) ?
00381     "FD %s:%d accept() = %d\n" :
00382     (sizeof(curl_socket_t) == sizeof(long)) ?
00383     "FD %s:%d accept() = %ld\n" :
00384     "FD %s:%d accept() = %zd\n";
00385 
00386   struct sockaddr *addr = (struct sockaddr *)saddr;
00387   curl_socklen_t *addrlen = (curl_socklen_t *)saddrlen;
00388 
00389   curl_socket_t sockfd = accept(s, addr, addrlen);
00390 
00391   if(source && (sockfd != CURL_SOCKET_BAD))
00392     curl_memlog(fmt, source, line, sockfd);
00393 
00394   return sockfd;
00395 }
00396 
00397 /* separate function to allow libcurl to mark a "faked" close */
00398 void curl_mark_sclose(curl_socket_t sockfd, int line, const char *source)
00399 {
00400   const char *fmt = (sizeof(curl_socket_t) == sizeof(int)) ?
00401     "FD %s:%d sclose(%d)\n":
00402     (sizeof(curl_socket_t) == sizeof(long)) ?
00403     "FD %s:%d sclose(%ld)\n":
00404     "FD %s:%d sclose(%zd)\n";
00405 
00406   if(source)
00407     curl_memlog(fmt, source, line, sockfd);
00408 }
00409 
00410 /* this is our own defined way to close sockets on *ALL* platforms */
00411 int curl_sclose(curl_socket_t sockfd, int line, const char *source)
00412 {
00413   int res=sclose(sockfd);
00414   curl_mark_sclose(sockfd, line, source);
00415   return res;
00416 }
00417 
00418 FILE *curl_fopen(const char *file, const char *mode,
00419                  int line, const char *source)
00420 {
00421   FILE *res=fopen(file, mode);
00422 
00423   if(source)
00424     curl_memlog("FILE %s:%d fopen(\"%s\",\"%s\") = %p\n",
00425                 source, line, file, mode, (void *)res);
00426 
00427   return res;
00428 }
00429 
00430 #ifdef HAVE_FDOPEN
00431 FILE *curl_fdopen(int filedes, const char *mode,
00432                   int line, const char *source)
00433 {
00434   FILE *res=fdopen(filedes, mode);
00435 
00436   if(source)
00437     curl_memlog("FILE %s:%d fdopen(\"%d\",\"%s\") = %p\n",
00438                 source, line, filedes, mode, (void *)res);
00439 
00440   return res;
00441 }
00442 #endif
00443 
00444 int curl_fclose(FILE *file, int line, const char *source)
00445 {
00446   int res;
00447 
00448   assert(file != NULL);
00449 
00450   res=fclose(file);
00451 
00452   if(source)
00453     curl_memlog("FILE %s:%d fclose(%p)\n",
00454                 source, line, (void *)file);
00455 
00456   return res;
00457 }
00458 
00459 #define LOGLINE_BUFSIZE  1024
00460 
00461 /* this does the writting to the memory tracking log file */
00462 void curl_memlog(const char *format, ...)
00463 {
00464   char *buf;
00465   int nchars;
00466   va_list ap;
00467 
00468   if(!logfile)
00469     return;
00470 
00471   buf = (Curl_cmalloc)(LOGLINE_BUFSIZE);
00472   if(!buf)
00473     return;
00474 
00475   va_start(ap, format);
00476   nchars = vsnprintf(buf, LOGLINE_BUFSIZE, format, ap);
00477   va_end(ap);
00478 
00479   if(nchars > LOGLINE_BUFSIZE - 1)
00480     nchars = LOGLINE_BUFSIZE - 1;
00481 
00482   if(nchars > 0)
00483     fwrite(buf, 1, nchars, logfile);
00484 
00485   (Curl_cfree)(buf);
00486 }
00487 
00488 #endif /* CURLDEBUG */


rc_visard_driver
Author(s): Heiko Hirschmueller , Christian Emmerich , Felix Ruess
autogenerated on Thu Jun 6 2019 20:43:05