1/*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) 1998 - 2010, 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 http://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 "setup.h" 24 25#ifdef CURLDEBUG 26#include <curl/curl.h> 27 28#ifdef HAVE_SYS_SOCKET_H 29#include <sys/socket.h> 30#endif 31 32#define _MPRINTF_REPLACE 33#include <curl/mprintf.h> 34#include "urldata.h" 35#include <stdio.h> 36#include <string.h> 37#include <stdlib.h> 38#include <stdarg.h> 39 40#ifdef HAVE_UNISTD_H 41#include <unistd.h> 42#endif 43 44#define MEMDEBUG_NODEFINES /* don't redefine the standard functions */ 45#include "curl_memory.h" 46#include "memdebug.h" 47 48#ifndef HAVE_ASSERT_H 49# define assert(x) do { } while (0) 50#endif 51 52struct memdebug { 53 size_t size; 54 union { 55 double d; 56 void * p; 57 } mem[1]; 58 /* I'm hoping this is the thing with the strictest alignment 59 * requirements. That also means we waste some space :-( */ 60}; 61 62/* 63 * Note that these debug functions are very simple and they are meant to 64 * remain so. For advanced analysis, record a log file and write perl scripts 65 * to analyze them! 66 * 67 * Don't use these with multithreaded test programs! 68 */ 69 70#define logfile curl_debuglogfile 71FILE *curl_debuglogfile = NULL; 72static bool memlimit = FALSE; /* enable memory limit */ 73static long memsize = 0; /* set number of mallocs allowed */ 74 75/* this sets the log file name */ 76void curl_memdebug(const char *logname) 77{ 78 if(!logfile) { 79 if(logname) 80 logfile = fopen(logname, "w"); 81 else 82 logfile = stderr; 83#ifdef MEMDEBUG_LOG_SYNC 84 /* Flush the log file after every line so the log isn't lost in a crash */ 85 setvbuf(logfile, (char *)NULL, _IOLBF, 0); 86#endif 87 } 88} 89 90/* This function sets the number of malloc() calls that should return 91 successfully! */ 92void curl_memlimit(long limit) 93{ 94 if(!memlimit) { 95 memlimit = TRUE; 96 memsize = limit; 97 } 98} 99 100/* returns TRUE if this isn't allowed! */ 101static bool countcheck(const char *func, int line, const char *source) 102{ 103 /* if source is NULL, then the call is made internally and this check 104 should not be made */ 105 if(memlimit && source) { 106 if(!memsize) { 107 if(source) { 108 /* log to file */ 109 curl_memlog("LIMIT %s:%d %s reached memlimit\n", 110 source, line, func); 111 /* log to stderr also */ 112 fprintf(stderr, "LIMIT %s:%d %s reached memlimit\n", 113 source, line, func); 114 } 115 SET_ERRNO(ENOMEM); 116 return TRUE; /* RETURN ERROR! */ 117 } 118 else 119 memsize--; /* countdown */ 120 121 /* log the countdown */ 122 if(source) 123 curl_memlog("LIMIT %s:%d %ld ALLOCS left\n", 124 source, line, memsize); 125 126 } 127 128 return FALSE; /* allow this */ 129} 130 131void *curl_domalloc(size_t wantedsize, int line, const char *source) 132{ 133 struct memdebug *mem; 134 size_t size; 135 136 assert(wantedsize != 0); 137 138 if(countcheck("malloc", line, source)) 139 return NULL; 140 141 /* alloc at least 64 bytes */ 142 size = sizeof(struct memdebug)+wantedsize; 143 144 mem = (Curl_cmalloc)(size); 145 if(mem) { 146 /* fill memory with junk */ 147 memset(mem->mem, 0xA5, wantedsize); 148 mem->size = wantedsize; 149 } 150 151 if(source) 152 curl_memlog("MEM %s:%d malloc(%zd) = %p\n", 153 source, line, wantedsize, mem ? mem->mem : 0); 154 return (mem ? mem->mem : NULL); 155} 156 157void *curl_docalloc(size_t wanted_elements, size_t wanted_size, 158 int line, const char *source) 159{ 160 struct memdebug *mem; 161 size_t size, user_size; 162 163 assert(wanted_elements != 0); 164 assert(wanted_size != 0); 165 166 if(countcheck("calloc", line, source)) 167 return NULL; 168 169 /* alloc at least 64 bytes */ 170 user_size = wanted_size * wanted_elements; 171 size = sizeof(struct memdebug) + user_size; 172 173 mem = (Curl_cmalloc)(size); 174 if(mem) { 175 /* fill memory with zeroes */ 176 memset(mem->mem, 0, user_size); 177 mem->size = user_size; 178 } 179 180 if(source) 181 curl_memlog("MEM %s:%d calloc(%zu,%zu) = %p\n", 182 source, line, wanted_elements, wanted_size, mem?mem->mem:0); 183 return (mem ? mem->mem : NULL); 184} 185 186char *curl_dostrdup(const char *str, int line, const char *source) 187{ 188 char *mem; 189 size_t len; 190 191 assert(str != NULL); 192 193 if(countcheck("strdup", line, source)) 194 return NULL; 195 196 len=strlen(str)+1; 197 198 mem=curl_domalloc(len, 0, NULL); /* NULL prevents logging */ 199 if(mem) 200 memcpy(mem, str, len); 201 202 if(source) 203 curl_memlog("MEM %s:%d strdup(%p) (%zu) = %p\n", 204 source, line, str, len, mem); 205 206 return mem; 207} 208 209/* We provide a realloc() that accepts a NULL as pointer, which then 210 performs a malloc(). In order to work with ares. */ 211void *curl_dorealloc(void *ptr, size_t wantedsize, 212 int line, const char *source) 213{ 214 struct memdebug *mem=NULL; 215 216 size_t size = sizeof(struct memdebug)+wantedsize; 217 218 assert(wantedsize != 0); 219 220 if(countcheck("realloc", line, source)) 221 return NULL; 222 223#ifdef __INTEL_COMPILER 224# pragma warning(push) 225# pragma warning(disable:1684) 226 /* 1684: conversion from pointer to same-sized integral type */ 227#endif 228 229 if(ptr) 230 mem = (void *)((char *)ptr - offsetof(struct memdebug, mem)); 231 232#ifdef __INTEL_COMPILER 233# pragma warning(pop) 234#endif 235 236 mem = (Curl_crealloc)(mem, size); 237 if(source) 238 curl_memlog("MEM %s:%d realloc(%p, %zu) = %p\n", 239 source, line, ptr, wantedsize, mem?mem->mem:NULL); 240 241 if(mem) { 242 mem->size = wantedsize; 243 return mem->mem; 244 } 245 246 return NULL; 247} 248 249void curl_dofree(void *ptr, int line, const char *source) 250{ 251 struct memdebug *mem; 252 253 assert(ptr != NULL); 254 255#ifdef __INTEL_COMPILER 256# pragma warning(push) 257# pragma warning(disable:1684) 258 /* 1684: conversion from pointer to same-sized integral type */ 259#endif 260 261 mem = (void *)((char *)ptr - offsetof(struct memdebug, mem)); 262 263#ifdef __INTEL_COMPILER 264# pragma warning(pop) 265#endif 266 267 /* destroy */ 268 memset(mem->mem, 0x13, mem->size); 269 270 /* free for real */ 271 (Curl_cfree)(mem); 272 273 if(source) 274 curl_memlog("MEM %s:%d free(%p)\n", source, line, ptr); 275} 276 277curl_socket_t curl_socket(int domain, int type, int protocol, 278 int line, const char *source) 279{ 280 const char *fmt = (sizeof(curl_socket_t) == sizeof(int)) ? 281 "FD %s:%d socket() = %d\n" : 282 (sizeof(curl_socket_t) == sizeof(long)) ? 283 "FD %s:%d socket() = %ld\n" : 284 "FD %s:%d socket() = %zd\n" ; 285 286 curl_socket_t sockfd = socket(domain, type, protocol); 287 if(source && (sockfd != CURL_SOCKET_BAD)) 288 curl_memlog(fmt, source, line, sockfd); 289 return sockfd; 290} 291 292curl_socket_t curl_accept(curl_socket_t s, void *saddr, void *saddrlen, 293 int line, const char *source) 294{ 295 const char *fmt = (sizeof(curl_socket_t) == sizeof(int)) ? 296 "FD %s:%d accept() = %d\n" : 297 (sizeof(curl_socket_t) == sizeof(long)) ? 298 "FD %s:%d accept() = %ld\n" : 299 "FD %s:%d accept() = %zd\n" ; 300 301 struct sockaddr *addr = (struct sockaddr *)saddr; 302 curl_socklen_t *addrlen = (curl_socklen_t *)saddrlen; 303 curl_socket_t sockfd = accept(s, addr, addrlen); 304 if(source && (sockfd != CURL_SOCKET_BAD)) 305 curl_memlog(fmt, source, line, sockfd); 306 return sockfd; 307} 308 309/* separate function to allow libcurl to mark a "faked" close */ 310void curl_mark_sclose(curl_socket_t sockfd, int line, const char *source) 311{ 312 const char *fmt = (sizeof(curl_socket_t) == sizeof(int)) ? 313 "FD %s:%d sclose(%d)\n" : 314 (sizeof(curl_socket_t) == sizeof(long)) ? 315 "FD %s:%d sclose(%ld)\n" : 316 "FD %s:%d sclose(%zd)\n" ; 317 318 if(source) 319 curl_memlog(fmt, source, line, sockfd); 320} 321 322/* this is our own defined way to close sockets on *ALL* platforms */ 323int curl_sclose(curl_socket_t sockfd, int line, const char *source) 324{ 325 int res=sclose(sockfd); 326 curl_mark_sclose(sockfd, line, source); 327 return res; 328} 329 330FILE *curl_fopen(const char *file, const char *mode, 331 int line, const char *source) 332{ 333 FILE *res=fopen(file, mode); 334 if(source) 335 curl_memlog("FILE %s:%d fopen(\"%s\",\"%s\") = %p\n", 336 source, line, file, mode, res); 337 return res; 338} 339 340#ifdef HAVE_FDOPEN 341FILE *curl_fdopen(int filedes, const char *mode, 342 int line, const char *source) 343{ 344 FILE *res=fdopen(filedes, mode); 345 if(source) 346 curl_memlog("FILE %s:%d fdopen(\"%d\",\"%s\") = %p\n", 347 source, line, filedes, mode, res); 348 return res; 349} 350#endif 351 352int curl_fclose(FILE *file, int line, const char *source) 353{ 354 int res; 355 356 assert(file != NULL); 357 358 res=fclose(file); 359 if(source) 360 curl_memlog("FILE %s:%d fclose(%p)\n", 361 source, line, file); 362 return res; 363} 364 365#define LOGLINE_BUFSIZE 1024 366 367/* this does the writting to the memory tracking log file */ 368void curl_memlog(const char *format, ...) 369{ 370 char *buf; 371 int nchars; 372 va_list ap; 373 374 if(!logfile) 375 return; 376 377 buf = (Curl_cmalloc)(LOGLINE_BUFSIZE); 378 if(!buf) 379 return; 380 381 va_start(ap, format); 382 nchars = vsnprintf(buf, LOGLINE_BUFSIZE, format, ap); 383 va_end(ap); 384 385 if(nchars > LOGLINE_BUFSIZE - 1) 386 nchars = LOGLINE_BUFSIZE - 1; 387 388 if(nchars > 0) 389 fwrite(buf, 1, nchars, logfile); 390 391 (Curl_cfree)(buf); 392} 393 394#endif /* CURLDEBUG */ 395