[337] | 1 | /***************************************************************************
|
---|
| 2 | * _ _ ____ _
|
---|
| 3 | * Project ___| | | | _ \| |
|
---|
| 4 | * / __| | | | |_) | |
|
---|
| 5 | * | (__| |_| | _ <| |___
|
---|
| 6 | * \___|\___/|_| \_\_____|
|
---|
| 7 | *
|
---|
| 8 | * Copyright (C) 1998 - 2017, 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 | #define logfile curl_debuglogfile
|
---|
| 104 | FILE *curl_debuglogfile = NULL;
|
---|
| 105 | static bool memlimit = FALSE; /* enable memory limit */
|
---|
| 106 | static long memsize = 0; /* set number of mallocs allowed */
|
---|
| 107 |
|
---|
| 108 | /* this sets the log file name */
|
---|
| 109 | void curl_memdebug(const char *logname)
|
---|
| 110 | {
|
---|
| 111 | if(!logfile) {
|
---|
| 112 | if(logname && *logname)
|
---|
| 113 | logfile = fopen(logname, FOPEN_WRITETEXT);
|
---|
| 114 | else
|
---|
| 115 | logfile = stderr;
|
---|
| 116 | #ifdef MEMDEBUG_LOG_SYNC
|
---|
| 117 | /* Flush the log file after every line so the log isn't lost in a crash */
|
---|
| 118 | if(logfile)
|
---|
| 119 | setbuf(logfile, (char *)NULL);
|
---|
| 120 | #endif
|
---|
| 121 | }
|
---|
| 122 | }
|
---|
| 123 |
|
---|
| 124 | /* This function sets the number of malloc() calls that should return
|
---|
| 125 | successfully! */
|
---|
| 126 | void curl_memlimit(long limit)
|
---|
| 127 | {
|
---|
| 128 | if(!memlimit) {
|
---|
| 129 | memlimit = TRUE;
|
---|
| 130 | memsize = limit;
|
---|
| 131 | }
|
---|
| 132 | }
|
---|
| 133 |
|
---|
| 134 | /* returns TRUE if this isn't allowed! */
|
---|
| 135 | static bool countcheck(const char *func, int line, const char *source)
|
---|
| 136 | {
|
---|
| 137 | /* if source is NULL, then the call is made internally and this check
|
---|
| 138 | should not be made */
|
---|
| 139 | if(memlimit && source) {
|
---|
| 140 | if(!memsize) {
|
---|
| 141 | if(source) {
|
---|
| 142 | /* log to file */
|
---|
| 143 | curl_memlog("LIMIT %s:%d %s reached memlimit\n",
|
---|
| 144 | source, line, func);
|
---|
| 145 | /* log to stderr also */
|
---|
| 146 | fprintf(stderr, "LIMIT %s:%d %s reached memlimit\n",
|
---|
| 147 | source, line, func);
|
---|
| 148 | fflush(logfile); /* because it might crash now */
|
---|
| 149 | }
|
---|
| 150 | errno = ENOMEM;
|
---|
| 151 | return TRUE; /* RETURN ERROR! */
|
---|
| 152 | }
|
---|
| 153 | else
|
---|
| 154 | memsize--; /* countdown */
|
---|
| 155 |
|
---|
| 156 |
|
---|
| 157 | }
|
---|
| 158 |
|
---|
| 159 | return FALSE; /* allow this */
|
---|
| 160 | }
|
---|
| 161 |
|
---|
| 162 | void *curl_domalloc(size_t wantedsize, int line, const char *source)
|
---|
| 163 | {
|
---|
| 164 | struct memdebug *mem;
|
---|
| 165 | size_t size;
|
---|
| 166 |
|
---|
| 167 | DEBUGASSERT(wantedsize != 0);
|
---|
| 168 |
|
---|
| 169 | if(countcheck("malloc", line, source))
|
---|
| 170 | return NULL;
|
---|
| 171 |
|
---|
| 172 | /* alloc at least 64 bytes */
|
---|
| 173 | size = sizeof(struct memdebug) + wantedsize;
|
---|
| 174 |
|
---|
| 175 | mem = (Curl_cmalloc)(size);
|
---|
| 176 | if(mem) {
|
---|
| 177 | /* fill memory with junk */
|
---|
| 178 | mt_malloc_fill(mem->mem, wantedsize);
|
---|
| 179 | mem->size = wantedsize;
|
---|
| 180 | }
|
---|
| 181 |
|
---|
| 182 | if(source)
|
---|
| 183 | curl_memlog("MEM %s:%d malloc(%zu) = %p\n",
|
---|
| 184 | source, line, wantedsize,
|
---|
| 185 | mem ? (void *)mem->mem : (void *)0);
|
---|
| 186 |
|
---|
| 187 | return (mem ? mem->mem : NULL);
|
---|
| 188 | }
|
---|
| 189 |
|
---|
| 190 | void *curl_docalloc(size_t wanted_elements, size_t wanted_size,
|
---|
| 191 | int line, const char *source)
|
---|
| 192 | {
|
---|
| 193 | struct memdebug *mem;
|
---|
| 194 | size_t size, user_size;
|
---|
| 195 |
|
---|
| 196 | DEBUGASSERT(wanted_elements != 0);
|
---|
| 197 | DEBUGASSERT(wanted_size != 0);
|
---|
| 198 |
|
---|
| 199 | if(countcheck("calloc", line, source))
|
---|
| 200 | return NULL;
|
---|
| 201 |
|
---|
| 202 | /* alloc at least 64 bytes */
|
---|
| 203 | user_size = wanted_size * wanted_elements;
|
---|
| 204 | size = sizeof(struct memdebug) + user_size;
|
---|
| 205 |
|
---|
| 206 | mem = (Curl_ccalloc)(1, size);
|
---|
| 207 | if(mem)
|
---|
| 208 | mem->size = user_size;
|
---|
| 209 |
|
---|
| 210 | if(source)
|
---|
| 211 | curl_memlog("MEM %s:%d calloc(%zu,%zu) = %p\n",
|
---|
| 212 | source, line, wanted_elements, wanted_size,
|
---|
| 213 | mem ? (void *)mem->mem : (void *)0);
|
---|
| 214 |
|
---|
| 215 | return (mem ? mem->mem : NULL);
|
---|
| 216 | }
|
---|
| 217 |
|
---|
| 218 | char *curl_dostrdup(const char *str, int line, const char *source)
|
---|
| 219 | {
|
---|
| 220 | char *mem;
|
---|
| 221 | size_t len;
|
---|
| 222 |
|
---|
| 223 | DEBUGASSERT(str != NULL);
|
---|
| 224 |
|
---|
| 225 | if(countcheck("strdup", line, source))
|
---|
| 226 | return NULL;
|
---|
| 227 |
|
---|
| 228 | len = strlen(str) + 1;
|
---|
| 229 |
|
---|
| 230 | mem = curl_domalloc(len, 0, NULL); /* NULL prevents logging */
|
---|
| 231 | if(mem)
|
---|
| 232 | memcpy(mem, str, len);
|
---|
| 233 |
|
---|
| 234 | if(source)
|
---|
| 235 | curl_memlog("MEM %s:%d strdup(%p) (%zu) = %p\n",
|
---|
| 236 | source, line, (const void *)str, len, (const void *)mem);
|
---|
| 237 |
|
---|
| 238 | return mem;
|
---|
| 239 | }
|
---|
| 240 |
|
---|
| 241 | #if defined(WIN32) && defined(UNICODE)
|
---|
| 242 | wchar_t *curl_dowcsdup(const wchar_t *str, int line, const char *source)
|
---|
| 243 | {
|
---|
| 244 | wchar_t *mem;
|
---|
| 245 | size_t wsiz, bsiz;
|
---|
| 246 |
|
---|
| 247 | DEBUGASSERT(str != NULL);
|
---|
| 248 |
|
---|
| 249 | if(countcheck("wcsdup", line, source))
|
---|
| 250 | return NULL;
|
---|
| 251 |
|
---|
| 252 | wsiz = wcslen(str) + 1;
|
---|
| 253 | bsiz = wsiz * sizeof(wchar_t);
|
---|
| 254 |
|
---|
| 255 | mem = curl_domalloc(bsiz, 0, NULL); /* NULL prevents logging */
|
---|
| 256 | if(mem)
|
---|
| 257 | memcpy(mem, str, bsiz);
|
---|
| 258 |
|
---|
| 259 | if(source)
|
---|
| 260 | curl_memlog("MEM %s:%d wcsdup(%p) (%zu) = %p\n",
|
---|
| 261 | source, line, (void *)str, bsiz, (void *)mem);
|
---|
| 262 |
|
---|
| 263 | return mem;
|
---|
| 264 | }
|
---|
| 265 | #endif
|
---|
| 266 |
|
---|
| 267 | /* We provide a realloc() that accepts a NULL as pointer, which then
|
---|
| 268 | performs a malloc(). In order to work with ares. */
|
---|
| 269 | void *curl_dorealloc(void *ptr, size_t wantedsize,
|
---|
| 270 | int line, const char *source)
|
---|
| 271 | {
|
---|
| 272 | struct memdebug *mem = NULL;
|
---|
| 273 |
|
---|
| 274 | size_t size = sizeof(struct memdebug) + wantedsize;
|
---|
| 275 |
|
---|
| 276 | DEBUGASSERT(wantedsize != 0);
|
---|
| 277 |
|
---|
| 278 | if(countcheck("realloc", line, source))
|
---|
| 279 | return NULL;
|
---|
| 280 |
|
---|
| 281 | #ifdef __INTEL_COMPILER
|
---|
| 282 | # pragma warning(push)
|
---|
| 283 | # pragma warning(disable:1684)
|
---|
| 284 | /* 1684: conversion from pointer to same-sized integral type */
|
---|
| 285 | #endif
|
---|
| 286 |
|
---|
| 287 | if(ptr)
|
---|
| 288 | mem = (void *)((char *)ptr - offsetof(struct memdebug, mem));
|
---|
| 289 |
|
---|
| 290 | #ifdef __INTEL_COMPILER
|
---|
| 291 | # pragma warning(pop)
|
---|
| 292 | #endif
|
---|
| 293 |
|
---|
| 294 | mem = (Curl_crealloc)(mem, size);
|
---|
| 295 | if(source)
|
---|
| 296 | curl_memlog("MEM %s:%d realloc(%p, %zu) = %p\n",
|
---|
| 297 | source, line, (void *)ptr, wantedsize,
|
---|
| 298 | mem ? (void *)mem->mem : (void *)0);
|
---|
| 299 |
|
---|
| 300 | if(mem) {
|
---|
| 301 | mem->size = wantedsize;
|
---|
| 302 | return mem->mem;
|
---|
| 303 | }
|
---|
| 304 |
|
---|
| 305 | return NULL;
|
---|
| 306 | }
|
---|
| 307 |
|
---|
| 308 | void curl_dofree(void *ptr, int line, const char *source)
|
---|
| 309 | {
|
---|
| 310 | struct memdebug *mem;
|
---|
| 311 |
|
---|
| 312 | if(ptr) {
|
---|
| 313 |
|
---|
| 314 | #ifdef __INTEL_COMPILER
|
---|
| 315 | # pragma warning(push)
|
---|
| 316 | # pragma warning(disable:1684)
|
---|
| 317 | /* 1684: conversion from pointer to same-sized integral type */
|
---|
| 318 | #endif
|
---|
| 319 |
|
---|
| 320 | mem = (void *)((char *)ptr - offsetof(struct memdebug, mem));
|
---|
| 321 |
|
---|
| 322 | #ifdef __INTEL_COMPILER
|
---|
| 323 | # pragma warning(pop)
|
---|
| 324 | #endif
|
---|
| 325 |
|
---|
| 326 | /* destroy */
|
---|
| 327 | mt_free_fill(mem->mem, mem->size);
|
---|
| 328 |
|
---|
| 329 | /* free for real */
|
---|
| 330 | (Curl_cfree)(mem);
|
---|
| 331 | }
|
---|
| 332 |
|
---|
| 333 | if(source)
|
---|
| 334 | curl_memlog("MEM %s:%d free(%p)\n", source, line, (void *)ptr);
|
---|
| 335 | }
|
---|
| 336 |
|
---|
| 337 | curl_socket_t curl_socket(int domain, int type, int protocol,
|
---|
| 338 | int line, const char *source)
|
---|
| 339 | {
|
---|
| 340 | const char *fmt = (sizeof(curl_socket_t) == sizeof(int)) ?
|
---|
| 341 | "FD %s:%d socket() = %d\n" :
|
---|
| 342 | (sizeof(curl_socket_t) == sizeof(long)) ?
|
---|
| 343 | "FD %s:%d socket() = %ld\n" :
|
---|
| 344 | "FD %s:%d socket() = %zd\n";
|
---|
| 345 |
|
---|
| 346 | curl_socket_t sockfd;
|
---|
| 347 |
|
---|
| 348 | if(countcheck("socket", line, source))
|
---|
| 349 | return CURL_SOCKET_BAD;
|
---|
| 350 |
|
---|
| 351 | sockfd = socket(domain, type, protocol);
|
---|
| 352 |
|
---|
| 353 | if(source && (sockfd != CURL_SOCKET_BAD))
|
---|
| 354 | curl_memlog(fmt, source, line, sockfd);
|
---|
| 355 |
|
---|
| 356 | return sockfd;
|
---|
| 357 | }
|
---|
| 358 |
|
---|
| 359 | SEND_TYPE_RETV curl_dosend(SEND_TYPE_ARG1 sockfd,
|
---|
| 360 | SEND_QUAL_ARG2 SEND_TYPE_ARG2 buf,
|
---|
| 361 | SEND_TYPE_ARG3 len, SEND_TYPE_ARG4 flags, int line,
|
---|
| 362 | const char *source)
|
---|
| 363 | {
|
---|
| 364 | SEND_TYPE_RETV rc;
|
---|
| 365 | if(countcheck("send", line, source))
|
---|
| 366 | return -1;
|
---|
| 367 | rc = send(sockfd, buf, len, flags);
|
---|
| 368 | if(source)
|
---|
| 369 | curl_memlog("SEND %s:%d send(%lu) = %ld\n",
|
---|
| 370 | source, line, (unsigned long)len, (long)rc);
|
---|
| 371 | return rc;
|
---|
| 372 | }
|
---|
| 373 |
|
---|
| 374 | RECV_TYPE_RETV curl_dorecv(RECV_TYPE_ARG1 sockfd, RECV_TYPE_ARG2 buf,
|
---|
| 375 | RECV_TYPE_ARG3 len, RECV_TYPE_ARG4 flags, int line,
|
---|
| 376 | const char *source)
|
---|
| 377 | {
|
---|
| 378 | RECV_TYPE_RETV rc;
|
---|
| 379 | if(countcheck("recv", line, source))
|
---|
| 380 | return -1;
|
---|
| 381 | rc = recv(sockfd, buf, len, flags);
|
---|
| 382 | if(source)
|
---|
| 383 | curl_memlog("RECV %s:%d recv(%lu) = %ld\n",
|
---|
| 384 | source, line, (unsigned long)len, (long)rc);
|
---|
| 385 | return rc;
|
---|
| 386 | }
|
---|
| 387 |
|
---|
| 388 | #ifdef HAVE_SOCKETPAIR
|
---|
| 389 | int curl_socketpair(int domain, int type, int protocol,
|
---|
| 390 | curl_socket_t socket_vector[2],
|
---|
| 391 | int line, const char *source)
|
---|
| 392 | {
|
---|
| 393 | const char *fmt = (sizeof(curl_socket_t) == sizeof(int)) ?
|
---|
| 394 | "FD %s:%d socketpair() = %d %d\n" :
|
---|
| 395 | (sizeof(curl_socket_t) == sizeof(long)) ?
|
---|
| 396 | "FD %s:%d socketpair() = %ld %ld\n" :
|
---|
| 397 | "FD %s:%d socketpair() = %zd %zd\n";
|
---|
| 398 |
|
---|
| 399 | int res = socketpair(domain, type, protocol, socket_vector);
|
---|
| 400 |
|
---|
| 401 | if(source && (0 == res))
|
---|
| 402 | curl_memlog(fmt, source, line, socket_vector[0], socket_vector[1]);
|
---|
| 403 |
|
---|
| 404 | return res;
|
---|
| 405 | }
|
---|
| 406 | #endif
|
---|
| 407 |
|
---|
| 408 | curl_socket_t curl_accept(curl_socket_t s, void *saddr, void *saddrlen,
|
---|
| 409 | int line, const char *source)
|
---|
| 410 | {
|
---|
| 411 | const char *fmt = (sizeof(curl_socket_t) == sizeof(int)) ?
|
---|
| 412 | "FD %s:%d accept() = %d\n" :
|
---|
| 413 | (sizeof(curl_socket_t) == sizeof(long)) ?
|
---|
| 414 | "FD %s:%d accept() = %ld\n" :
|
---|
| 415 | "FD %s:%d accept() = %zd\n";
|
---|
| 416 |
|
---|
| 417 | struct sockaddr *addr = (struct sockaddr *)saddr;
|
---|
| 418 | curl_socklen_t *addrlen = (curl_socklen_t *)saddrlen;
|
---|
| 419 |
|
---|
| 420 | curl_socket_t sockfd = accept(s, addr, addrlen);
|
---|
| 421 |
|
---|
| 422 | if(source && (sockfd != CURL_SOCKET_BAD))
|
---|
| 423 | curl_memlog(fmt, source, line, sockfd);
|
---|
| 424 |
|
---|
| 425 | return sockfd;
|
---|
| 426 | }
|
---|
| 427 |
|
---|
| 428 | /* separate function to allow libcurl to mark a "faked" close */
|
---|
| 429 | void curl_mark_sclose(curl_socket_t sockfd, int line, const char *source)
|
---|
| 430 | {
|
---|
| 431 | const char *fmt = (sizeof(curl_socket_t) == sizeof(int)) ?
|
---|
| 432 | "FD %s:%d sclose(%d)\n":
|
---|
| 433 | (sizeof(curl_socket_t) == sizeof(long)) ?
|
---|
| 434 | "FD %s:%d sclose(%ld)\n":
|
---|
| 435 | "FD %s:%d sclose(%zd)\n";
|
---|
| 436 |
|
---|
| 437 | if(source)
|
---|
| 438 | curl_memlog(fmt, source, line, sockfd);
|
---|
| 439 | }
|
---|
| 440 |
|
---|
| 441 | /* this is our own defined way to close sockets on *ALL* platforms */
|
---|
| 442 | int curl_sclose(curl_socket_t sockfd, int line, const char *source)
|
---|
| 443 | {
|
---|
| 444 | int res = sclose(sockfd);
|
---|
| 445 | curl_mark_sclose(sockfd, line, source);
|
---|
| 446 | return res;
|
---|
| 447 | }
|
---|
| 448 |
|
---|
| 449 | FILE *curl_fopen(const char *file, const char *mode,
|
---|
| 450 | int line, const char *source)
|
---|
| 451 | {
|
---|
| 452 | FILE *res = fopen(file, mode);
|
---|
| 453 |
|
---|
| 454 | if(source)
|
---|
| 455 | curl_memlog("FILE %s:%d fopen(\"%s\",\"%s\") = %p\n",
|
---|
| 456 | source, line, file, mode, (void *)res);
|
---|
| 457 |
|
---|
| 458 | return res;
|
---|
| 459 | }
|
---|
| 460 |
|
---|
| 461 | #ifdef HAVE_FDOPEN
|
---|
| 462 | FILE *curl_fdopen(int filedes, const char *mode,
|
---|
| 463 | int line, const char *source)
|
---|
| 464 | {
|
---|
| 465 | FILE *res = fdopen(filedes, mode);
|
---|
| 466 |
|
---|
| 467 | if(source)
|
---|
| 468 | curl_memlog("FILE %s:%d fdopen(\"%d\",\"%s\") = %p\n",
|
---|
| 469 | source, line, filedes, mode, (void *)res);
|
---|
| 470 |
|
---|
| 471 | return res;
|
---|
| 472 | }
|
---|
| 473 | #endif
|
---|
| 474 |
|
---|
| 475 | int curl_fclose(FILE *file, int line, const char *source)
|
---|
| 476 | {
|
---|
| 477 | int res;
|
---|
| 478 |
|
---|
| 479 | DEBUGASSERT(file != NULL);
|
---|
| 480 |
|
---|
| 481 | res = fclose(file);
|
---|
| 482 |
|
---|
| 483 | if(source)
|
---|
| 484 | curl_memlog("FILE %s:%d fclose(%p)\n",
|
---|
| 485 | source, line, (void *)file);
|
---|
| 486 |
|
---|
| 487 | return res;
|
---|
| 488 | }
|
---|
| 489 |
|
---|
| 490 | #define LOGLINE_BUFSIZE 1024
|
---|
| 491 |
|
---|
| 492 | /* this does the writing to the memory tracking log file */
|
---|
| 493 | void curl_memlog(const char *format, ...)
|
---|
| 494 | {
|
---|
| 495 | char *buf;
|
---|
| 496 | int nchars;
|
---|
| 497 | va_list ap;
|
---|
| 498 |
|
---|
| 499 | if(!logfile)
|
---|
| 500 | return;
|
---|
| 501 |
|
---|
| 502 | buf = (Curl_cmalloc)(LOGLINE_BUFSIZE);
|
---|
| 503 | if(!buf)
|
---|
| 504 | return;
|
---|
| 505 |
|
---|
| 506 | va_start(ap, format);
|
---|
| 507 | nchars = vsnprintf(buf, LOGLINE_BUFSIZE, format, ap);
|
---|
| 508 | va_end(ap);
|
---|
| 509 |
|
---|
| 510 | if(nchars > LOGLINE_BUFSIZE - 1)
|
---|
| 511 | nchars = LOGLINE_BUFSIZE - 1;
|
---|
| 512 |
|
---|
| 513 | if(nchars > 0)
|
---|
| 514 | fwrite(buf, 1, (size_t)nchars, logfile);
|
---|
| 515 |
|
---|
| 516 | (Curl_cfree)(buf);
|
---|
| 517 | }
|
---|
| 518 |
|
---|
| 519 | #endif /* CURLDEBUG */
|
---|